From 45a2137d08b84ae94cf8e77b70aef91a251e343f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 10:02:40 -0700 Subject: [PATCH 001/133] linux: fix incorrect gethostname usage, fix build, fix clang warnings --- src/demon/linux/demon_core_linux.h | 2 +- src/os/core/linux/os_core_linux.c | 103 +- src/rdi_from_dwarf/rdi_from_dwarf.c | 1468 +++++++++++++-------------- 3 files changed, 787 insertions(+), 786 deletions(-) diff --git a/src/demon/linux/demon_core_linux.h b/src/demon/linux/demon_core_linux.h index 18347a4f..297fdb3a 100644 --- a/src/demon/linux/demon_core_linux.h +++ b/src/demon/linux/demon_core_linux.h @@ -279,7 +279,7 @@ struct DMN_LNX_State Arena *arena; // rjf: access locking mechanism - OS_Handle access_mutex; + Mutex access_mutex; B32 access_run_state; // rjf: deferred events diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 8a22f460..df98d409 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -800,8 +800,8 @@ os_process_kill(OS_Handle handle) //////////////////////////////// //~ rjf: @os_hooks Threads (Implemented Per-OS) -internal OS_Handle -os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr, void *params) +internal Thread +os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr) { OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Thread); entity->thread.func = func; @@ -814,14 +814,14 @@ os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr, void *params) entity = 0; } } - OS_Handle handle = {(U64)entity}; + Thread handle = {(U64)entity}; return handle; } internal B32 -os_thread_join(OS_Handle handle, U64 endt_us) +os_thread_join(Thread handle, U64 endt_us) { - if(os_handle_match(handle, os_handle_zero())) { return 0; } + if(MemoryIsZeroStruct(&handle)) { return 0; } OS_LNX_Entity *entity = (OS_LNX_Entity *)handle.u64[0]; int join_result = pthread_join(entity->thread.handle, 0); B32 result = (join_result == 0); @@ -830,9 +830,9 @@ os_thread_join(OS_Handle handle, U64 endt_us) } internal void -os_thread_detach(OS_Handle handle) +os_thread_detach(Thread handle) { - if(os_handle_match(handle, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&handle)) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)handle.u64[0]; os_lnx_entity_release(entity); } @@ -842,7 +842,7 @@ os_thread_detach(OS_Handle handle) //- rjf: mutexes -internal OS_Handle +internal Mutex os_mutex_alloc(void) { OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Mutex); @@ -856,38 +856,38 @@ os_mutex_alloc(void) os_lnx_entity_release(entity); entity = 0; } - OS_Handle handle = {(U64)entity}; + Mutex handle = {(U64)entity}; return handle; } internal void -os_mutex_release(OS_Handle mutex) +os_mutex_release(Mutex mutex) { - if(os_handle_match(mutex, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&mutex)) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0]; pthread_mutex_destroy(&entity->mutex_handle); os_lnx_entity_release(entity); } internal void -os_mutex_take(OS_Handle mutex) +os_mutex_take(Mutex mutex) { - if(os_handle_match(mutex, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&mutex)) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0]; pthread_mutex_lock(&entity->mutex_handle); } internal void -os_mutex_drop(OS_Handle mutex) +os_mutex_drop(Mutex mutex) { - if(os_handle_match(mutex, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&mutex)) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0]; pthread_mutex_unlock(&entity->mutex_handle); } //- rjf: reader/writer mutexes -internal OS_Handle +internal RWMutex os_rw_mutex_alloc(void) { OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_RWMutex); @@ -897,23 +897,23 @@ os_rw_mutex_alloc(void) os_lnx_entity_release(entity); entity = 0; } - OS_Handle handle = {(U64)entity}; + RWMutex handle = {(U64)entity}; return handle; } internal void -os_rw_mutex_release(OS_Handle rw_mutex) +os_rw_mutex_release(RWMutex rw_mutex) { - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&rw_mutex)) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; pthread_rwlock_destroy(&entity->rwmutex_handle); os_lnx_entity_release(entity); } internal void -os_rw_mutex_take(OS_Handle rw_mutex, B32 write_mode) +os_rw_mutex_take(RWMutex rw_mutex, B32 write_mode) { - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&rw_mutex)) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; if(write_mode) { @@ -926,16 +926,16 @@ os_rw_mutex_take(OS_Handle rw_mutex, B32 write_mode) } internal void -os_rw_mutex_drop(OS_Handle rw_mutex, B32 write_mode) +os_rw_mutex_drop(RWMutex rw_mutex, B32 write_mode) { - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&rw_mutex)) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; pthread_rwlock_unlock(&entity->rwmutex_handle); } //- rjf: condition variables -internal OS_Handle +internal CondVar os_cond_var_alloc(void) { OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_ConditionVariable); @@ -956,14 +956,14 @@ os_cond_var_alloc(void) os_lnx_entity_release(entity); entity = 0; } - OS_Handle handle = {(U64)entity}; + CondVar handle = {(U64)entity}; return handle; } internal void -os_cond_var_release(OS_Handle cv) +os_cond_var_release(CondVar cv) { - if(os_handle_match(cv, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&cv)) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)cv.u64[0]; pthread_cond_destroy(&entity->cv.cond_handle); pthread_mutex_destroy(&entity->cv.rwlock_mutex_handle); @@ -971,10 +971,10 @@ os_cond_var_release(OS_Handle cv) } internal B32 -os_cond_var_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) +os_cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) { - if(os_handle_match(cv, os_handle_zero())) { return 0; } - if(os_handle_match(mutex, os_handle_zero())) { return 0; } + if(MemoryIsZeroStruct(&cv)) { return 0; } + if(MemoryIsZeroStruct(&mutex)) { return 0; } OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; OS_LNX_Entity *mutex_entity = (OS_LNX_Entity *)mutex.u64[0]; struct timespec endt_timespec; @@ -986,14 +986,14 @@ os_cond_var_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) } internal B32 -os_cond_var_wait_rw(OS_Handle cv, OS_Handle mutex_rw, B32 write_mode, U64 endt_us) +os_cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us) { // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack // this together, but this would probably just be a lot better if we just // implemented the primitives ourselves with e.g. futexes // - if(os_handle_match(cv, os_handle_zero())) { return 0; } - if(os_handle_match(mutex_rw, os_handle_zero())) { return 0; } + if(MemoryIsZeroStruct(&cv)) { return 0; } + if(MemoryIsZeroStruct(&mutex_rw)) { return 0; } OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; OS_LNX_Entity *rw_mutex_entity = (OS_LNX_Entity *)mutex_rw.u64[0]; struct timespec endt_timespec; @@ -1036,27 +1036,27 @@ os_cond_var_wait_rw(OS_Handle cv, OS_Handle mutex_rw, B32 write_mode, U64 endt_u } internal void -os_cond_var_signal(OS_Handle cv) +os_cond_var_signal(CondVar cv) { - if(os_handle_match(cv, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&cv)) { return; } OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; pthread_cond_signal(&cv_entity->cv.cond_handle); } internal void -os_cond_var_broadcast(OS_Handle cv) +os_cond_var_broadcast(CondVar cv) { - if(os_handle_match(cv, os_handle_zero())) { return; } + if(MemoryIsZeroStruct(&cv)) { return; } OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; pthread_cond_broadcast(&cv_entity->cv.cond_handle); } //- rjf: cross-process semaphores -internal OS_Handle +internal Semaphore os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) { - OS_Handle result = {0}; + Semaphore result = {0}; if (name.size > 0) { // TODO: we need to allocate shared memory to store sem_t @@ -1076,26 +1076,26 @@ os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) } internal void -os_semaphore_release(OS_Handle semaphore) +os_semaphore_release(Semaphore semaphore) { int err = munmap((void*)semaphore.u64[0], sizeof(sem_t)); AssertAlways(err == 0); } -internal OS_Handle +internal Semaphore os_semaphore_open(String8 name) { NotImplemented; } internal void -os_semaphore_close(OS_Handle semaphore) +os_semaphore_close(Semaphore semaphore) { NotImplemented; } internal B32 -os_semaphore_take(OS_Handle semaphore, U64 endt_us) +os_semaphore_take(Semaphore semaphore, U64 endt_us) { // TODO(rjf): we need to use `sem_timedwait` here. AssertAlways(endt_us == max_U64); @@ -1116,7 +1116,7 @@ os_semaphore_take(OS_Handle semaphore, U64 endt_us) } internal void -os_semaphore_drop(OS_Handle semaphore) +os_semaphore_drop(Semaphore semaphore) { for(;;) { @@ -1138,17 +1138,17 @@ os_semaphore_drop(OS_Handle semaphore) //- rjf: barriers -internal OS_Handle +internal Barrier os_barrier_alloc(U64 count) { OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Barrier); pthread_barrier_init(&entity->barrier, 0, count); - OS_Handle result = {IntFromPtr(entity)}; + Barrier result = {IntFromPtr(entity)}; return result; } internal void -os_barrier_release(OS_Handle barrier) +os_barrier_release(Barrier barrier) { OS_LNX_Entity *entity = (OS_LNX_Entity*)PtrFromInt(barrier.u64[0]); pthread_barrier_destroy(&entity->barrier); @@ -1156,7 +1156,7 @@ os_barrier_release(OS_Handle barrier) } internal void -os_barrier_wait(OS_Handle barrier) +os_barrier_wait(Barrier barrier) { OS_LNX_Entity *entity = (OS_LNX_Entity*)PtrFromInt(barrier.u64[0]); pthread_barrier_wait(&entity->barrier); @@ -1288,9 +1288,10 @@ main(int argc, char **argv) for(S64 cap = 4096, r = 0; r < 4; cap *= 2, r += 1) { scratch_end(scratch); - buffer = push_array_no_zero(scratch.arena, U8, cap); - size = gethostname((char*)buffer, cap); - if(size < cap) + buffer = push_array(scratch.arena, U8, cap); + int gethostname_result = gethostname((char*)buffer, cap); + size = cstring8_length(buffer); + if(gethostname_result == 0 && size < cap) { got_final_result = 1; break; diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 25645a49..e1e279fa 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -8,7 +8,7 @@ // [ ] Error handling //////////////////////////////// - + static const U64 UNIT_CHUNK_CAP = 256; static const U64 UDT_CHUNK_CAP = 256; static const U64 TYPE_CHUNK_CAP = 256; @@ -210,7 +210,7 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_HighPc); if (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) { U64 lo_pc = dw_address_from_attrib(input, cu, lo_pc_attrib); - + U64 hi_pc = 0; DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); if (hi_pc_class == DW_AttribClass_Address) { @@ -221,7 +221,7 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag } else { AssertAlways(!"unexpected attribute encoding"); } - + if (lo_pc >= image_base && hi_pc >= image_base) { if (lo_pc < hi_pc) { rng1u64_list_push(arena, &ranges, rng_1u64(lo_pc - image_base, hi_pc - image_base)); @@ -231,8 +231,8 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag } else { // invalid low and hi PC are likely are caused by an optimization pass during linking } - } else if (lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null || - lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null) { + } else if ((lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) || + (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null)) { // TODO: error handling } } @@ -364,9 +364,9 @@ d2r_bytecode_from_expression(Arena *arena, }; struct Frame *stack = 0; #define push_of_type(type) do { \ - struct Frame *f = push_array(scratch.arena, struct Frame, 1); \ - f->value_type = d2r_type_group_from_type_kind(type); \ - SLLStackPush(stack, f); \ +struct Frame *f = push_array(scratch.arena, struct Frame, 1); \ +f->value_type = d2r_type_group_from_type_kind(type); \ +SLLStackPush(stack, f); \ } while (0) #define pop_type() stack->value_type; SLLStackPop(stack) #define peek_type() stack->value_type @@ -918,7 +918,7 @@ d2r_bytecode_from_expression(Arena *arena, rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_TLSOff, 0); rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, peek_type()); } break; - + default: InvalidPath; break; } } @@ -941,7 +941,7 @@ d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Inp RDIM_LocationInfo *loc_info = push_array(arena, RDIM_LocationInfo, 1); loc_info->kind = is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; loc_info->bytecode = bytecode; - + loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); } return loc; @@ -1037,7 +1037,7 @@ d2r_var_locset_from_tag(Arena *arena, loc_info->kind = RDI_LocationKind_ValBytecodeStream; loc_info->bytecode = bc; RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); - + // push location cases for EachNode(range_n, RDIM_Rng1U64Node, curr_scope->voff_ranges.first) { rdim_push_location_case(arena, scopes, &locset, loc, range_n->v); @@ -1211,19 +1211,19 @@ d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter) goto exit; } } - + while (iter->stack) { // go to sibling iter->stack->node = iter->stack->node->sibling; if (iter->stack->node) { break; } - + // no more siblings, go up D2R_TagFrame *f = iter->stack; SLLStackPop(iter->stack); SLLStackPush(iter->free_list, f); } - -exit:; + + exit:; // update iterator iter->visit_children = 1; iter->tag_node = iter->stack ? iter->stack->node : 0; @@ -1281,13 +1281,13 @@ d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *inpu // find type type = d2r_type_from_offset(type_table, ref.info_off); - + // was type converted? if (type == 0) { // issue type conversion DW_TagNode *ref_node = dw_tag_node_from_info_off(cu, ref.info_off); d2r_convert_types(arena, type_table, input, cu, cu_lang, arch_addr_size, ref_node); - + // if we do not have a converted type at this point then debug info is malformed type = d2r_type_from_offset(type_table, ref.info_off); Assert(type); @@ -1313,7 +1313,7 @@ d2r_convert_types(Arena *arena, for (D2R_TagIterator *it = d2r_tag_iterator_init(scratch.arena, root); it->tag_node != 0; d2r_tag_iterator_next(scratch.arena, it)) { DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; - + // skip converted tags if (d2r_is_tag_converted(tag_node)) { d2r_tag_iterator_skip_children(it); @@ -1321,376 +1321,376 @@ d2r_convert_types(Arena *arena, } // mark the tag as converted here, because during conversion we may recurse on the same tag d2r_flag_converted_tag(tag_node); - + switch (tag.kind) { - case DW_TagKind_ClassType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_IncompleteClass; - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - Assert(!tag_node->first_child); + case DW_TagKind_ClassType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_IncompleteClass; + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Class; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + type->direct_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + } + } break; + case DW_TagKind_StructureType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteStruct; + + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Struct; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + } + } break; + case DW_TagKind_UnionType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteUnion; + + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Union; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + } + } break; + case DW_TagKind_EnumerationType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteEnum; + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Enum; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + type->direct_type = enum_base_type; + } + } break; + case DW_TagKind_SubroutineType: { + RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + + // collect parameters + RDIM_TypeList param_list = {0}; + for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind == DW_TagKind_FormalParameter) { + RDIM_Type *param_type = d2r_type_from_attrib(type_table, input, cu, n->tag, DW_AttribKind_Type); + rdim_type_list_push(scratch.arena, ¶m_list, param_type); + } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { + rdim_type_list_push(scratch.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); + } else { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } + } + + // init proceudre type + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Function; + type->byte_size = arch_addr_size; + type->direct_type = ret_type; + type->count = param_list.count; + type->param_types = rdim_array_from_type_list(arena, param_list); + d2r_tag_iterator_skip_children(it); - } else { + } break; + case DW_TagKind_Typedef: { RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Class; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - type->direct_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - } - } break; - case DW_TagKind_StructureType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteStruct; - - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Struct; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - } - } break; - case DW_TagKind_UnionType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteUnion; - - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Union; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - } - } break; - case DW_TagKind_EnumerationType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteEnum; - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->direct_type = direct_type; + for (RDIM_Type *n = direct_type; n != 0; n = n->direct_type) { + if (n->byte_size) { + type->byte_size = n->byte_size; + break; + } + } + } break; + case DW_TagKind_BaseType: { + DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); + U64 byte_size = dw_byte_size_from_tag(input, cu, tag); + + // convert base type encoding to RDI version + RDI_TypeKind kind = RDI_TypeKind_NULL; + switch (encoding) { + case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; + case DW_ATE_Address: kind = RDI_TypeKind_Void; break; + case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; + case DW_ATE_ComplexFloat: { + switch (byte_size) { + case 4: kind = RDI_TypeKind_ComplexF32; break; + case 8: kind = RDI_TypeKind_ComplexF64; break; + case 10: kind = RDI_TypeKind_ComplexF80; break; + case 16: kind = RDI_TypeKind_ComplexF128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Float: { + switch (byte_size) { + case 2: kind = RDI_TypeKind_F16; break; + case 4: kind = RDI_TypeKind_F32; break; + case 6: kind = RDI_TypeKind_F48; break; + case 8: kind = RDI_TypeKind_F64; break; + case 16: kind = RDI_TypeKind_F128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Signed: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_S8; break; + case 2: kind = RDI_TypeKind_S16; break; + case 4: kind = RDI_TypeKind_S32; break; + case 8: kind = RDI_TypeKind_S64; break; + case 16: kind = RDI_TypeKind_S128; break; + case 32: kind = RDI_TypeKind_S256; break; + case 64: kind = RDI_TypeKind_S512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_SignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_Char8; break; + case 2: kind = RDI_TypeKind_Char16; break; + case 4: kind = RDI_TypeKind_Char32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Unsigned: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_U8; break; + case 2: kind = RDI_TypeKind_U16; break; + case 4: kind = RDI_TypeKind_U32; break; + case 8: kind = RDI_TypeKind_U64; break; + case 16: kind = RDI_TypeKind_U128; break; + case 32: kind = RDI_TypeKind_U256; break; + case 64: kind = RDI_TypeKind_U512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_UnsignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_UChar8; break; + case 2: kind = RDI_TypeKind_UChar16; break; + case 4: kind = RDI_TypeKind_UChar32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_ImaginaryFloat: { + NotImplemented; + } break; + case DW_ATE_PackedDecimal: { + NotImplemented; + } break; + case DW_ATE_NumericString: { + NotImplemented; + } break; + case DW_ATE_Edited: { + NotImplemented; + } break; + case DW_ATE_SignedFixed: { + NotImplemented; + } break; + case DW_ATE_UnsignedFixed: { + NotImplemented; + } break; + case DW_ATE_DecimalFloat: { + NotImplemented; + } break; + case DW_ATE_Utf: { + NotImplemented; + } break; + case DW_ATE_Ucs: { + NotImplemented; + } break; + case DW_ATE_Ascii: { + NotImplemented; + } break; + default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + } + + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Enum; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - type->direct_type = enum_base_type; - } - } break; - case DW_TagKind_SubroutineType: { - RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - - // collect parameters - RDIM_TypeList param_list = {0}; - for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind == DW_TagKind_FormalParameter) { - RDIM_Type *param_type = d2r_type_from_attrib(type_table, input, cu, n->tag, DW_AttribKind_Type); - rdim_type_list_push(scratch.arena, ¶m_list, param_type); - } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { - rdim_type_list_push(scratch.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); - } else { - // TODO: error handling - AssertAlways(!"unexpected tag"); + type->direct_type = type_table->builtin_types[kind]; + type->byte_size = byte_size; + } break; + case DW_TagKind_PointerType: { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); + + U64 byte_size = arch_addr_size; + if (cu->version == DW_Version_5 || cu->relaxed) { + dw_try_byte_size_from_tag(input, cu, tag, &byte_size); } - } - - // init proceudre type - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Function; - type->byte_size = arch_addr_size; - type->direct_type = ret_type; - type->count = param_list.count; - type->param_types = rdim_array_from_type_list(arena, param_list); - - d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_Typedef: { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->direct_type = direct_type; - for (RDIM_Type *n = direct_type; n != 0; n = n->direct_type) { - if (n->byte_size) { - type->byte_size = n->byte_size; - break; + + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Ptr; + type->byte_size = byte_size; + type->direct_type = direct_type; + } break; + case DW_TagKind_RestrictType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Restrict; + type->direct_type = direct_type; + } break; + case DW_TagKind_VolatileType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Volatile; + type->direct_type = direct_type; + } break; + case DW_TagKind_ConstType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Const; + type->direct_type = direct_type; + } break; + case DW_TagKind_ArrayType: { + // * DWARF vs RDI Array Type Graph * + // + // For example lets take following decl: + // + // int (*foo[2])[3]; + // + // This compiles to in DWARF: + // + // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] + // \ + // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] + // \ + // -> (B1) DW_TAG_BaseType (int) + // + // RDI expects: + // + // foo -> Array[2] -> Pointer -> Array[3] -> int + // + // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and + // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. + // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from + // B to A. + struct SubrangeNode { struct SubrangeNode *next; U64 count; }; + struct SubrangeNode *subrange_stack = 0; + for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind != DW_TagKind_SubrangeType) { + // TODO: error handling + AssertAlways(!"unexpected tag"); + continue; + } + + // resolve lower bound + U64 lower_bound = 0; + if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_LowerBound)) { + lower_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_LowerBound); + } else { + lower_bound = dw_pick_default_lower_bound(cu_lang); + } + + // resolve upper bound + U64 upper_bound = 0; + if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_Count)) { + U64 count = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_Count); + upper_bound = lower_bound + count; + } else if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_UpperBound)) { + upper_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_UpperBound); + // turn upper bound into exclusive range + upper_bound += 1; + } else { + // zero sized array + } + + struct SubrangeNode *s = push_array(scratch.arena, struct SubrangeNode, 1); + s->count = upper_bound - lower_bound; + SLLStackPush(subrange_stack, s); } - } - } break; - case DW_TagKind_BaseType: { - DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); - U64 byte_size = dw_byte_size_from_tag(input, cu, tag); - - // convert base type encoding to RDI version - RDI_TypeKind kind = RDI_TypeKind_NULL; - switch (encoding) { - case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; - case DW_ATE_Address: kind = RDI_TypeKind_Void; break; - case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; - case DW_ATE_ComplexFloat: { - switch (byte_size) { - case 4: kind = RDI_TypeKind_ComplexF32; break; - case 8: kind = RDI_TypeKind_ComplexF64; break; - case 10: kind = RDI_TypeKind_ComplexF80; break; - case 16: kind = RDI_TypeKind_ComplexF128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling + + RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = array_base_type; + U64 size_cursor = array_base_type->byte_size; + for EachNode(s, struct SubrangeNode, subrange_stack) { + size_cursor *= s->count; + + RDIM_Type *t; + if (s->next) { t = d2r_create_type(arena, type_table); } + else { t = d2r_create_type_from_offset(arena, type_table, tag.info_off); } + + t->kind = RDI_TypeKind_Array; + t->direct_type = direct_type; + t->byte_size = size_cursor; + t->count = s->count; + + direct_type = t; } + + d2r_tag_iterator_skip_children(it); } break; - case DW_ATE_Float: { - switch (byte_size) { - case 2: kind = RDI_TypeKind_F16; break; - case 4: kind = RDI_TypeKind_F32; break; - case 6: kind = RDI_TypeKind_F48; break; - case 8: kind = RDI_TypeKind_F64; break; - case 16: kind = RDI_TypeKind_F128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Signed: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_S8; break; - case 2: kind = RDI_TypeKind_S16; break; - case 4: kind = RDI_TypeKind_S32; break; - case 8: kind = RDI_TypeKind_S64; break; - case 16: kind = RDI_TypeKind_S128; break; - case 32: kind = RDI_TypeKind_S256; break; - case 64: kind = RDI_TypeKind_S512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_SignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_Char8; break; - case 2: kind = RDI_TypeKind_Char16; break; - case 4: kind = RDI_TypeKind_Char32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Unsigned: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_U8; break; - case 2: kind = RDI_TypeKind_U16; break; - case 4: kind = RDI_TypeKind_U32; break; - case 8: kind = RDI_TypeKind_U64; break; - case 16: kind = RDI_TypeKind_U128; break; - case 32: kind = RDI_TypeKind_U256; break; - case 64: kind = RDI_TypeKind_U512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_UnsignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_UChar8; break; - case 2: kind = RDI_TypeKind_UChar16; break; - case 4: kind = RDI_TypeKind_UChar32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_ImaginaryFloat: { - NotImplemented; - } break; - case DW_ATE_PackedDecimal: { - NotImplemented; - } break; - case DW_ATE_NumericString: { - NotImplemented; - } break; - case DW_ATE_Edited: { - NotImplemented; - } break; - case DW_ATE_SignedFixed: { - NotImplemented; - } break; - case DW_ATE_UnsignedFixed: { - NotImplemented; - } break; - case DW_ATE_DecimalFloat: { - NotImplemented; - } break; - case DW_ATE_Utf: { - NotImplemented; - } break; - case DW_ATE_Ucs: { - NotImplemented; - } break; - case DW_ATE_Ascii: { - NotImplemented; - } break; - default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling - } - - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->direct_type = type_table->builtin_types[kind]; - type->byte_size = byte_size; - } break; - case DW_TagKind_PointerType: { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); - - U64 byte_size = arch_addr_size; - if (cu->version == DW_Version_5 || cu->relaxed) { - dw_try_byte_size_from_tag(input, cu, tag, &byte_size); - } - - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Ptr; - type->byte_size = byte_size; - type->direct_type = direct_type; - } break; - case DW_TagKind_RestrictType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Restrict; - type->direct_type = direct_type; - } break; - case DW_TagKind_VolatileType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Volatile; - type->direct_type = direct_type; - } break; - case DW_TagKind_ConstType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Const; - type->direct_type = direct_type; - } break; - case DW_TagKind_ArrayType: { - // * DWARF vs RDI Array Type Graph * - // - // For example lets take following decl: - // - // int (*foo[2])[3]; - // - // This compiles to in DWARF: - // - // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] - // \ - // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] - // \ - // -> (B1) DW_TAG_BaseType (int) - // - // RDI expects: - // - // foo -> Array[2] -> Pointer -> Array[3] -> int - // - // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and - // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. - // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from - // B to A. - struct SubrangeNode { struct SubrangeNode *next; U64 count; }; - struct SubrangeNode *subrange_stack = 0; - for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind != DW_TagKind_SubrangeType) { - // TODO: error handling - AssertAlways(!"unexpected tag"); - continue; - } - - // resolve lower bound - U64 lower_bound = 0; - if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_LowerBound)) { - lower_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_LowerBound); - } else { - lower_bound = dw_pick_default_lower_bound(cu_lang); - } - - // resolve upper bound - U64 upper_bound = 0; - if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_Count)) { - U64 count = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_Count); - upper_bound = lower_bound + count; - } else if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_UpperBound)) { - upper_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_UpperBound); - // turn upper bound into exclusive range - upper_bound += 1; - } else { - // zero sized array - } - - struct SubrangeNode *s = push_array(scratch.arena, struct SubrangeNode, 1); - s->count = upper_bound - lower_bound; - SLLStackPush(subrange_stack, s); - } - - RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *direct_type = array_base_type; - U64 size_cursor = array_base_type->byte_size; - for EachNode(s, struct SubrangeNode, subrange_stack) { - size_cursor *= s->count; - - RDIM_Type *t; - if (s->next) { t = d2r_create_type(arena, type_table); } - else { t = d2r_create_type_from_offset(arena, type_table, tag.info_off); } - - t->kind = RDI_TypeKind_Array; - t->direct_type = direct_type; - t->byte_size = size_cursor; - t->count = s->count; - - direct_type = t; - } - - d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_SubrangeType: { - // TODO: error handling - AssertAlways(!"unexpected tag"); - } break; - case DW_TagKind_Inheritance: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind != DW_TagKind_StructureType && parent_tag.kind != DW_TagKind_ClassType) { + case DW_TagKind_SubrangeType: { // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - - RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); - member->kind = RDI_MemberKind_Base; - member->type = type; - member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); - } break; + AssertAlways(!"unexpected tag"); + } break; + case DW_TagKind_Inheritance: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind != DW_TagKind_StructureType && parent_tag.kind != DW_TagKind_ClassType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = type; + member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); + } break; } } scratch_end(scratch); @@ -1710,85 +1710,85 @@ d2r_convert_udts(Arena *arena, DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; switch (tag.kind) { - case DW_TagKind_ClassType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_StructureType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_UnionType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_EnumerationType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_Member: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - B32 is_parent_udt = parent_tag.kind == DW_TagKind_StructureType || - parent_tag.kind == DW_TagKind_ClassType || - parent_tag.kind == DW_TagKind_UnionType; - if (is_parent_udt) { - DW_Attrib *data_member_location = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_DataMemberLocation); - DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); - if (data_member_location_class == DW_AttribClass_LocList) { - AssertAlways(!"UDT member with multiple locations are not supported"); + case DW_TagKind_ClassType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; } - - RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTMember *udt_member = rdim_udt_push_member(arena, &udts, parent_type->udt); - udt_member->kind = RDI_MemberKind_DataField; - udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - udt_member->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - udt_member->off = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation); - } else { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - } break; - case DW_TagKind_Enumerator: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_EnumerationType) { - RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &udts, parent_type->udt); - udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - udt_member->val = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ConstValue); - } else { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - } break; + } break; + case DW_TagKind_StructureType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_UnionType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_EnumerationType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_Member: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + B32 is_parent_udt = parent_tag.kind == DW_TagKind_StructureType || + parent_tag.kind == DW_TagKind_ClassType || + parent_tag.kind == DW_TagKind_UnionType; + if (is_parent_udt) { + DW_Attrib *data_member_location = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_DataMemberLocation); + DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); + if (data_member_location_class == DW_AttribClass_LocList) { + AssertAlways(!"UDT member with multiple locations are not supported"); + } + + RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTMember *udt_member = rdim_udt_push_member(arena, &udts, parent_type->udt); + udt_member->kind = RDI_MemberKind_DataField; + udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + udt_member->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + udt_member->off = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation); + } else { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + } break; + case DW_TagKind_Enumerator: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_EnumerationType) { + RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &udts, parent_type->udt); + udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + udt_member->val = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ConstValue); + } else { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + } break; } } scratch_end(scratch); @@ -1811,37 +1811,110 @@ d2r_convert_symbols(Arena *arena, DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; switch (tag.kind) { - case DW_TagKind_Null: { InvalidPath; } break; - case DW_TagKind_ClassType: - case DW_TagKind_StructureType: - case DW_TagKind_UnionType: { - // visit children to collect methods and variables - } break; - case DW_TagKind_EnumerationType: - case DW_TagKind_SubroutineType: - case DW_TagKind_Typedef: - case DW_TagKind_BaseType: - case DW_TagKind_PointerType: - case DW_TagKind_RestrictType: - case DW_TagKind_VolatileType: - case DW_TagKind_ConstType: - case DW_TagKind_ArrayType: - case DW_TagKind_SubrangeType: - case DW_TagKind_Inheritance: - case DW_TagKind_Enumerator: - case DW_TagKind_Member: { - d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_SubProgram: { - DW_InlKind inl = dw_u64_from_attrib(input, cu, tag, DW_AttribKind_Inline); - switch (inl) { - case DW_Inl_NotInlined: { + case DW_TagKind_Null: { InvalidPath; } break; + case DW_TagKind_ClassType: + case DW_TagKind_StructureType: + case DW_TagKind_UnionType: { + // visit children to collect methods and variables + } break; + case DW_TagKind_EnumerationType: + case DW_TagKind_SubroutineType: + case DW_TagKind_Typedef: + case DW_TagKind_BaseType: + case DW_TagKind_PointerType: + case DW_TagKind_RestrictType: + case DW_TagKind_VolatileType: + case DW_TagKind_ConstType: + case DW_TagKind_ArrayType: + case DW_TagKind_SubrangeType: + case DW_TagKind_Inheritance: + case DW_TagKind_Enumerator: + case DW_TagKind_Member: { + d2r_tag_iterator_skip_children(it); + } break; + case DW_TagKind_SubProgram: { + DW_InlKind inl = dw_u64_from_attrib(input, cu, tag, DW_AttribKind_Inline); + switch (inl) { + case DW_Inl_NotInlined: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *container_type = 0; + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { + container_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); + } + + // get frame base expression + String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_FrameBase); + + // get proc container symbol + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP); + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + root_scope->symbol = proc; + + // fill out proc + proc->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); + proc->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + proc->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); + proc->type = proc_type; + proc->container_symbol = 0; + proc->container_type = container_type; + proc->root_scope = root_scope; + proc->location_cases = d2r_locset_from_attrib(arena, &scopes, root_scope, &locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); + + // sub program with user-defined parent tag is a method + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_ClassType || parent_tag.kind == DW_TagKind_StructureType) { + RDI_MemberKind member_kind = RDI_MemberKind_NULL; + DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Virtuality); + switch (virtuality) { + case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; + case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; + case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal + //default: InvalidPath; break; + } + + RDIM_Type *type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = member_kind; + member->type = type; + member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + } else if (parent_tag.kind != DW_TagKind_CompileUnit) { + //AssertAlways(!"unexpected tag"); + } + + it->stack->scope = root_scope; + } break; + case DW_Inl_DeclaredNotInlined: + case DW_Inl_DeclaredInlined: + case DW_Inl_Inlined: { + d2r_tag_iterator_skip_children(it); + } break; + default: InvalidPath; break; + } + } break; + case DW_TagKind_InlinedSubroutine: { U64 param_count = 0; RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); - + // get return type RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - + // fill out proc type RDIM_Type *proc_type = d2r_create_type(arena, type_table); proc_type->kind = RDI_TypeKind_Function; @@ -1849,197 +1922,124 @@ d2r_convert_symbols(Arena *arena, proc_type->direct_type = ret_type; proc_type->count = param_count; proc_type->param_types = params; - + // get container type - RDIM_Type *container_type = 0; + RDIM_Type *owner = 0; if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { - container_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); + owner = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); } - - // get frame base expression - String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_FrameBase); - - // get proc container symbol - RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP); - + + // fill out inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); + inline_site->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + inline_site->type = proc_type; + inline_site->owner = owner; + inline_site->line_table = 0; + // make scope Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - root_scope->symbol = proc; - - // fill out proc - proc->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); - proc->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - proc->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); - proc->type = proc_type; - proc->container_symbol = 0; - proc->container_type = container_type; - proc->root_scope = root_scope; - proc->location_cases = d2r_locset_from_attrib(arena, &scopes, root_scope, &locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); - - // sub program with user-defined parent tag is a method + root_scope->inline_site = inline_site; + } break; + case DW_TagKind_Variable: { + String8 name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + RDIM_Type *type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_ClassType || parent_tag.kind == DW_TagKind_StructureType) { - RDI_MemberKind member_kind = RDI_MemberKind_NULL; - DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Virtuality); - switch (virtuality) { - case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; - case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; - case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal - //default: InvalidPath; break; - } - - RDIM_Type *type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); - member->kind = member_kind; - member->type = type; - member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - } else if (parent_tag.kind != DW_TagKind_CompileUnit) { - //AssertAlways(!"unexpected tag"); - } - - it->stack->scope = root_scope; - } break; - case DW_Inl_DeclaredNotInlined: - case DW_Inl_DeclaredInlined: - case DW_Inl_Inlined: { - d2r_tag_iterator_skip_children(it); - } break; - default: InvalidPath; break; - } - } break; - case DW_TagKind_InlinedSubroutine: { - U64 param_count = 0; - RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); - - // get return type - RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - - // fill out proc type - RDIM_Type *proc_type = d2r_create_type(arena, type_table); - proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; - proc_type->direct_type = ret_type; - proc_type->count = param_count; - proc_type->param_types = params; - - // get container type - RDIM_Type *owner = 0; - if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { - owner = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); - } - - // fill out inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); - inline_site->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - inline_site->type = proc_type; - inline_site->owner = owner; - inline_site->line_table = 0; - - // make scope - Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - root_scope->inline_site = inline_site; - } break; - case DW_TagKind_Variable: { - String8 name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - RDIM_Type *type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || - parent_tag.kind == DW_TagKind_InlinedSubroutine || - parent_tag.kind == DW_TagKind_LexicalBlock) { - RDIM_Scope *scope = it->stack->next->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &scopes, scope); - local->kind = RDI_LocalKind_Variable; - local->name = name; - local->type = type; - local->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); - } else { - - // NOTE: due to a bug in clang in stb_sprint.h local variables - // are declared in global scope without a name - if (name.size == 0) { break; } - - B32 is_thread_var = 0; - U64 voff = 0; - { - DW_Attrib *loc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_Location); - DW_AttribClass loc_class = dw_value_class_from_attrib(cu, loc_attrib); - if (loc_class == DW_AttribClass_ExprLoc) { - String8 expr = dw_exprloc_from_attrib(input, cu, loc_attrib); - B32 is_addr = 0; - RDIM_EvalBytecode bc = d2r_bytecode_from_expression(arena, input, image_base, arch_addr_size, arch, cu->addr_lu, expr, cu, &is_addr); - - for EachNode(n, RDIM_EvalBytecodeOp, bc.first_op) { - if (n->op == RDI_EvalOp_TLSOff) { - is_thread_var = 1; - break; + if (parent_tag.kind == DW_TagKind_SubProgram || + parent_tag.kind == DW_TagKind_InlinedSubroutine || + parent_tag.kind == DW_TagKind_LexicalBlock) { + RDIM_Scope *scope = it->stack->next->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &scopes, scope); + local->kind = RDI_LocalKind_Variable; + local->name = name; + local->type = type; + local->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + } else { + + // NOTE: due to a bug in clang in stb_sprint.h local variables + // are declared in global scope without a name + if (name.size == 0) { break; } + + B32 is_thread_var = 0; + U64 voff = 0; + { + DW_Attrib *loc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_Location); + DW_AttribClass loc_class = dw_value_class_from_attrib(cu, loc_attrib); + if (loc_class == DW_AttribClass_ExprLoc) { + String8 expr = dw_exprloc_from_attrib(input, cu, loc_attrib); + B32 is_addr = 0; + RDIM_EvalBytecode bc = d2r_bytecode_from_expression(arena, input, image_base, arch_addr_size, arch, cu->addr_lu, expr, cu, &is_addr); + + for EachNode(n, RDIM_EvalBytecodeOp, bc.first_op) { + if (n->op == RDI_EvalOp_TLSOff) { + is_thread_var = 1; + break; + } } - } - - if (is_addr) { - if (rdim_is_eval_bytecode_static(bc)) { - voff = rdim_do_static_bytecode_eval(bc, image_base); + + if (is_addr) { + if (rdim_is_eval_bytecode_static(bc)) { + voff = rdim_do_static_bytecode_eval(bc, image_base); + } } } } + + RDIM_SymbolChunkList *var_chunks; U64 var_chunks_cap; + if (is_thread_var) { var_chunks = &tvars; var_chunks_cap = TVAR_CHUNK_CAP; } + else { var_chunks = &gvars; var_chunks_cap = GVAR_CHUNK_CAP; } + + RDIM_Symbol *var = rdim_symbol_chunk_list_push(arena, var_chunks, var_chunks_cap); + var->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); + var->name = name; + var->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); + var->type = type; + var->offset = voff; + var->container_symbol = 0; + var->container_type = 0; // TODO: NotImplemented; } - - RDIM_SymbolChunkList *var_chunks; U64 var_chunks_cap; - if (is_thread_var) { var_chunks = &tvars; var_chunks_cap = TVAR_CHUNK_CAP; } - else { var_chunks = &gvars; var_chunks_cap = GVAR_CHUNK_CAP; } - - RDIM_Symbol *var = rdim_symbol_chunk_list_push(arena, var_chunks, var_chunks_cap); - var->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); - var->name = name; - var->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); - var->type = type; - var->offset = voff; - var->container_symbol = 0; - var->container_type = 0; // TODO: NotImplemented; - } - } break; - case DW_TagKind_FormalParameter: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || parent_tag.kind == DW_TagKind_InlinedSubroutine) { - RDIM_Scope *scope = it->stack->next->scope; - RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); - param->kind = RDI_LocalKind_Parameter; - param->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - param->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - param->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); - } else { - // TODO: error handling - AssertAlways(!"this is a local variable"); - } - } break; - case DW_TagKind_LexicalBlock: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || - parent_tag.kind == DW_TagKind_InlinedSubroutine || - parent_tag.kind == DW_TagKind_LexicalBlock) { - Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - } - } break; - case DW_TagKind_CallSite: { - // TODO - } break; - case DW_TagKind_CallSiteParameter: { - // TODO - } break; - case DW_TagKind_Label: - case DW_TagKind_CompileUnit: - case DW_TagKind_UnspecifiedParameters: - case DW_TagKind_Namespace: - case DW_TagKind_ImportedDeclaration: - case DW_TagKind_PtrToMemberType: - case DW_TagKind_TemplateTypeParameter: - case DW_TagKind_ReferenceType: { - // TODO: - } break; - default: NotImplemented; break; + } break; + case DW_TagKind_FormalParameter: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || parent_tag.kind == DW_TagKind_InlinedSubroutine) { + RDIM_Scope *scope = it->stack->next->scope; + RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); + param->kind = RDI_LocalKind_Parameter; + param->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + param->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + param->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + } else { + // TODO: error handling + AssertAlways(!"this is a local variable"); + } + } break; + case DW_TagKind_LexicalBlock: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || + parent_tag.kind == DW_TagKind_InlinedSubroutine || + parent_tag.kind == DW_TagKind_LexicalBlock) { + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + } + } break; + case DW_TagKind_CallSite: { + // TODO + } break; + case DW_TagKind_CallSiteParameter: { + // TODO + } break; + case DW_TagKind_Label: + case DW_TagKind_CompileUnit: + case DW_TagKind_UnspecifiedParameters: + case DW_TagKind_Namespace: + case DW_TagKind_ImportedDeclaration: + case DW_TagKind_PtrToMemberType: + case DW_TagKind_TemplateTypeParameter: + case DW_TagKind_ReferenceType: { + // TODO: + } break; + default: NotImplemented; break; } } scratch_end(scratch); @@ -2052,68 +2052,68 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) if (lane_idx() == 0) { //////////////////////////////// - + ProfBegin("compute exe hash"); U64 exe_hash = rdi_hash(params->exe_data.str, params->exe_data.size); ProfEnd(); - + //////////////////////////////// - + Arch arch = Arch_Null; U64 image_base = 0; DW_Input input = {0}; - + switch(params->exe_kind) { - default:{}break; - case ExecutableImageKind_CoffPe: { - PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); - String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); - COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(raw_sections, 0, sizeof(COFF_SectionHeader) * pe.section_count); - String8 string_table = str8_substr(params->exe_data, pe.string_table_range); - arch = pe.arch; - image_base = pe.image_base; - binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); - input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); - } break; - case ExecutableImageKind_Elf32: - case ExecutableImageKind_Elf64: { - ELF_Bin bin = elf_bin_from_data(scratch.arena, params->dbg_data); - arch = arch_from_elf_machine(bin.hdr.e_machine); - image_base = elf_base_addr_from_bin(&bin); - binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); - input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); - } break; + default:{}break; + case ExecutableImageKind_CoffPe: { + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); + String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); + COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(raw_sections, 0, sizeof(COFF_SectionHeader) * pe.section_count); + String8 string_table = str8_substr(params->exe_data, pe.string_table_range); + arch = pe.arch; + image_base = pe.image_base; + binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); + input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); + } break; + case ExecutableImageKind_Elf32: + case ExecutableImageKind_Elf64: { + ELF_Bin bin = elf_bin_from_data(scratch.arena, params->dbg_data); + arch = arch_from_elf_machine(bin.hdr.e_machine); + image_base = elf_base_addr_from_bin(&bin); + binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); + input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); + } break; } - + //////////////////////////////// - + top_level_info = rdim_make_top_level_info(params->exe_name, arch, exe_hash, binary_sections); - + //////////////////////////////// - + U64 arch_addr_size = rdi_addr_size_from_arch(top_level_info.arch); - + //////////////////////////////// - + RDIM_Scope *global_scope = rdim_scope_chunk_list_push(arena, &scopes, SCOPE_CHUNK_CAP); - + //////////////////////////////// - + ProfBegin("Parse Unit Contrib Map"); D2R_CompUnitContribMap cu_contrib_map = {0}; if (input.sec[DW_Section_ARanges].data.size) { cu_contrib_map = d2r_cu_contrib_map_from_aranges(arena, &input, image_base); } ProfEnd(); - + ProfBegin("Parse Comop Unit Ranges"); DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); Rng1U64List cu_range_list = dw_unit_ranges_from_data(scratch.arena, input.sec[DW_Section_Info].data); Rng1U64Array cu_ranges = rng1u64_array_from_list(scratch.arena, &cu_range_list); ProfEnd(); - + //////////////////////////////// - + ProfBegin("Parse Compile Unit Headers"); // TODO(rjf): parse should always be relaxed. any verification checks we do // should just be logged via log_info(...), and then the caller of this @@ -2124,9 +2124,9 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); } ProfEnd(); - + //////////////////////////////// - + ProfBegin("Parse Line Tables"); DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); for EachIndex(cu_idx, cu_ranges.count) { @@ -2137,15 +2137,15 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) cu_line_tables[cu_idx] = dw_parsed_line_table_from_data(scratch.arena, cu_stmt_list, &input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu); } ProfEnd(); - + //////////////////////////////// - + ProfBegin("Convert Line Tables"); HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); for EachIndex(cu_idx, cu_ranges.count) { cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); - + DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; @@ -2164,78 +2164,78 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } src_file_map[file_idx] = src_file; } - + for EachNode(line_seq, DW_LineSeqNode, line_table->first_seq) { if (line_seq->count == 0) { continue; } - + U64 *voffs = push_array(arena, U64, line_seq->count); U32 *line_nums = push_array(arena, U32, line_seq->count); U16 *col_nums = 0; U64 line_idx = 0; - + DW_LineNode *file_line_n = line_seq->first; U64 file_line_count = 0; - + for EachNode(line_n, DW_LineNode, file_line_n) { if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { U64 file_index = file_line_n->v.file_index; U64 *file_voffs = &voffs[line_idx]; U32 *file_line_nums = &line_nums[line_idx]; U16 *file_col_nums = 0; - + U64 lines_written = 0; U64 prev_ln = max_U64; DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; for (; file_line_n != sentinel; file_line_n = file_line_n->next) { if (file_line_n->v.line != prev_ln) { if (file_line_n->v.address == 0) { continue; } - + voffs[line_idx] = file_line_n->v.address - image_base; line_nums[line_idx] = file_line_n->v.line; - + ++lines_written; ++line_idx; - + prev_ln = file_line_n->v.line; } } - + RDIM_SrcFile *src_file = src_file_map[file_index]; RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, lines_written); rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); - + file_line_count = 1; } else { file_line_count += 1; } } - + // handle last line if (file_line_n) { U64 file_index = file_line_n->v.file_index; U64 *file_voffs = &voffs[line_idx]; U32 *file_line_nums = &line_nums[line_idx]; U16 *file_col_nums = 0; - + for (; file_line_n != 0; file_line_n = file_line_n->next, line_idx += 1) { // TODO: error handling AssertAlways(file_line_n->v.address >= image_base); voffs[line_idx] = file_line_n->v.address - image_base; line_nums[line_idx] = file_line_n->v.line; } - + RDIM_SrcFile *src_file = src_file_map[file_index]; RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, file_line_count); rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); } - + //Assert(line_idx == line_seq->count); } } ProfEnd(); - + //////////////////////////////// - + RDIM_Type *builtin_types[RDI_TypeKind_Count] = {0}; for (RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; type_kind <= RDI_TypeKind_LastBuiltIn; type_kind += 1) { RDIM_Type *type = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); @@ -2246,53 +2246,53 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } builtin_types[RDI_TypeKind_Void]->byte_size = arch_addr_size; builtin_types[RDI_TypeKind_Handle]->byte_size = arch_addr_size; - + builtin_types[RDI_TypeKind_Variadic] = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); builtin_types[RDI_TypeKind_Variadic]->kind = RDI_TypeKind_Variadic; - + //////////////////////////////// - + ProfBegin("Convert Units"); for EachIndex(cu_idx, cu_ranges.count) { Temp comp_temp = temp_begin(scratch.arena); - + DW_CompUnit *cu = &cu_arr[cu_idx]; - + // parse and build tag tree DW_TagTree tag_tree = dw_tag_tree_from_cu(comp_temp.arena, &input, cu); - + // skip DWO { if (cu->dwo_id) { goto next_cu; } - + String8 dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_DwoName); if (dwo_name.size) { goto next_cu; } - + String8 gnu_dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_GNU_DwoName); if (gnu_dwo_name.size) { goto next_cu; } } - + // build (info offset -> tag) hash table to resolve tags with abstract origin cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); - + // extract compile unit info String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); - + // init type table D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); type_table->ht = hash_table_init(comp_temp.arena, 0x4000); type_table->types = &types; type_table->type_chunk_cap = TYPE_CHUNK_CAP; type_table->builtin_types = builtin_types; - + // convert debug info d2r_convert_types(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); d2r_convert_udts(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); d2r_convert_symbols(arena, type_table, global_scope, &input, cu, cu_lang, arch_addr_size, image_base, arch, tag_tree.root); - + RDIM_Rng1U64ChunkList cu_voff_ranges = {0}; if (cu_idx < cu_contrib_map.count) { cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); @@ -2300,7 +2300,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // TODO: synthesize cu ranges from scopes NotImplemented; } - + // convert compile unit { RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); @@ -2314,15 +2314,15 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) unit->line_table = cu_line_tables_rdi[cu_idx]; unit->voff_ranges = cu_voff_ranges; } - + next_cu:; temp_end(comp_temp); } ProfEnd(); } - + lane_sync(); - + RDIM_BakeParams bake_params = {0}; bake_params.top_level_info = top_level_info; bake_params.binary_sections = binary_sections; @@ -2337,7 +2337,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) bake_params.procedures = procs; bake_params.scopes = scopes; bake_params.inline_sites = inline_sites; - + scratch_end(scratch); return bake_params; } From bf27344a9b7776a47ac427a5014f189ee5bb85bd Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 11:01:04 -0700 Subject: [PATCH 002/133] replace extra gen parameters in artifact creation hook; replace with explicit cancellation signal, passed by caller --- src/artifact_cache/artifact_cache.c | 6 +- src/artifact_cache/artifact_cache.h | 10 +- src/ctrl/ctrl_core.c | 6 +- src/ctrl/ctrl_core.h | 6 +- src/dbg_info/dbg_info2.c | 157 +++++++++++++++++++++++++--- src/dbg_info/dbg_info2.h | 2 +- src/disasm/disasm.c | 2 +- src/disasm/disasm.h | 2 +- src/file_stream/file_stream.c | 2 +- src/file_stream/file_stream.h | 2 +- src/raddbg/raddbg_views.c | 4 +- src/text/text.c | 2 +- src/text/text.h | 2 +- 13 files changed, 170 insertions(+), 33 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 514463b5..2993b3be 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -161,8 +161,8 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 } n->v.key = str8_copy(req_batch->arena, key); n->v.gen = params->gen; - n->v.last_requested_gen = &node->last_requested_gen; n->v.create = params->create; + n->v.cancel_signal = params->cancel_signal; } cond_var_broadcast(async_tick_start_cond_var); ins_atomic_u32_eval_assign(&async_loop_again, 1); @@ -356,7 +356,7 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - AC_Artifact val = r->create(r->key, r->gen, r->last_requested_gen, &retry); + AC_Artifact val = r->create(r->key, r->cancel_signal, &retry); // rjf: retry? -> resubmit request if(retry && lane_idx() == 0) @@ -458,7 +458,7 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - AC_Artifact val = r->create(r->key, r->gen, r->last_requested_gen, &retry); + AC_Artifact val = r->create(r->key, r->cancel_signal, &retry); // rjf: retry? -> resubmit request if(retry) diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 6d14a48e..eab90c4e 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -16,7 +16,7 @@ struct AC_Artifact //////////////////////////////// //~ rjf: Artifact Computation Function Types -typedef AC_Artifact AC_CreateFunctionType(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out); typedef void AC_DestroyFunctionType(AC_Artifact artifact); typedef U32 AC_Flags; @@ -37,6 +37,7 @@ struct AC_ArtifactParams U64 gen; U64 evict_threshold_us; B32 *stale_out; + B32 *cancel_signal; AC_Flags flags; }; @@ -48,7 +49,7 @@ struct AC_Request { String8 key; U64 gen; - U64 *last_requested_gen; + B32 *cancel_signal; AC_CreateFunctionType *create; }; @@ -138,6 +139,11 @@ global AC_Shared *ac_shared = 0; internal void ac_init(void); +//////////////////////////////// +//~ rjf: Helpers + +internal B32 ac_cancelled(void); + //////////////////////////////// //~ rjf: Cache Lookups diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 8a0b1b2d..be446cdd 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6134,7 +6134,7 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //~ rjf: Process Memory Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { AC_Artifact artifact = {0}; { @@ -6503,7 +6503,7 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) //~ rjf: Call Stack Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { AC_Artifact artifact = {0}; { @@ -6699,7 +6699,7 @@ ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_ //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +ctrl_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { Temp scratch = scratch_begin(0, 0); Access *access = access_open(); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 56762142..218dc1af 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1002,7 +1002,7 @@ internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); @@ -1017,14 +1017,14 @@ internal B32 ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src); //////////////////////////////// //~ rjf: Call Stack Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void ctrl_call_stack_artifact_destroy(AC_Artifact artifact); internal CTRL_CallStack ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); //////////////////////////////// //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact); internal CTRL_CallStackTree ctrl_call_stack_tree(Access *access, U64 endt_us); diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 720ddce0..1e118c82 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -861,7 +861,7 @@ di2_conversion_completion_signal_receiver_thread_entry_point(void *p) //~ rjf: Search Artifact Cache Hooks / Lookups internal AC_Artifact -di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +di2_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); Access *access = access_open(); @@ -1065,9 +1065,144 @@ di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_ } lane_sync(); - //- rjf: flatten into array + //- rjf: produce sort records + typedef struct SortRecord SortRecord; + struct SortRecord + { + U64 key; + DI2_SearchItem *item; + }; + U64 sort_records_count = all_items->total_count; + SortRecord *sort_records = 0; + SortRecord *sort_records__swap = 0; + ProfScope("produce sort records") + { + if(lane_idx() == 0) + { + sort_records = push_array(scratch.arena, SortRecord, sort_records_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + sort_records__swap = push_array(scratch.arena, SortRecord, sort_records_count); + } + lane_sync_u64(&sort_records, 0); + lane_sync_u64(&sort_records__swap, lane_from_task_idx(1)); + for EachNode(n, DI2_SearchItemChunk, all_items->first) + { + Rng1U64 range = lane_range(n->count); + U64 dst_idx = n->base_idx + range.min; + for EachInRange(n_idx, range) + { + DI2_SearchItem *item = &n->v[n_idx]; + sort_records[dst_idx].item = item; + sort_records[dst_idx].key = (((item->missed_size & 0xffffffffull) << 32) | (u64_hash_from_seed_str8(item->idx, str8_struct(&key)) & 0xffffffffull)); + dst_idx += 1; + } + } + } + lane_sync(); + + //- rjf: sort records + ProfScope("sort records") + { + //- rjf: set up common data + U64 bits_per_digit = 8; + U64 digits_count = 64 / bits_per_digit; + U64 num_possible_values_per_digit = 1 << bits_per_digit; + U32 **lanes_digit_counts = 0; + U32 **lanes_digit_offsets = 0; + if(lane_idx() == 0) + { + lanes_digit_counts = push_array(scratch.arena, U32 *, lane_count()); + lanes_digit_offsets = push_array(scratch.arena, U32 *, lane_count()); + } + lane_sync_u64(&lanes_digit_counts, 0); + lane_sync_u64(&lanes_digit_offsets, 0); + + //- rjf: set up this lane + lanes_digit_counts[lane_idx()] = push_array(scratch.arena, U32, num_possible_values_per_digit); + lanes_digit_offsets[lane_idx()] = push_array(scratch.arena, U32, num_possible_values_per_digit); + SortRecord *src = sort_records; + SortRecord *dst = sort_records__swap; + U64 count = sort_records_count; + + //- rjf: do all per-digit sorts + for EachIndex(digit_idx, digits_count) + { + // rjf: count digit value occurrences per-lane + { + U32 *digit_counts = lanes_digit_counts[lane_idx()]; + MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) + { + SortRecord *r = &src[idx]; + U16 digit_value = (U16)(U8)(r->key >> (digit_idx*bits_per_digit)); + digit_counts[digit_value] += 1; + } + } + lane_sync(); + + // rjf: compute thread * digit value *relative* offset table + { + Rng1U64 range = lane_range(num_possible_values_per_digit); + for EachInRange(value_idx, range) + { + U64 layout_off = 0; + for EachIndex(lane_idx, lane_count()) + { + lanes_digit_offsets[lane_idx][value_idx] = layout_off; + layout_off += lanes_digit_counts[lane_idx][value_idx]; + } + } + } + lane_sync(); + + // rjf: convert relative offsets -> absolute offsets + if(lane_idx() == 0) + { + U64 last_off = 0; + U64 num_of_nonzero_digit = 0; + for EachIndex(value_idx, num_possible_values_per_digit) + { + for EachIndex(lane_idx, lane_count()) + { + lanes_digit_offsets[lane_idx][value_idx] += last_off; + } + last_off = lanes_digit_offsets[lane_count()-1][value_idx] + lanes_digit_counts[lane_count()-1][value_idx]; + } + // NOTE(rjf): required that: (last_off == element_count) + } + lane_sync(); + + // rjf: move + { + U32 *lane_digit_offsets = lanes_digit_offsets[lane_idx()]; + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) + { + SortRecord *src_r = &src[idx]; + U16 digit_value = (U16)(U8)(src_r->key >> (digit_idx*bits_per_digit)); + U64 dst_off = lane_digit_offsets[digit_value]; + lane_digit_offsets[digit_value] += 1; + MemoryCopyStruct(&dst[dst_off], src_r); + } + } + lane_sync(); + + // rjf: swap + { + SortRecord *swap = src; + src = dst; + dst = swap; + } + } + } + lane_sync(); + + //- rjf: produce final array DI2_SearchItemArray items = {0}; - ProfScope("flatten into array") + ProfScope("produce final array") { if(lane_idx() == 0) { @@ -1076,19 +1211,15 @@ di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_ } lane_sync_u64(&items.count, 0); lane_sync_u64(&items.v, 0); - for EachNode(n, DI2_SearchItemChunk, all_items->first) + Rng1U64 range = lane_range(sort_records_count); + for EachInRange(idx, range) { - Rng1U64 range = lane_range(n->count); - U64 dst_idx = n->base_idx + range.min; - MemoryCopy(&items.v[dst_idx], n->v, sizeof(n->v[0]) * dim_1u64(range)); + SortRecord *record = &sort_records[idx]; + DI2_SearchItem *dst_item = &items.v[idx]; + MemoryCopyStruct(dst_item, record->item); } } - - //- rjf: sort items - ProfScope("sort items") - { - - } + lane_sync(); //- rjf: bundle as artifact artifact.u64[0] = (U64)arena; diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index d1129d3c..e96f2455 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -274,7 +274,7 @@ internal void di2_conversion_completion_signal_receiver_thread_entry_point(void //////////////////////////////// //~ rjf: Search Artifact Cache Hooks / Lookups -internal AC_Artifact di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal AC_Artifact di2_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void di2_search_artifact_destroy(AC_Artifact artifact); internal DI2_SearchItemArray di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us); diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index 6143ceab..b54fb710 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -266,7 +266,7 @@ struct DASM_Artifact }; internal AC_Artifact -dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { DASM_Artifact *artifact = 0; if(lane_idx() == 0) diff --git a/src/disasm/disasm.h b/src/disasm/disasm.h index 7ccd09f8..0001693c 100644 --- a/src/disasm/disasm.h +++ b/src/disasm/disasm.h @@ -197,7 +197,7 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal AC_Artifact dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal AC_Artifact dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void dasm_artifact_destroy(AC_Artifact artifact); internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index f68da6f5..aa29c8c2 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -32,7 +32,7 @@ fs_change_gen(void) //~ rjf: Cache Interaction internal AC_Artifact -fs_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 9622e48c..132debf5 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -55,7 +55,7 @@ internal U64 fs_change_gen(void); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Accessing API -internal AC_Artifact fs_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal AC_Artifact fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void fs_artifact_destroy(AC_Artifact artifact); internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index b1ced1c3..19d175b0 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -3749,7 +3749,7 @@ struct RD_BitmapCanvasBoxDrawData }; internal AC_Artifact -rd_bitmap_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +rd_bitmap_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { Access *access = access_open(); @@ -4363,7 +4363,7 @@ struct RD_Geo3DBoxDrawData }; internal AC_Artifact -rd_geo3d_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +rd_geo3d_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { Access *access = access_open(); U128 hash = {0}; diff --git a/src/text/text.c b/src/text/text.c index 3ee0c191..d86062fc 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -1970,7 +1970,7 @@ struct TXT_ArtifactCreateShared }; internal AC_Artifact -txt_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +txt_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/text/text.h b/src/text/text.h index 1c31aa52..06e69bd4 100644 --- a/src/text/text.h +++ b/src/text/text.h @@ -203,7 +203,7 @@ internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal AC_Artifact txt_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal AC_Artifact txt_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void txt_artifact_destroy(AC_Artifact artifact); internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); From ea99cb22e72facf6b45ff54e701a356938c26117 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 11:16:15 -0700 Subject: [PATCH 003/133] dbg_info2: async match artifact cache hooks / lookup --- src/dbg_info/dbg_info2.c | 104 +++++++++++++++++++++++++++++++++++++++ src/dbg_info/dbg_info2.h | 17 +++++++ 2 files changed, 121 insertions(+) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 1e118c82..2324dd39 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -1267,3 +1267,107 @@ di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, } return result; } + +//////////////////////////////// +//~ rjf: Match Artifact Cache Hooks / Lookups + +internal AC_Artifact +di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: unpack key + U64 index = 0; + String8 name = {0}; + { + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, &index); + key_read_off += str8_deserial_read_struct(key, key_read_off, &name.size); + name.str = push_array_no_zero(scratch.arena, U8, name.size); + key_read_off += str8_deserial_read(key, key_read_off, name.str, name.size, 1); + } + + //- rjf: get all loaded keys + DI2_KeyArray dbgi_keys = di2_push_all_loaded_keys(scratch.arena); + + //- rjf: wide search across all debug infos + DI2_Match match = {0}; + { + read_only local_persist RDI_NameMapKind name_map_kinds[] = + { + RDI_NameMapKind_GlobalVariables, + RDI_NameMapKind_ThreadVariables, + RDI_NameMapKind_Constants, + RDI_NameMapKind_Procedures, + RDI_NameMapKind_Types, + }; + read_only local_persist RDI_SectionKind name_map_section_kinds[] = + { + RDI_SectionKind_GlobalVariables, + RDI_SectionKind_ThreadVariables, + RDI_SectionKind_Constants, + RDI_SectionKind_Procedures, + RDI_SectionKind_TypeNodes, + }; + Rng1U64 range = lane_range(dbgi_keys.count); + for EachInRange(dbgi_idx, range) + { + Access *access = access_open(); + { + DI2_Key dbgi_key = dbgi_keys.v[dbgi_idx]; + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + for EachElement(name_map_kind_idx, name_map_kinds) + { + RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, name_map_kinds[name_map_kind_idx]); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); + RDI_NameMapNode *map_node = rdi_name_map_lookup(rdi, &parsed_name_map, name.str, name.size); + U32 num = 0; + U32 *run = rdi_matches_from_map_node(rdi, map_node, &num); + if(num != 0) + { + match.key = dbgi_key; + match.section_kind = name_map_section_kinds[name_map_kind_idx]; + match.idx = run[num-1]; + } + } + } + access_close(access); + } + } + + //- rjf: package as artifact + AC_Artifact artifact = {0}; + { + StaticAssert(ArrayCount(artifact.u64) >= 4, artifact_size_check); + artifact.u64[0] = match.key.u64[0]; + artifact.u64[1] = match.key.u64[1]; + artifact.u64[2] = match.section_kind; + artifact.u64[3] = match.idx; + } + + scratch_end(scratch); +} + +internal DI2_Match +di2_match_from_string(String8 string, U64 index, U64 endt_us) +{ + DI2_Match result = {0}; + Access *access = access_open(); + Temp scratch = scratch_begin(0, 0); + { + String8List key_parts = {0}; + str8_list_push(scratch.arena, &key_parts, str8_struct(&index)); + str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); + str8_list_push(scratch.arena, &key_parts, string); + String8 key = str8_list_join(scratch.arena, &key_parts, 0); + AC_Artifact artifact = ac_artifact_from_key(access, key, di2_match_artifact_create, 0, endt_us, .flags = AC_Flag_Wide); + result.key.u64[0] = artifact.u64[0]; + result.key.u64[1] = artifact.u64[1]; + result.section_kind = artifact.u64[2]; + result.idx = artifact.u64[3]; + } + scratch_end(scratch); + access_close(access); + return result; +} diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index e96f2455..af2625de 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -186,6 +186,17 @@ struct DI2_SearchItemArray U64 count; }; +//////////////////////////////// +//~ rjf: Match Types + +typedef struct DI2_Match DI2_Match; +struct DI2_Match +{ + DI2_Key key; + RDI_SectionKind section_kind; + U32 idx; +}; + //////////////////////////////// //~ rjf: Shared State @@ -278,4 +289,10 @@ internal AC_Artifact di2_search_artifact_create(String8 key, B32 *cancel_signal, internal void di2_search_artifact_destroy(AC_Artifact artifact); internal DI2_SearchItemArray di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us); +//////////////////////////////// +//~ rjf: Match Artifact Cache Hooks / Lookups + +internal AC_Artifact di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal DI2_Match di2_match_from_string(String8 string, U64 index, U64 endt_us); + #endif // DBG_INFO2_H From 4b122dec51c09d453a6795c95523c2db53b71ded Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 11:21:35 -0700 Subject: [PATCH 004/133] testing / debugging --- src/dbg_info/dbg_info2.c | 1 + src/scratch/ryan_scratch.c | 47 ++++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 2324dd39..1e357805 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -1347,6 +1347,7 @@ di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) } scratch_end(scratch); + return artifact; } internal DI2_Match diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 692a9e04..7729b4e1 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -34,16 +34,53 @@ internal void entry_point(CmdLine *cmdline) { - DI2_Key key = di2_key_from_path_timestamp(str8_lit("C:/devel/raddebugger/build/raddbg.pdb"), 0); - di2_open(key); + local_persist char *pdb_paths[] = + { + "C:/devel/raddebugger/build/raddbg.pdb", + // #include "fn_debug_infos.inc" + }; + + DI2_Key keys[ArrayCount(pdb_paths)] = {0}; + for EachElement(idx, pdb_paths) + { + String8 path = str8_cstring(pdb_paths[idx]); + keys[idx] = di2_key_from_path_timestamp(path, 0); + di2_open(keys[idx]); + } + for(;;) { Access *access = access_open(); - RDI_Parsed *rdi = di2_rdi_from_key(access, key, 1, 0); - if(rdi != &rdi_parsed_nil) + B32 got_all_rdis = 1; + U64 num_rdis_loaded = 0; + for EachElement(idx, pdb_paths) { - int x = 0; + RDI_Parsed *rdi = di2_rdi_from_key(access, keys[idx], 1, 0); + if(rdi == &rdi_parsed_nil) + { + got_all_rdis = 0; + } + else + { + num_rdis_loaded += 1; + } } + printf("\rloaded [%I64u/%I64u], %I64u active threads, %I64u active processes", num_rdis_loaded, ArrayCount(pdb_paths), di2_shared->conversion_thread_count, di2_shared->conversion_process_count); access_close(access); + if(got_all_rdis) + { + Access *access = access_open(); + String8 search_query = str8_lit("rd_"); + DI2_SearchItemArray items = di2_search_item_array_from_target_query(access, RDI_SectionKind_Procedures, search_query, max_U64); + printf("\n"); + printf("fuzzy searched for %.*s, found %I64u items\n", str8_varg(search_query), items.count); + access_close(access); + + String8 match_query = str8_lit("rd_frame"); + DI2_Match match = di2_match_from_string(match_query, 0, max_U64); + printf("searched for %.*s, found at %i in [%I64x:%I64x]\n", str8_varg(match_query), match.idx, match.key.u64[0], match.key.u64[1]); + + break; + } } } From 4964a94cd3ed4848bd5180df6d04f7392048c797 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 12:52:32 -0700 Subject: [PATCH 005/133] transition to dbg_info2 --- src/base/base_thread_context.c | 4 +- src/ctrl/ctrl_core.c | 257 ++++------------------------- src/ctrl/ctrl_core.h | 6 +- src/dbg_engine/dbg_engine_core.c | 178 ++++++-------------- src/dbg_engine/dbg_engine_core.h | 21 +-- src/dbg_info/dbg_info2.c | 69 +++++++- src/dbg_info/dbg_info2.h | 2 + src/disasm/disasm.c | 10 +- src/disasm/disasm.h | 2 +- src/eval/eval_core.h | 1 - src/eval/eval_ir.c | 44 +++-- src/eval/eval_parse.c | 23 ++- src/raddbg/generated/raddbg.meta.c | 2 +- src/raddbg/generated/raddbg.meta.h | 2 +- src/raddbg/raddbg.mdesk | 4 +- src/raddbg/raddbg_core.c | 126 ++++++-------- src/raddbg/raddbg_core.h | 4 - src/raddbg/raddbg_eval.c | 92 +++++------ src/raddbg/raddbg_main.c | 4 +- src/raddbg/raddbg_views.c | 62 +++---- src/raddbg/raddbg_views.h | 4 +- src/raddbg/raddbg_widgets.c | 39 ++--- src/raddbg/raddbg_widgets.h | 2 +- 23 files changed, 356 insertions(+), 602 deletions(-) diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 3e12a8b9..a1b97d8d 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -219,7 +219,7 @@ access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params) U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us); U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched); B32 result = (access_refcount == 0 && - last_time_touched_us + params->time < os_now_microseconds() && - last_update_idx_touched + params->update_idxs < update_tick_idx()); + last_time_touched_us + params->time <= os_now_microseconds() && + last_update_idx_touched + params->update_idxs <= update_tick_idx()); return result; } diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index be446cdd..774ad4b8 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -786,11 +786,11 @@ ctrl_module_from_process_vaddr(CTRL_Entity *process, U64 vaddr) return result; } -internal DI_Key +internal DI2_Key ctrl_dbgi_key_from_module(CTRL_Entity *module) { CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - DI_Key dbgi_key = {debug_info_path->string, debug_info_path->timestamp}; + DI2_Key dbgi_key = di2_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp); return dbgi_key; } @@ -1176,15 +1176,15 @@ ctrl_entity_array_from_kind(CTRL_EntityCtx *ctx, CTRL_EntityKind kind) } internal CTRL_EntityList -ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key *dbgi_key) +ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI2_Key dbgi_key) { CTRL_EntityList list = {0}; CTRL_EntityArray all_modules = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Module); for EachIndex(idx, all_modules.count) { CTRL_Entity *module = all_modules.v[idx]; - DI_Key module_dbgi_key = ctrl_dbgi_key_from_module(module); - if(di_key_match(&module_dbgi_key, dbgi_key)) + DI2_Key module_dbgi_key = ctrl_dbgi_key_from_module(module); + if(di2_key_match(module_dbgi_key, dbgi_key)) { ctrl_entity_list_push(arena, &list, module); } @@ -2756,7 +2756,7 @@ internal CTRL_CallStack ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *base_unwind) { Temp scratch = scratch_begin(&arena, 1); - DI_Scope *di_scope = di_scope_open(); + Access *access = access_open(); Arch arch = process->arch; CTRL_CallStack result = {0}; { @@ -2778,8 +2778,8 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas U64 rip_vaddr = regs_rip_from_arch_block(arch, src->regs); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); RDI_Scope *scope = rdi_scope_from_voff(rdi, rip_voff); // rjf: build inline frames (minus parent & inline depth) @@ -2841,7 +2841,7 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas } } } - di_scope_close(di_scope); + access_close(access); scratch_end(scratch); return result; } @@ -3185,16 +3185,16 @@ ctrl_thread__entry_point(void *p) String8 path = msg->path; CTRL_Entity *module = ctrl_entity_from_handle(entity_ctx, msg->entity); CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - DI_Key old_dbgi_key = {debug_info_path->string, debug_info_path->timestamp}; - di_close(&old_dbgi_key); + DI2_Key old_dbgi_key = di2_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp); + di2_close(old_dbgi_key); MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) { ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path_normalized_from_string(scratch.arena, path)); } U64 new_dbgi_timestamp = os_properties_from_file_path(path).modified; debug_info_path->timestamp = new_dbgi_timestamp; - DI_Key new_dbgi_key = {debug_info_path->string, new_dbgi_timestamp}; - di_open(&new_dbgi_key); + DI2_Key new_dbgi_key = di2_key_from_path_timestamp(debug_info_path->string, new_dbgi_timestamp); + di2_open(new_dbgi_key); CTRL_EventList evts = {0}; CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); evt->kind = CTRL_EventKind_ModuleDebugInfoPathChange; @@ -3259,12 +3259,12 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope * if(user_bps->first == 0) { return; } ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); - DI_Scope *di_scope = eval_scope->di_scope; + Access *access = eval_scope->access; CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; CTRL_Entity *module_entity = ctrl_entity_from_handle(entity_ctx, module); CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath); - DI_Key dbgi_key = {debug_info_path_entity->string, debug_info_path_entity->timestamp}; - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module_entity); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); U64 base_vaddr = module_entity->vaddr_range.min; for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { @@ -3828,7 +3828,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, if(!should_filter_event && ev->code == 0xc0000005 && (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)) { - DI_Scope *di_scope = di_scope_open(); + Access *access = access_open(); CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, ev->process)); CTRL_Entity *module = &ctrl_entity_nil; for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) @@ -3844,9 +3844,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, // rjf: determine base address of asan shadow space U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; - CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, max_U64); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, max_U64); RDI_NameMap *unparsed_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_GlobalVariables); { RDI_ParsedNameMap map = {0}; @@ -3888,7 +3887,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, } } - di_scope_close(di_scope); + access_close(access); } }break; } @@ -4057,8 +4056,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt2->parent = process_handle; out_evt2->timestamp = debug_info_timestamp; out_evt2->string = initial_debug_info_path; - DI_Key initial_dbgi_key = {initial_debug_info_path, debug_info_timestamp}; - di_open(&initial_dbgi_key); + DI2_Key initial_dbgi_key = di2_key_from_path_timestamp(initial_debug_info_path, debug_info_timestamp); + di2_open(initial_dbgi_key); }break; case DMN_EventKind_ExitProcess: { @@ -4090,12 +4089,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt->msg_id = msg->msg_id; out_evt->entity = module_handle; out_evt->string = module_path; - CTRL_Entity *debug_info_path_ent = ctrl_entity_child_from_kind(module_ent, CTRL_EntityKind_DebugInfoPath); - if(debug_info_path_ent != &ctrl_entity_nil) - { - DI_Key dbgi_key = {debug_info_path_ent->string, debug_info_path_ent->timestamp}; - di_close(&dbgi_key); - } + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module_ent); + di2_close(dbgi_key); }break; case DMN_EventKind_DebugString: { @@ -4169,187 +4164,6 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, ctrl_state->dbg_dir_root = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1); } - //- rjf: when a new module is loaded, pre-emptively try to open all adjacent - // debug infos. with debug events, we learn about loaded modules serially, - // and we need to completely load debug info before continuing. for massive - // projects, this is a problem, because completely loading debug info isn't a - // trivial cost, and there are often 1000s of DLLs. - // - // an imperfect but usually reasonable heuristic is to look at adjacent - // debug info files, in the same or under the directory as the initially - // loaded, and pre-emptively convert all of them (which for us is the - // heaviest part of debug info loading, if native RDI is not used). - // - // only do this on the first ever loaded module, *or* once we get beyond 256 - // modules (a very bad heuristic that may or may not inform us that we are - // dealing with insane-town projects) - // - if(0 && - event->kind == DMN_EventKind_LoadModule && - (entity_ctx->entity_kind_counts[CTRL_EntityKind_Module] > 256 || - entity_ctx->entity_kind_counts[CTRL_EntityKind_Module] == 1)) - { - //- rjf: unpack event - CTRL_Handle process_handle = ctrl_handle_make(CTRL_MachineID_Local, event->process); - CTRL_Handle loaded_module_handle = ctrl_handle_make(CTRL_MachineID_Local, event->module); - CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, process_handle); - CTRL_Entity *loaded_module = ctrl_entity_from_handle(entity_ctx, loaded_module_handle); - - //- rjf: for each module, use its full path as the start to a new limited recursive - // directory search. cache each directory once traversed in the dbg_dir tree. if any - // node is not cached, then scan it & pre-emptively convert debug info. - ProfScope("pre-emptively load adjacent debug info for %.*s", str8_varg(loaded_module->string)) - { - //- rjf: calculate seed path - DI_Key loaded_di_key = ctrl_dbgi_key_from_module(loaded_module); - String8 loaded_di_name = str8_skip_last_slash(loaded_di_key.path); - String8 debug_info_ext = str8_skip_last_dot(loaded_di_key.path); - String8 seed_folder_path = str8_chop_last_slash(loaded_di_key.path); - if(seed_folder_path.size == 0) - { - String8 module_path = loaded_module->string; - seed_folder_path = str8_chop_last_slash(module_path); - } - - //- rjf: split seed path - String8List seed_path_parts = str8_split_path(scratch.arena, seed_folder_path); - - //- rjf: find parent dir node for this module's debug info; build tree leading to this dir - CTRL_DbgDirNode *parent_dir_node = ctrl_state->dbg_dir_root; - for(String8Node *n = seed_path_parts.first; n != 0; n = n->next) - { - String8 name = n->string; - CTRL_DbgDirNode *next_child = 0; - for(CTRL_DbgDirNode *child = parent_dir_node->first; child != 0; child = child->next) - { - if(str8_match(child->name, name, StringMatchFlag_CaseInsensitive)) - { - next_child = child; - break; - } - } - if(next_child == 0) - { - next_child = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1); - DLLPushBack(parent_dir_node->first, parent_dir_node->last, next_child); - next_child->parent = parent_dir_node; - next_child->name = push_str8_copy(ctrl_state->dbg_dir_arena, name); - parent_dir_node->child_count += 1; - } - parent_dir_node = next_child; - } - - //- rjf: count modules - { - parent_dir_node->module_direct_count += 1; - } - - //- rjf: iterate from dir node up its ancestor chain - do recursive - // searches if this is an ancestor of loaded modules, it has not been - // searched yet, but it has >4 child branches, meaning it looks like - // project directory - // - DI_KeyList preemptively_loaded_keys = {0}; - for(CTRL_DbgDirNode *dir_node = parent_dir_node; dir_node != 0; dir_node = dir_node->parent) - { - if(dir_node->search_count == 0 && dir_node->module_direct_count >= 1) - { - //- rjf: form full path of this directory node - String8List dir_node_path_parts = {0}; - for(CTRL_DbgDirNode *n = dir_node; n != 0; n = n->parent) - { - if(n->name.size != 0) - { - str8_list_push_front(scratch.arena, &dir_node_path_parts, n->name); - } - } - String8 dir_node_path = str8_list_join(scratch.arena, &dir_node_path_parts, &(StringJoin){.sep = str8_lit("/")}); - - //- rjf: iterate downwards from this directory recursively, locate - // debug infos, and pre-emptively convert - typedef struct Task Task; - struct Task - { - Task *next; - CTRL_DbgDirNode *node; - String8 path; - }; - Task start_task = {0, dir_node, dir_node_path}; - Task *first_task = &start_task; - Task *last_task = first_task; - U64 task_count = 0; - for(Task *t = first_task; t != 0; t = t->next) - { - ProfBegin("search task %.*s", str8_varg(t->path)); - - // rjf: increment search counter - t->node->search_count += 1; - - // rjf: iterate this directory. if debug infos are encountered, - // kick off pre-emptive conversion, and gather key. if folders - // are encountered, then add them to the tree, and kick off a - // sub-search if needed. - OS_FileIter *it = os_file_iter_begin(scratch.arena, t->path, 0); - U64 idx = 0; - for(OS_FileInfo info = {0}; idx < 16384 && os_file_iter_next(scratch.arena, it, &info); idx += 1) - { - // rjf: folder -> do sub-search if not duplicative - if(info.props.flags & FilePropertyFlag_IsFolder && task_count < 16384 && !str8_match(str8_prefix(info.name, 1), str8_lit("."), 0)) - { - CTRL_DbgDirNode *existing_dir_child = 0; - for(CTRL_DbgDirNode *child = t->node->first; child != 0; child = child->next) - { - if(str8_match(child->name, info.name, StringMatchFlag_CaseInsensitive)) - { - existing_dir_child = child; - break; - } - } - if(existing_dir_child == 0) - { - existing_dir_child = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1); - DLLPushBack(t->node->first, t->node->last, existing_dir_child); - existing_dir_child->parent = t->node; - existing_dir_child->name = push_str8_copy(ctrl_state->dbg_dir_arena, info.name); - t->node->child_count += 1; - } - if(existing_dir_child->search_count == 0) - { - Task *task = push_array(scratch.arena, Task, 1); - task->node = existing_dir_child; - task->path = push_str8f(scratch.arena, "%S/%S", t->path, info.name); - SLLQueuePush(first_task, last_task, task); - task_count += 1; - } - } - - // rjf: debug info file -> kick off open - else if(preemptively_loaded_keys.count < 4096 && - !(info.props.flags & FilePropertyFlag_IsFolder) && - str8_match(str8_skip_last_dot(info.name), debug_info_ext, StringMatchFlag_CaseInsensitive) && - !str8_match(loaded_di_name, info.name, StringMatchFlag_CaseInsensitive)) - { - DI_Key key = {push_str8f(scratch.arena, "%S/%S", t->path, info.name), info.props.modified}; - di_open(&key); - di_key_list_push(scratch.arena, &preemptively_loaded_keys, &key); - if(preemptively_loaded_keys.count >= Max(1, async_thread_count()/2)) - { - for(DI_KeyNode *n = preemptively_loaded_keys.first; n != 0; n = n->next) - { - di_close(&n->v); - } - MemoryZeroStruct(&preemptively_loaded_keys); - } - } - } - os_file_iter_end(it); - ProfEnd(); - } - } - } - } - } - //- rjf: out of queued up demon events -> clear event arena if(ctrl_state->first_dmn_event_node == 0) { @@ -4416,7 +4230,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C { CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; CTRL_EvalScope *scope = push_array(arena, CTRL_EvalScope, 1); - scope->di_scope = di_scope_open(); + scope->access = access_open(); ////////////////////////////// //- rjf: unpack thread @@ -4452,11 +4266,10 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C mod = mod->next) { if(mod->kind != CTRL_EntityKind_Module) { continue; } - CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath); - DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(mod); //- rjf: try to obtain this module's RDI - RDI_Parsed *rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, 1, 0); + RDI_Parsed *rdi = di2_rdi_from_key(scope->access, dbgi_key, 0, 0); //- rjf: if this RDI is not yet ready => determine if we need to wait for it // @@ -4488,7 +4301,8 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C // rjf: not cached -> compute & store else ProfScope("cache miss") { - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, dbgi_key.path); + CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath); + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, debug_info_path->string); { //- rjf: determine if file is PDB B32 file_is_pdb = 0; @@ -4538,7 +4352,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C //- rjf: if this RDI is necessary, but we do not have it => wait for it forever if(rdi == &rdi_parsed_nil && rdi_is_necessary) { - rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, 1, max_U64); + rdi = di2_rdi_from_key(scope->access, dbgi_key, 1, max_U64); } //- rjf: fill evaluation module info @@ -4625,7 +4439,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C internal void ctrl_thread__eval_scope_end(CTRL_EvalScope *scope) { - di_scope_close(scope->di_scope); + access_close(scope->access); } //- rjf: log flusher @@ -5351,15 +5165,14 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) if(msg->run_flags & CTRL_RunFlag_StopOnEntryPoint && !launch_done_first_module && event->kind == DMN_EventKind_HandshakeComplete) { launch_done_first_module = 1; - DI_Scope *di_scope = di_scope_open(); + Access *access = access_open(); //- rjf: unpack process/module info CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->process)); CTRL_Entity *module = ctrl_entity_child_from_kind(process, CTRL_EntityKind_Module); U64 module_base_vaddr = module->vaddr_range.min; - CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, max_U64); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, max_U64); RDI_NameMap *unparsed_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures); RDI_ParsedNameMap map = {0}; rdi_parsed_from_name_map(rdi, unparsed_map, &map); @@ -5572,7 +5385,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: found entry points -> add to joined traps dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &entry_traps); - di_scope_close(di_scope); + access_close(access); } ////////////////////////// diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 218dc1af..36db33cd 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -650,7 +650,7 @@ struct CTRL_DbgDirNode typedef struct CTRL_EvalScope CTRL_EvalScope; struct CTRL_EvalScope { - DI_Scope *di_scope; + Access *access; E_BaseCtx base_ctx; E_IRCtx ir_ctx; E_InterpretCtx interpret_ctx; @@ -845,7 +845,7 @@ internal CTRL_Entity *ctrl_entity_child_from_kind(CTRL_Entity *parent, CTRL_Enti internal CTRL_Entity *ctrl_entity_ancestor_from_kind(CTRL_Entity *entity, CTRL_EntityKind kind); internal CTRL_Entity *ctrl_process_from_entity(CTRL_Entity *entity); internal CTRL_Entity *ctrl_module_from_process_vaddr(CTRL_Entity *process, U64 vaddr); -internal DI_Key ctrl_dbgi_key_from_module(CTRL_Entity *module); +internal DI2_Key ctrl_dbgi_key_from_module(CTRL_Entity *module); internal CTRL_Entity *ctrl_module_from_thread_candidates(CTRL_EntityCtx *ctx, CTRL_Entity *thread, CTRL_EntityList *candidates); internal U64 ctrl_vaddr_from_voff(CTRL_Entity *module, U64 voff); internal U64 ctrl_voff_from_vaddr(CTRL_Entity *module, U64 vaddr); @@ -877,7 +877,7 @@ internal void ctrl_entity_equip_string(CTRL_EntityCtxRWStore *store, CTRL_Entity //- rjf: accelerated entity context lookups internal CTRL_EntityCtxLookupAccel *ctrl_thread_entity_ctx_lookup_accel(void); internal CTRL_EntityArray ctrl_entity_array_from_kind(CTRL_EntityCtx *ctx, CTRL_EntityKind kind); -internal CTRL_EntityList ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key *dbgi_key); +internal CTRL_EntityList ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI2_Key dbgi_key); internal CTRL_Entity *ctrl_thread_from_id(CTRL_EntityCtx *ctx, U64 id); //- rjf: applying events to entity caches diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index d5e2ad00..9895bd6a 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -152,7 +152,6 @@ d_line_list_copy(Arena *arena, D_LineList *list) D_LineNode *dst_n = push_array(arena, D_LineNode, 1); MemoryCopyStruct(dst_n, src_n); dst_n->v.file_path = push_str8_copy(arena, dst_n->v.file_path); - dst_n->v.dbgi_key = di_key_copy(arena, &src_n->v.dbgi_key); SLLQueuePush(dst.first, dst.last, dst_n); dst.count += 1; } @@ -340,15 +339,15 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) U64 ip_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); log_infof("ip_vaddr: 0x%I64x\n", ip_vaddr); - log_infof("dbgi_key: {%S, 0x%I64x}\n", dbgi_key.path, dbgi_key.min_timestamp); + log_infof("dbgi_key: {0x%I64x, 0x%I64x}\n", dbgi_key.u64[0], dbgi_key.u64[1]); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; { U64 ip_voff = ctrl_voff_from_vaddr(module, ip_vaddr); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, ip_voff); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, ip_voff); Rng1U64 line_voff_rng = {0}; if(lines.first != 0) { @@ -366,7 +365,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) // is enabled. This is enabled by default normally. { U64 opl_line_voff_rng = ctrl_voff_from_vaddr(module, line_vaddr_rng.max); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, opl_line_voff_rng); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, opl_line_voff_rng); if(lines.first != 0 && (lines.first->v.pt.line == 0xf00f00 || lines.first->v.pt.line == 0xfeefee)) { line_vaddr_rng.max = ctrl_vaddr_from_voff(module, lines.first->v.voff_range.max); @@ -503,13 +502,13 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) U64 ip_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; { U64 ip_voff = ctrl_voff_from_vaddr(module, ip_vaddr); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, ip_voff); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, ip_voff); Rng1U64 line_voff_rng = {0}; if(lines.first != 0) { @@ -524,7 +523,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) // is enabled. This is enabled by default normally. { U64 opl_line_voff_rng = ctrl_voff_from_vaddr(module, line_vaddr_rng.max); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, opl_line_voff_rng); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, opl_line_voff_rng); if(lines.first != 0 && (lines.first->v.pt.line == 0xf00f00 || lines.first->v.pt.line == 0xfeefee)) { line_vaddr_rng.max = ctrl_vaddr_from_voff(module, lines.first->v.voff_range.max); @@ -586,8 +585,8 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) U64 jump_dest_vaddr = point->jump_dest_vaddr; CTRL_Entity *jump_dest_module = ctrl_module_from_process_vaddr(process, jump_dest_vaddr); U64 jump_dest_voff = ctrl_voff_from_vaddr(jump_dest_module, jump_dest_vaddr); - DI_Key jump_dest_dbgi_key = ctrl_dbgi_key_from_module(jump_dest_module); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &jump_dest_dbgi_key, jump_dest_voff); + DI2_Key jump_dest_dbgi_key = ctrl_dbgi_key_from_module(jump_dest_module); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, jump_dest_dbgi_key, jump_dest_voff); if(lines.count == 0) { add = 0; @@ -644,97 +643,14 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: symbol -> voff lookups - -internal U64 -d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - DI_Scope *scope = di_scope_open(); - U64 result = 0; - { - RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0); - RDI_NameMapKind name_map_kinds[] = - { - RDI_NameMapKind_GlobalVariables, - RDI_NameMapKind_Procedures, - }; - if(rdi != &rdi_parsed_nil) - { - for(U64 name_map_kind_idx = 0; - name_map_kind_idx < ArrayCount(name_map_kinds); - name_map_kind_idx += 1) - { - RDI_NameMapKind name_map_kind = name_map_kinds[name_map_kind_idx]; - RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, name_map_kind); - RDI_ParsedNameMap parsed_name_map = {0}; - rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, symbol_name.str, symbol_name.size); - - // rjf: node -> num - U64 entity_num = 0; - if(node != 0) - { - switch(node->match_count) - { - case 1: - { - entity_num = node->match_idx_or_idx_run_first + 1; - }break; - default: - { - U32 num = 0; - U32 *run = rdi_matches_from_map_node(rdi, node, &num); - if(num != 0) - { - entity_num = run[0]+1; - } - }break; - } - } - - // rjf: num -> voff - U64 voff = 0; - if(entity_num != 0) switch(name_map_kind) - { - default:{}break; - case RDI_NameMapKind_GlobalVariables: - { - RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, entity_num-1); - voff = global_var->voff; - }break; - case RDI_NameMapKind_Procedures: - { - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, entity_num-1); - RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx); - voff = *rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_first); - }break; - } - - // rjf: nonzero voff -> break - if(voff != 0) - { - result = voff; - break; - } - } - } - } - di_scope_close(scope); - scratch_end(scratch); - ProfEnd(); - return result; -} - //- rjf: voff -> line info internal D_LineList -d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff) +d_lines_from_dbgi_key_voff(Arena *arena, DI2_Key dbgi_key, U64 voff) { Temp scratch = scratch_begin(&arena, 1); - DI_Scope *scope = di_scope_open(); - RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0); + Access *access = access_open(); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, 0); D_LineList result = {0}; { //- rjf: gather line tables @@ -799,7 +715,7 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff) } n->v.pt = txt_pt(line->line_num, column ? column->col_first : 1); n->v.voff_range = r1u64(parsed_line_table.voffs[line_info_idx], parsed_line_table.voffs[line_info_idx+1]); - n->v.dbgi_key = *dbgi_key; + n->v.dbgi_key = dbgi_key; if(line_table_n == top_line_table) { shallowest_voff_range = n->v.voff_range; @@ -813,7 +729,7 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff) n->v.voff_range = intersect_1u64(n->v.voff_range, shallowest_voff_range); } } - di_scope_close(scope); + access_close(access); scratch_end(scratch); return result; } @@ -823,17 +739,17 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff) // TODO(rjf): this depends on file path maps, needs to move internal D_LineListArray -d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range) +d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI2_Key dbgi_key, String8 file_path, Rng1S64 line_num_range) { D_LineListArray array = {0}; { array.count = dim_1s64(line_num_range)+1; array.v = push_array(arena, D_LineList, array.count); - di_key_list_push(arena, &array.dbgi_keys, &dbgi_key); + di2_key_list_push(arena, &array.dbgi_keys, dbgi_key); } Temp scratch = scratch_begin(&arena, 1); U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count); - DI_Scope *scope = di_scope_open(); + Access *access = access_open(); String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path); for(String8Node *override_n = overrides.first; override_n != 0; @@ -843,7 +759,7 @@ d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path_normalized = lower_from_str8(scratch.arena, path_normalized_from_string(scratch.arena, file_path)); // rjf: binary -> rdi - RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; @@ -911,7 +827,7 @@ d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, } } } - di_scope_close(scope); + access_close(access); scratch_end(scratch); return array; } @@ -926,8 +842,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 } Temp scratch = scratch_begin(&arena, 1); U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count); - DI_Scope *scope = di_scope_open(); - DI_KeyList dbgi_keys = d_push_active_dbgi_key_list(scratch.arena); + DI2_KeyArray dbgi_keys = di2_push_all_loaded_keys(scratch.arena); String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path); for(String8Node *override_n = overrides.first; override_n != 0; @@ -935,13 +850,13 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 { String8 file_path = override_n->string; String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); - for(DI_KeyNode *dbgi_key_n = dbgi_keys.first; - dbgi_key_n != 0; - dbgi_key_n = dbgi_key_n->next) + for EachIndex(idx, dbgi_keys.count) { + Access *access = access_open(); + // rjf: binary -> rdi - DI_Key key = dbgi_key_n->v; - RDI_Parsed *rdi = di_rdi_from_key(scope, &key, 1, 0); + DI2_Key key = dbgi_keys.v[idx]; + RDI_Parsed *rdi = di2_rdi_from_key(access, key, 1, 0); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; @@ -1012,17 +927,18 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 // rjf: good src id -> push to relevant dbgi keys if(good_src_id) { - di_key_list_push(arena, &array.dbgi_keys, &key); + di2_key_list_push(arena, &array.dbgi_keys, key); } + + access_close(access); } } - di_scope_close(scope); scratch_end(scratch); return array; } internal D_LineList -d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num) +d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI2_Key dbgi_key, String8 file_path, S64 line_num) { D_LineListArray array = d_lines_array_from_dbgi_key_file_path_line_range(arena, dbgi_key, file_path, r1s64(line_num, line_num+1)); D_LineList list = {0}; @@ -1175,16 +1091,16 @@ d_ctrl_targets_running(void) //- rjf: active entity based queries -internal DI_KeyList +internal DI2_KeyList d_push_active_dbgi_key_list(Arena *arena) { - DI_KeyList dbgis = {0}; + DI2_KeyList dbgis = {0}; CTRL_EntityArray modules = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Module); for EachIndex(idx, modules.count) { CTRL_Entity *module = modules.v[idx]; - DI_Key key = ctrl_dbgi_key_from_module(module); - di_key_list_push(arena, &dbgis, &key); + DI2_Key key = ctrl_dbgi_key_from_module(module); + di2_key_list_push(arena, &dbgis, key); } return dbgis; } @@ -1271,7 +1187,7 @@ d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 ro } internal E_String2NumMap * -d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) +d_query_cached_locals_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) { ProfBeginFunction(); E_String2NumMap *map = &e_string2num_map_nil; @@ -1287,13 +1203,13 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) { break; } - U64 hash = di_hash_from_key(dbgi_key); + U64 hash = u64_hash_from_str8(str8_struct(&dbgi_key)); U64 slot_idx = hash % cache->table_size; D_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; D_RunLocalsCacheNode *node = 0; for(D_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(di_key_match(&n->dbgi_key, dbgi_key) && n->voff == voff) + if(di2_key_match(n->dbgi_key, dbgi_key) && n->voff == voff) { node = n; break; @@ -1301,18 +1217,18 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) } if(node == 0) { - DI_Scope *scope = di_scope_open(); - RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0); + Access *access = access_open(); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, 0); E_String2NumMap *map = e_push_locals_map_from_rdi_voff(cache->arena, rdi, voff); if(map->slots_count != 0) { node = push_array(cache->arena, D_RunLocalsCacheNode, 1); - node->dbgi_key = di_key_copy(cache->arena, dbgi_key); + node->dbgi_key = dbgi_key; node->voff = voff; node->locals_map = map; SLLQueuePush_N(slot->first, slot->last, node, hash_next); } - di_scope_close(scope); + access_close(access); } if(node != 0 && node->locals_map->slots_count != 0) { @@ -1325,7 +1241,7 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) } internal E_String2NumMap * -d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) +d_query_cached_member_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) { ProfBeginFunction(); E_String2NumMap *map = &e_string2num_map_nil; @@ -1341,13 +1257,13 @@ d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) { break; } - U64 hash = di_hash_from_key(dbgi_key); + U64 hash = u64_hash_from_str8(str8_struct(&dbgi_key)); U64 slot_idx = hash % cache->table_size; D_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; D_RunLocalsCacheNode *node = 0; for(D_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(di_key_match(&n->dbgi_key, dbgi_key) && n->voff == voff) + if(di2_key_match(n->dbgi_key, dbgi_key) && n->voff == voff) { node = n; break; @@ -1355,18 +1271,18 @@ d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) } if(node == 0) { - DI_Scope *scope = di_scope_open(); - RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0); + Access *access = access_open(); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, 0); E_String2NumMap *map = e_push_member_map_from_rdi_voff(cache->arena, rdi, voff); if(map->slots_count != 0) { node = push_array(cache->arena, D_RunLocalsCacheNode, 1); - node->dbgi_key = di_key_copy(cache->arena, dbgi_key); + node->dbgi_key = dbgi_key; node->voff = voff; node->locals_map = map; SLLQueuePush_N(slot->first, slot->last, node, hash_next); } - di_scope_close(scope); + access_close(access); } if(node != 0 && node->locals_map->slots_count != 0) { diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index 9b7aeafc..d39e3237 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -126,7 +126,7 @@ struct D_Line String8 file_path; TxtPt pt; Rng1U64 voff_range; - DI_Key dbgi_key; + DI2_Key dbgi_key; }; typedef struct D_LineNode D_LineNode; @@ -149,7 +149,7 @@ struct D_LineListArray { D_LineList *v; U64 count; - DI_KeyList dbgi_keys; + DI2_KeyList dbgi_keys; }; //////////////////////////////// @@ -248,7 +248,7 @@ typedef struct D_RunLocalsCacheNode D_RunLocalsCacheNode; struct D_RunLocalsCacheNode { D_RunLocalsCacheNode *hash_next; - DI_Key dbgi_key; + DI2_Key dbgi_key; U64 voff; E_String2NumMap *locals_map; }; @@ -365,18 +365,15 @@ internal CTRL_TrapList d_trap_net_from_thread__step_into_line(Arena *arena, CTRL //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: symbol -> voff lookups -internal U64 d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name); - //- rjf: voff -> line info -internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff); +internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI2_Key dbgi_key, U64 voff); //- rjf: file:line -> line info // TODO(rjf): this depends on file path maps, needs to move // TODO(rjf): need to clean this up & dedup -internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range); +internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI2_Key dbgi_key, String8 file_path, Rng1S64 line_num_range); internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range); -internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num); +internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI2_Key dbgi_key, String8 file_path, S64 line_num); internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num); //////////////////////////////// @@ -402,14 +399,14 @@ internal U64 d_ctrl_last_run_frame_idx(void); internal B32 d_ctrl_targets_running(void); //- rjf: active entity based queries -internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena); +internal DI2_KeyList d_push_active_dbgi_key_list(Arena *arena); //- rjf: per-run caches internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread); internal U64 d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count); internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr); -internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff); -internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff); +internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff); +internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff); //- rjf: top-level command dispatch internal void d_push_cmd(D_CmdKind kind, D_CmdParams *params); diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 1e357805..7ada292f 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -18,6 +18,30 @@ di2_key_match(DI2_Key a, DI2_Key b) return result; } +internal void +di2_key_list_push(Arena *arena, DI2_KeyList *list, DI2_Key key) +{ + DI2_KeyNode *n = push_array(arena, DI2_KeyNode, 1); + n->v = key; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal DI2_KeyArray +di2_key_array_from_list(Arena *arena, DI2_KeyList *list) +{ + DI2_KeyArray array = {0}; + array.count = list->count; + array.v = push_array(arena, DI2_Key, array.count); + U64 idx = 0; + for EachNode(n, DI2_KeyNode, list->first) + { + array.v[idx] = n->v; + idx += 1; + } + return array; +} + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -269,6 +293,7 @@ di2_open(DI2_Key key) batch->count += 1; } cond_var_broadcast(async_tick_start_cond_var); + ins_atomic_u32_eval_assign(&async_loop_again, 1); } } @@ -327,7 +352,10 @@ di2_close(DI2_Key key) //- rjf: release node's resources if needed if(node_released) { - arena_release(arena); + if(arena != 0) + { + arena_release(arena); + } os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); os_file_map_close(file_map); os_file_close(file); @@ -398,7 +426,7 @@ di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us) B32 grabbed = 0; for(DI2_Node *n = slot->first; n != 0; n = n->next) { - if(di2_key_match(n->key, key)) + if(di2_key_match(n->key, key) && ins_atomic_u64_eval(&n->refcount) > 0) { found = 1; if(high_priority && ins_atomic_u64_eval_cond_assign(&n->batch_request_counts[0], 1, 0) == 0) @@ -427,6 +455,7 @@ di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us) batch->count += 1; } cond_var_broadcast(async_tick_start_cond_var); + ins_atomic_u32_eval_assign(&async_loop_again, 1); } // rjf: found current results, or out-of-time? abort @@ -695,6 +724,14 @@ di2_async_tick(void) t->status = DI2_LoadTaskStatus_Done; } + //- rjf: if the RDI for this task *is* stale, but the O.G. path is actually RDI, + // then we can't actually re-convert to produce a non-stale RDI. in this case, just + // mark as done. + if(rdi_is_stale && og_is_rdi) + { + t->status = DI2_LoadTaskStatus_Done; + } + //- rjf: if task is done, retire & recycle task; gather path to load if(t->status == DI2_LoadTaskStatus_Done) { @@ -853,6 +890,7 @@ di2_conversion_completion_signal_receiver_thread_entry_point(void *p) if(semaphore_take(di2_shared->conversion_completion_signal_semaphore, max_U64)) { cond_var_broadcast(async_tick_start_cond_var); + ins_atomic_u32_eval_assign(&async_loop_again, 1); } } } @@ -1291,7 +1329,12 @@ di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) DI2_KeyArray dbgi_keys = di2_push_all_loaded_keys(scratch.arena); //- rjf: wide search across all debug infos - DI2_Match match = {0}; + DI2_Match *lane_matches = 0; + if(lane_idx() == 0) + { + lane_matches = push_array(scratch.arena, DI2_Match, lane_count()); + } + lane_sync_u64(&lane_matches, 0); { read_only local_persist RDI_NameMapKind name_map_kinds[] = { @@ -1326,15 +1369,27 @@ di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) U32 *run = rdi_matches_from_map_node(rdi, map_node, &num); if(num != 0) { - match.key = dbgi_key; - match.section_kind = name_map_section_kinds[name_map_kind_idx]; - match.idx = run[num-1]; + lane_matches[lane_idx()].key = dbgi_key; + lane_matches[lane_idx()].section_kind = name_map_section_kinds[name_map_kind_idx]; + lane_matches[lane_idx()].idx = run[num-1]; } } } access_close(access); } } + lane_sync(); + + //- rjf: pick match + DI2_Match match = {0}; + for EachIndex(idx, lane_count()) + { + if(lane_matches[idx].idx != 0) + { + match = lane_matches[idx]; + break; + } + } //- rjf: package as artifact AC_Artifact artifact = {0}; @@ -1362,7 +1417,7 @@ di2_match_from_string(String8 string, U64 index, U64 endt_us) str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); str8_list_push(scratch.arena, &key_parts, string); String8 key = str8_list_join(scratch.arena, &key_parts, 0); - AC_Artifact artifact = ac_artifact_from_key(access, key, di2_match_artifact_create, 0, endt_us, .flags = AC_Flag_Wide); + AC_Artifact artifact = ac_artifact_from_key(access, key, di2_match_artifact_create, 0, endt_us, .flags = AC_Flag_Wide, .gen = di2_load_gen()); result.key.u64[0] = artifact.u64[0]; result.key.u64[1] = artifact.u64[1]; result.section_kind = artifact.u64[2]; diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index af2625de..96671f1e 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -247,6 +247,8 @@ global DI2_Shared *di2_shared = 0; internal DI2_Key di2_key_zero(void); internal B32 di2_key_match(DI2_Key a, DI2_Key b); +internal void di2_key_list_push(Arena *arena, DI2_KeyList *list, DI2_Key key); +internal DI2_KeyArray di2_key_array_from_list(Arena *arena, DI2_KeyList *list); //////////////////////////////// //~ rjf: Main Layer Initialization diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index b54fb710..b740448a 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -185,7 +185,7 @@ dasm_params_match(DASM_Params *a, DASM_Params *b) a->style_flags == b->style_flags && a->syntax == b->syntax && a->base_vaddr == b->base_vaddr && - di_key_match(&a->dbgi_key, &b->dbgi_key)); + di2_key_match(a->dbgi_key, b->dbgi_key)); return result; } @@ -273,7 +273,6 @@ dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { Temp scratch = scratch_begin(0, 0); Access *access = access_open(); - DI_Scope *di_scope = di_scope_open(); //- rjf: unpack key U128 hash = {0}; @@ -281,15 +280,14 @@ dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) U64 key_read_off = 0; key_read_off += str8_deserial_read_struct(key, key_read_off, &hash); key_read_off += str8_deserial_read_struct(key, key_read_off, ¶ms); - params.dbgi_key.path.str = key.str + key_read_off; String8 data = c_data_from_hash(access, hash); //- rjf: get dbg info B32 stale = 0; RDI_Parsed *rdi = &rdi_parsed_nil; - if(params.dbgi_key.path.size != 0) + if(!di2_key_match(params.dbgi_key, di2_key_zero())) { - rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, 0); + rdi = di2_rdi_from_key(access, params.dbgi_key, 0, 0); stale = (stale || (rdi == &rdi_parsed_nil)); } @@ -483,7 +481,6 @@ dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) artifact->data_hash = hash; } - di_scope_close(di_scope); access_close(access); scratch_end(scratch); } @@ -514,7 +511,6 @@ dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) String8List key_parts = {0}; str8_list_push(scratch.arena, &key_parts, str8_struct(&hash)); str8_list_push(scratch.arena, &key_parts, str8_struct(params)); - str8_list_push(scratch.arena, &key_parts, params->dbgi_key.path); String8 key = str8_list_join(scratch.arena, &key_parts, 0); // rjf: get info diff --git a/src/disasm/disasm.h b/src/disasm/disasm.h index 0001693c..9b5c9b54 100644 --- a/src/disasm/disasm.h +++ b/src/disasm/disasm.h @@ -97,7 +97,7 @@ struct DASM_Params DASM_StyleFlags style_flags; DASM_Syntax syntax; U64 base_vaddr; - DI_Key dbgi_key; + DI2_Key dbgi_key; }; //////////////////////////////// diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index dce2082c..e1baf525 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -763,7 +763,6 @@ struct E_BaseCtx E_Module *modules; U64 modules_count; E_Module *primary_module; - DI_MatchStore *dbgi_match_store; // rjf: space hooks void *space_rw_user_data; diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index ab6da91f..2f5131e9 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -1866,9 +1866,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I //- rjf: debug info matches case E_IdentifierResolutionPath_DebugInfoMatch: { - if(!string_mapped && e_base_ctx->dbgi_match_store != 0 && (qualifier.size == 0 || str8_match(qualifier, str8_lit("symbol"), 0))) + if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("symbol"), 0))) { - DI_Match match = di_match_from_name(e_base_ctx->dbgi_match_store, string, 0); + Access *access = access_open(); + + // rjf: find match + DI2_Match match = di2_match_from_string(string, 0, 0); if(match.idx == 0) { String8List namespaceified_strings = {0}; @@ -1897,18 +1900,34 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } for(String8Node *n = namespaceified_strings.first; n != 0; n = n->next) { - match = di_match_from_name(e_base_ctx->dbgi_match_store, n->string, 0); + match = di2_match_from_string(n->string, 0, 0); if(match.idx != 0) { break; } } } - if(match.idx != 0 && match.dbgi_idx < e_base_ctx->modules_count) + + // rjf: match -> RDI + RDI_Parsed *rdi = di2_rdi_from_key(access, match.key, 0, 0); + + // rjf: find module from dbgi key + U32 dbgi_idx = 0; + E_Module *module = &e_module_nil; + for EachIndex(idx, e_base_ctx->modules_count) { - E_Module *module = &e_base_ctx->modules[match.dbgi_idx]; - RDI_Parsed *rdi = module->rdi; - switch(match.section) + if(e_base_ctx->modules[idx].rdi == rdi) + { + module = &e_base_ctx->modules[idx]; + dbgi_idx = (U32)idx; + break; + } + } + + // rjf: form result + if(match.idx != 0 && module != &e_module_nil) + { + switch(match.section_kind) { default:{}break; case RDI_SectionKind_GlobalVariables: @@ -1919,7 +1938,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_OpList oplist = {0}; e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + global_var->voff)); string_mapped = 1; - mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx); mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Offset; mapped_bytecode_space = module->space; @@ -1932,7 +1951,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_OpList oplist = {0}; e_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, e_value_u64(thread_var->tls_off)); string_mapped = 1; - mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx); mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Offset; mapped_bytecode_space = module->space; @@ -1955,7 +1974,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_OpList oplist = {0}; e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(value)); string_mapped = 1; - mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx); mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Value; mapped_bytecode_space = module->space; @@ -1973,7 +1992,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_OpList oplist = {0}; e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff)); string_mapped = 1; - mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx); mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Value; mapped_bytecode_space = module->space; @@ -1982,11 +2001,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I { U32 type_idx = match.idx; RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); - mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx); string_mapped = 1; }break; } } + access_close(access); } }break; diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index 7e87d294..9feaad41 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -585,14 +585,23 @@ e_leaf_type_key_from_name(String8 name) E_TypeKey key = e_leaf_builtin_type_key_from_name(name); if(!e_type_key_match(e_type_key_zero(), key)) { - DI_Match match = di_match_from_name(e_base_ctx->dbgi_match_store, name, 0); - if(match.section == RDI_SectionKind_TypeNodes) + DI2_Match match = di2_match_from_string(name, 0, 0); + if(match.section_kind == RDI_SectionKind_TypeNodes) { - E_Module *module = &e_base_ctx->modules[match.dbgi_idx]; - RDI_Parsed *rdi = module->rdi; - U32 type_idx = match.idx; - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); - key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx); + Access *access = access_open(); + RDI_Parsed *rdi = di2_rdi_from_key(access, match.key, 0, 0); + for EachIndex(idx, e_base_ctx->modules_count) + { + E_Module *module = &e_base_ctx->modules[idx]; + if(module->rdi == rdi) + { + U32 type_idx = match.idx; + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); + key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)idx); + break; + } + } + access_close(access); } } return key; diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 140275af..199f0699 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -520,7 +520,7 @@ Rng1U64 rd_reg_slot_range_table[47] = {OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(C_Key)}, {OffsetOf(RD_Regs, lang_kind), OffsetOf(RD_Regs, lang_kind) + sizeof(TXT_LangKind)}, {OffsetOf(RD_Regs, lines), OffsetOf(RD_Regs, lines) + sizeof(D_LineList)}, -{OffsetOf(RD_Regs, dbgi_key), OffsetOf(RD_Regs, dbgi_key) + sizeof(DI_Key)}, +{OffsetOf(RD_Regs, dbgi_key), OffsetOf(RD_Regs, dbgi_key) + sizeof(DI2_Key)}, {OffsetOf(RD_Regs, vaddr), OffsetOf(RD_Regs, vaddr) + sizeof(U64)}, {OffsetOf(RD_Regs, voff), OffsetOf(RD_Regs, voff) + sizeof(U64)}, {OffsetOf(RD_Regs, vaddr_range), OffsetOf(RD_Regs, vaddr_range) + sizeof(Rng1U64)}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index 14e419f0..fd98a78b 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -466,7 +466,7 @@ TxtPt mark; C_Key text_key; TXT_LangKind lang_kind; D_LineList lines; -DI_Key dbgi_key; +DI2_Key dbgi_key; U64 vaddr; U64 voff; Rng1U64 vaddr_range; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index b1175fde..f340f64c 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -733,10 +733,10 @@ RD_RegTable: {String8 file_path FilePath } {TxtPt cursor Cursor } {TxtPt mark Mark } - {C_Key text_key TextKey } + {C_Key text_key TextKey } {TXT_LangKind lang_kind LangKind } {D_LineList lines Lines } - {DI_Key dbgi_key DbgiKey } + {DI2_Key dbgi_key DbgiKey } {U64 vaddr Vaddr } {U64 voff Voff } {Rng1U64 vaddr_range VaddrRange } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index e59dc2e3..911a7134 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -42,7 +42,6 @@ rd_regs_copy_contents(Arena *arena, RD_Regs *dst, RD_Regs *src) dst->cfg_list = rd_cfg_id_list_copy(arena, &src->cfg_list); dst->file_path = push_str8_copy(arena, src->file_path); dst->lines = d_line_list_copy(arena, &src->lines); - dst->dbgi_key = di_key_copy(arena, &src->dbgi_key); dst->expr = push_str8_copy(arena, src->expr); dst->string = push_str8_copy(arena, src->string); dst->cmd_name = push_str8_copy(arena, src->cmd_name); @@ -3274,11 +3273,11 @@ rd_view_ui(Rng2F32 rect) U64 vaddr = eval.value.u64; CTRL_Entity *process = rd_ctrl_entity_from_eval_space(eval.space); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 voff = ctrl_voff_from_vaddr(module, vaddr); { - DI_Scope *scope = di_scope_open(); - RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0); + Access *access = access_open(); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); String8 name = {0}; if(name.size == 0) { @@ -3294,7 +3293,7 @@ rd_view_ui(Rng2F32 rect) { rd_cmd(RD_CmdKind_CompleteQuery, .string = name); } - di_scope_close(scope); + access_close(access); } }break; case E_SpaceKind_File: @@ -3361,11 +3360,11 @@ rd_view_ui(Rng2F32 rect) U64 vaddr = eval.value.u64; CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 voff = ctrl_voff_from_vaddr(module, vaddr); { - DI_Scope *scope = di_scope_open(); - RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0); + Access *access = access_open(); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, 0); if(name.size == 0) { RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); @@ -3376,7 +3375,7 @@ rd_view_ui(Rng2F32 rect) RDI_GlobalVariable *gvar = rdi_global_variable_from_voff(rdi, voff); name.str = rdi_string_from_idx(rdi, gvar->name_string_idx, &name.size); } - di_scope_close(scope); + access_close(access); } } if(name.size != 0) @@ -5299,9 +5298,9 @@ rd_view_ui(Rng2F32 rect) { U64 vaddr = cell->eval.value.u64; CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 voff = ctrl_voff_from_vaddr(module, vaddr); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, voff); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, voff); String8 file_path = {0}; TxtPt pt = {0}; if(lines.first != 0) @@ -6443,22 +6442,23 @@ rd_window_frame(void) // rjf: debug info status if(ctrl_entity->kind == CTRL_EntityKind_Module) UI_TagF("weak") { - DI_Scope *di_scope = di_scope_open(); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(ctrl_entity); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0); + Access *access = access_open(); + CTRL_Entity *dbg_info_entity = ctrl_entity_child_from_kind(ctrl_entity, CTRL_EntityKind_DebugInfoPath); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(ctrl_entity); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); if(rdi->raw_data_size != 0) { - ui_labelf("Symbols successfully loaded from %S", dbgi_key.path); + ui_labelf("Symbols successfully loaded from %S", dbg_info_entity->string); } - else if(dbgi_key.path.size != 0) + else if(dbg_info_entity->string.size != 0) { - ui_labelf("Symbols not found at %S", dbgi_key.path); + ui_labelf("Symbols not found at %S", dbg_info_entity->string); } - else if(dbgi_key.path.size == 0) + else if(dbg_info_entity->string.size == 0) { ui_labelf("Symbol information not found in module file"); } - di_scope_close(di_scope); + access_close(access); } // rjf: unwind @@ -6611,11 +6611,6 @@ rd_window_frame(void) ui_divider(ui_em(1.f, 1.f)); - //- rjf: draw match store stats - ui_labelf("name match nodes: %I64u", rd_state->match_store->active_match_name_nodes_count); - - ui_divider(ui_em(1.f, 1.f)); - //- rjf: draw registers ui_labelf("hover_reg_slot: %i", rd_state->hover_regs_slot); struct @@ -10267,8 +10262,6 @@ rd_code_color_slot_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 RD_CodeColorSlot color = RD_CodeColorSlot_CodeDefault; if(kind == TXT_TokenKind_Identifier || kind == TXT_TokenKind_Keyword) { - CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); B32 mapped = 0; // rjf: try to map as local @@ -10318,7 +10311,8 @@ rd_code_color_slot_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 // rjf: try to map using asynchronous matching system if(!mapped && kind == TXT_TokenKind_Identifier) { - RDI_SectionKind section_kind = di_match_from_name(rd_state->match_store, string, 0).section; + DI2_Match match = di2_match_from_string(string, 0, 0); + RDI_SectionKind section_kind = match.section_kind; mapped = 1; switch(section_kind) { @@ -10885,7 +10879,6 @@ rd_init(CmdLine *cmdln) } rd_state->num_frames_requested = 2; rd_state->seconds_until_autosave = 0.5f; - rd_state->match_store = di_match_store_alloc(); rd_state->eval_cache = e_cache_alloc(); for(U64 idx = 0; idx < ArrayCount(rd_state->cmds_arenas); idx += 1) { @@ -11406,6 +11399,7 @@ rd_frame(void) ////////////////////////////// //- rjf: sync with di parsers // +#if 0 // TODO(rjf): @dbgi2 ProfScope("sync with di parsers") { DI_EventList events = di_p2u_pop_events(scratch.arena, 0); @@ -11436,6 +11430,7 @@ rd_frame(void) } } } +#endif ////////////////////////////// //- rjf: animate all views @@ -11496,9 +11491,7 @@ rd_frame(void) //- rjf: push frame scopes // Access *frame_access_restore = rd_state->frame_access; - DI_Scope *frame_di_scope_restore = rd_state->frame_di_scope; rd_state->frame_access = access_open(); - rd_state->frame_di_scope = di_scope_open(); rd_state->got_frame_call_stack_tree = 0; ////////////////////////////// @@ -11854,15 +11847,6 @@ rd_frame(void) } } - ////////////////////////////// - //- rjf: set name matching parameters; begin matching - // - { - DI_KeyList keys_list = d_push_active_dbgi_key_list(scratch.arena); - DI_KeyArray keys = di_key_array_from_list(scratch.arena, &keys_list); - di_match_store_begin(rd_state->match_store, keys); - } - ////////////////////////////// //- rjf: loop - consume events in core, tick engine, and repeat // @@ -11888,15 +11872,15 @@ rd_frame(void) E_Module *eval_modules_primary = &eval_modules[0]; eval_modules_primary->rdi = &rdi_parsed_nil; eval_modules_primary->vaddr_range = r1u64(0, max_U64); - DI_Key primary_dbgi_key = {0}; + DI2_Key primary_dbgi_key = {0}; ProfScope("produce all eval modules") { for EachIndex(eval_module_idx, all_modules.count) { CTRL_Entity *m = all_modules.v[eval_module_idx]; - DI_Key dbgi_key = ctrl_dbgi_key_from_module(m); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(m); eval_modules[eval_module_idx].arch = m->arch; - eval_modules[eval_module_idx].rdi = di_rdi_from_key(rd_state->frame_di_scope, &dbgi_key, 1, 0); + eval_modules[eval_module_idx].rdi = di2_rdi_from_key(rd_state->frame_access, dbgi_key, 0, 0); eval_modules[eval_module_idx].vaddr_range = m->vaddr_range; eval_modules[eval_module_idx].space = rd_eval_space_from_ctrl_entity(ctrl_entity_ancestor_from_kind(m, CTRL_EntityKind_Process), RD_EvalSpaceKind_CtrlEntity); if(module == m) @@ -11931,7 +11915,6 @@ rd_frame(void) ctx->modules = eval_modules; ctx->modules_count = eval_modules_count; ctx->primary_module = eval_modules_primary; - ctx->dbgi_match_store = rd_state->match_store; //- rjf: fill space hooks ctx->space_gen = rd_eval_space_gen; @@ -12702,8 +12685,8 @@ rd_frame(void) E_IRCtx *ctx = ir_ctx; ctx->regs_map = ctrl_string2reg_from_arch(eval_base_ctx->primary_module->arch); ctx->reg_alias_map = ctrl_string2alias_from_arch(eval_base_ctx->primary_module->arch); - ctx->locals_map = d_query_cached_locals_map_from_dbgi_key_voff(&primary_dbgi_key, rip_voff); - ctx->member_map = d_query_cached_member_map_from_dbgi_key_voff(&primary_dbgi_key, rip_voff); + ctx->locals_map = d_query_cached_locals_map_from_dbgi_key_voff(primary_dbgi_key, rip_voff); + ctx->member_map = d_query_cached_member_map_from_dbgi_key_voff(primary_dbgi_key, rip_voff); ctx->macro_map = macro_map; ctx->auto_hook_map = auto_hook_map; } @@ -14405,7 +14388,7 @@ rd_frame(void) U64 vaddr = 0; for(D_LineNode *n = rd_regs()->lines.first; n != 0; n = n->next) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, n->v.dbgi_key); CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules); if(module != &ctrl_entity_nil) { @@ -14686,7 +14669,7 @@ rd_frame(void) //- rjf: thread finding case RD_CmdKind_FindThread: { - DI_Scope *scope = di_scope_open(); + Access *access = access_open(); //- rjf: unpack thread info CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); @@ -14695,10 +14678,10 @@ rd_frame(void) U64 rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_index); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, rip_voff); D_Line line = {0}; { U64 idx = 0; @@ -14712,7 +14695,7 @@ rd_frame(void) } } B32 missing_rip = (rip_vaddr == 0); - B32 dbgi_missing = (dbgi_key.min_timestamp == 0 || dbgi_key.path.size == 0); + B32 dbgi_missing = (di2_key_match(di2_key_zero(), dbgi_key)); B32 dbgi_pending = !dbgi_missing && rdi == &rdi_parsed_nil; B32 has_line_info = (line.voff_range.max != 0); B32 has_module = (module != &ctrl_entity_nil); @@ -14749,7 +14732,7 @@ rd_frame(void) { find_thread_retry = thread->handle; } - di_scope_close(scope); + access_close(access); }break; case RD_CmdKind_FindSelectedThread: { @@ -14776,20 +14759,21 @@ rd_frame(void) // rjf: try to resolve name as a symbol U64 voff = 0; - DI_Key voff_dbgi_key = {0}; + DI2_Key voff_dbgi_key = {0}; if(!name_resolved) { - DI_KeyList keys = d_push_active_dbgi_key_list(scratch.arena); - for(DI_KeyNode *n = keys.first; n != 0; n = n->next) + DI2_Match match = di2_match_from_string(name, 0, 0); + if(match.section_kind == RDI_SectionKind_Procedures) { - U64 binary_voff = d_voff_from_dbgi_key_symbol_name(&n->v, name); - if(binary_voff != 0) + Access *access = access_open(); { - voff = binary_voff; - voff_dbgi_key = n->v; name_resolved = 1; - break; + RDI_Parsed *rdi = di2_rdi_from_key(access, match.key, 0, 0); + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, match.idx); + voff = rdi_first_voff_from_procedure(rdi, procedure); + voff_dbgi_key = match.key; } + access_close(access); } } @@ -14848,20 +14832,17 @@ rd_frame(void) // rjf: name resolved to voff * dbg info if(name_resolved && voff != 0) { - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &voff_dbgi_key, voff); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, voff_dbgi_key, voff); if(lines.first != 0) { CTRL_Entity *process = &ctrl_entity_nil; U64 vaddr = 0; - if(voff_dbgi_key.path.size != 0) + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, voff_dbgi_key); + CTRL_Entity *module = ctrl_entity_list_first(&modules); + process = ctrl_entity_ancestor_from_kind(module, CTRL_EntityKind_Process); + if(process != &ctrl_entity_nil) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &voff_dbgi_key); - CTRL_Entity *module = ctrl_entity_list_first(&modules); - process = ctrl_entity_ancestor_from_kind(module, CTRL_EntityKind_Process); - if(process != &ctrl_entity_nil) - { - vaddr = module->vaddr_range.min + lines.first->v.voff_range.min; - } + vaddr = module->vaddr_range.min + lines.first->v.voff_range.min; } rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = lines.first->v.file_path, @@ -14951,7 +14932,7 @@ rd_frame(void) D_LineList lines = d_lines_from_file_path_line_num(scratch.arena, file_path, point.line); for(D_LineNode *n = lines.first; n != 0; n = n->next) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, n->v.dbgi_key); CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules); vaddr = ctrl_vaddr_from_voff(module, n->v.voff_range.min); break; @@ -16126,7 +16107,7 @@ rd_frame(void) D_LineList *lines = &rd_regs()->lines; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, n->v.dbgi_key); CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules); if(module != &ctrl_entity_nil) { @@ -17015,7 +16996,6 @@ rd_frame(void) U64 vaddr = evt->vaddr; CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 voff = ctrl_voff_from_vaddr(module, vaddr); U64 test_cached_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); @@ -17325,9 +17305,7 @@ rd_frame(void) // since eviction threads may be waiting to get rid of stuff. // access_close(rd_state->frame_access); - di_scope_close(rd_state->frame_di_scope); rd_state->frame_access = frame_access_restore; - rd_state->frame_di_scope = frame_di_scope_restore; ////////////////////////////// //- rjf: submit rendering to all windows diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index c58aff29..ad58381e 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -600,13 +600,9 @@ struct RD_State // rjf: frame parameters F32 frame_dt; Access *frame_access; - DI_Scope *frame_di_scope; CTRL_CallStackTree frame_call_stack_tree; B32 got_frame_call_stack_tree; - // rjf: dbgi match store - DI_MatchStore *match_store; - // rjf: evaluation cache E_Cache *eval_cache; diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 7b4f8088..698d5675 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1634,9 +1634,7 @@ typedef struct RD_DebugInfoTableLookupAccel RD_DebugInfoTableLookupAccel; struct RD_DebugInfoTableLookupAccel { RDI_SectionKind section; - U64 rdis_count; - RDI_Parsed **rdis; - DI_SearchItemArray items; + DI2_SearchItemArray items; }; E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) @@ -1663,28 +1661,10 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) { U64 endt_us = rd_state->frame_eval_memread_endt_us; - //- rjf: unpack context - DI_KeyList dbgi_keys_list = d_push_active_dbgi_key_list(scratch.arena); - DI_KeyArray dbgi_keys = di_key_array_from_list(scratch.arena, &dbgi_keys_list); - U64 rdis_count = dbgi_keys.count; - RDI_Parsed **rdis = push_array(arena, RDI_Parsed *, rdis_count); - for(U64 idx = 0; idx < rdis_count; idx += 1) - { - rdis[idx] = di_rdi_from_key(rd_state->frame_di_scope, &dbgi_keys.v[idx], 1, endt_us); - } - //- rjf: query all filtered items from dbgi searching system U128 fuzzy_search_key = {d_hash_from_string(str8_struct(&rd_regs()->view)), (U64)section}; - B32 items_stale = 0; - DI_SearchParams params = {section, dbgi_keys}; accel->section = section; - accel->rdis_count = rdis_count; - accel->rdis = rdis; - accel->items = di_search_items_from_key_params_query(rd_state->frame_di_scope, fuzzy_search_key, ¶ms, filter, endt_us, &items_stale); - if(items_stale) - { - rd_request_frame(); - } + accel->items = di2_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us); } E_TypeExpandInfo info = {accel, accel->items.count}; scratch_end(scratch); @@ -1698,18 +1678,11 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table) U64 needed_row_count = dim_1u64(idx_range); for EachIndex(idx, needed_row_count) { + Access *access = access_open(); + // rjf: unpack row - DI_SearchItem *item = &accel->items.v[idx_range.min + idx]; - - // rjf: skip bad elements - if(item->dbgi_idx >= accel->rdis_count) - { - continue; - } - - // rjf: unpack row info - RDI_Parsed *rdi = accel->rdis[item->dbgi_idx]; - E_Module *module = &e_base_ctx->modules[item->dbgi_idx]; + DI2_SearchItem *item = &accel->items.v[idx_range.min + idx]; + RDI_Parsed *rdi = di2_rdi_from_key(access, item->key, 0, 0); // rjf: get item's string String8 item_string = {0}; @@ -1721,51 +1694,43 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table) default:{}break; case RDI_SectionKind_Procedures: { - RDI_Procedure *procedure = rdi_element_from_name_idx(module->rdi, Procedures, element_idx); - RDI_Scope *scope = rdi_element_from_name_idx(module->rdi, Scopes, procedure->root_scope_idx); - U64 voff = *rdi_element_from_name_idx(module->rdi, ScopeVOffData, scope->voff_range_first); - E_OpList oplist = {0}; - e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff)); - String8 bytecode = e_bytecode_from_oplist(arena, &oplist); - U32 type_idx = procedure->type_idx; - RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, type_idx); - E_TypeKey type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)(module - e_base_ctx->modules)); + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, element_idx); String8 symbol_name = {0}; - symbol_name.str = rdi_string_from_idx(module->rdi, procedure->name_string_idx, &symbol_name.size); + symbol_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &symbol_name.size); item_string = symbol_name; }break; case RDI_SectionKind_GlobalVariables: { - RDI_GlobalVariable *gvar = rdi_element_from_name_idx(module->rdi, GlobalVariables, element_idx); + RDI_GlobalVariable *gvar = rdi_element_from_name_idx(rdi, GlobalVariables, element_idx); String8 symbol_name = {0}; - symbol_name.str = rdi_string_from_idx(module->rdi, gvar->name_string_idx, &symbol_name.size); + symbol_name.str = rdi_string_from_idx(rdi, gvar->name_string_idx, &symbol_name.size); item_string = symbol_name; }break; case RDI_SectionKind_ThreadVariables: { - RDI_ThreadVariable *tvar = rdi_element_from_name_idx(module->rdi, ThreadVariables, element_idx); + RDI_ThreadVariable *tvar = rdi_element_from_name_idx(rdi, ThreadVariables, element_idx); String8 symbol_name = {0}; - symbol_name.str = rdi_string_from_idx(module->rdi, tvar->name_string_idx, &symbol_name.size); + symbol_name.str = rdi_string_from_idx(rdi, tvar->name_string_idx, &symbol_name.size); item_string = symbol_name; }break; case RDI_SectionKind_Constants: { - RDI_Constant *cnst = rdi_element_from_name_idx(module->rdi, Constants, element_idx); + RDI_Constant *cnst = rdi_element_from_name_idx(rdi, Constants, element_idx); String8 symbol_name = {0}; - symbol_name.str = rdi_string_from_idx(module->rdi, cnst->name_string_idx, &symbol_name.size); + symbol_name.str = rdi_string_from_idx(rdi, cnst->name_string_idx, &symbol_name.size); item_string = symbol_name; }break; case RDI_SectionKind_UDTs: { - RDI_UDT *udt = rdi_element_from_name_idx(module->rdi, UDTs, element_idx); - RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, udt->self_type_idx); + RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, element_idx); + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); String8 name = {0}; - name.str = rdi_string_from_idx(module->rdi, type_node->user_defined.name_string_idx, &name.size); + name.str = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name.size); item_string = name; }break; case RDI_SectionKind_SourceFiles: { - RDI_SourceFile *sf = rdi_element_from_name_idx(module->rdi, SourceFiles, element_idx); + RDI_SourceFile *sf = rdi_element_from_name_idx(rdi, SourceFiles, element_idx); String8List path_parts = {0}; for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, sf->file_path_node_idx); fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0); @@ -1815,6 +1780,8 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table) // rjf: fill evals_out[idx] = item_eval; temp_end(scratch); + + access_close(access); } scratch_end(scratch); } @@ -1825,7 +1792,10 @@ E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(debug_info_table) U64 id = 0; if(0 < num && num <= accel->items.count) { - id = accel->items.v[num-1].idx+1; + U64 hash = 5381; + hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].key.u64[0])); + hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].key.u64[1])); + hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].idx)); } return id; } @@ -1833,6 +1803,18 @@ E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(debug_info_table) E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(debug_info_table) { RD_DebugInfoTableLookupAccel *accel = (RD_DebugInfoTableLookupAccel *)user_data; - U64 num = di_search_item_num_from_array_element_idx__linear_search(&accel->items, id-1); + U64 num = 0; + for EachIndex(idx, accel->items.count) + { + U64 hash = 5381; + hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[idx].key.u64[0])); + hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[idx].key.u64[1])); + hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[idx].idx)); + if(hash == id) + { + num = idx+1; + break; + } + } return num; } diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 4d7a2865..27745928 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -248,7 +248,7 @@ #include "radbin/radbin.h" #include "regs/regs.h" #include "regs/rdi/regs_rdi.h" -#include "dbg_info/dbg_info.h" +// #include "dbg_info/dbg_info.h" #include "dbg_info/dbg_info2.h" #include "disasm/disasm.h" #include "demon/demon_inc.h" @@ -296,7 +296,7 @@ #include "radbin/radbin.c" #include "regs/regs.c" #include "regs/rdi/regs_rdi.c" -#include "dbg_info/dbg_info.c" +// #include "dbg_info/dbg_info.c" #include "dbg_info/dbg_info2.c" #include "disasm/disasm.c" #include "demon/demon_inc.c" diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 19d175b0..2054e97e 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -20,7 +20,7 @@ rd_code_view_init(RD_CodeViewState *cv) } internal RD_CodeViewBuildResult -rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags flags, Rng2F32 rect, String8 text_data, TXT_TextInfo *text_info, DASM_LineArray *dasm_lines, Rng1U64 dasm_vaddr_range, DI_Key dasm_dbgi_key) +rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags flags, Rng2F32 rect, String8 text_data, TXT_TextInfo *text_info, DASM_LineArray *dasm_lines, Rng1U64 dasm_vaddr_range, DI2_Key dasm_dbgi_key) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -289,8 +289,8 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla U64 last_inst_on_unwound_rip_vaddr = rip_vaddr - !!unwind_count; CTRL_Entity *module = ctrl_module_from_process_vaddr(process, last_inst_on_unwound_rip_vaddr); U64 rip_voff = ctrl_voff_from_vaddr(module, last_inst_on_unwound_rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, rip_voff); for(D_LineNode *n = lines.first; n != 0; n = n->next) { if(visible_line_num_range.min <= n->v.pt.line && n->v.pt.line <= visible_line_num_range.max) @@ -341,7 +341,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla { String8 file_path = rd_regs()->file_path; CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); D_LineListArray lines_array = d_lines_array_from_dbgi_key_file_path_line_range(scratch.arena, dbgi_key, file_path, visible_line_num_range); if(lines_array.count != 0) { @@ -423,21 +423,21 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla if(dasm_lines) { CTRL_Entity *module = ctrl_module_from_process_vaddr(process, dasm_vaddr_range.min); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) { U64 vaddr = dasm_vaddr_range.min + dasm_line_array_code_off_from_idx(dasm_lines, line_num-1); U64 voff = ctrl_voff_from_vaddr(module, vaddr); U64 slice_idx = line_num-visible_line_num_range.min; code_slice_params.line_vaddrs[slice_idx] = vaddr; - code_slice_params.line_infos[slice_idx] = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, voff); + code_slice_params.line_infos[slice_idx] = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, voff); } } // rjf: add dasm dbgi key to relevant dbgis if(dasm_lines != 0) { - di_key_list_push(scratch.arena, &code_slice_params.relevant_dbgi_keys, &dasm_dbgi_key); + di2_key_list_push(scratch.arena, &code_slice_params.relevant_dbgi_keys, dasm_dbgi_key); } } @@ -813,10 +813,9 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // RD_CodeViewBuildResult result = {0}; { - for(DI_KeyNode *n = code_slice_params.relevant_dbgi_keys.first; n != 0; n = n->next) + for(DI2_KeyNode *n = code_slice_params.relevant_dbgi_keys.first; n != 0; n = n->next) { - DI_Key copy = di_key_copy(arena, &n->v); - di_key_list_push(arena, &result.dbgi_keys, ©); + di2_key_list_push(arena, &result.dbgi_keys, n->v); } } @@ -2148,7 +2147,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) ////////////////////////////// //- rjf: build code contents // - DI_KeyList dbgi_keys = {0}; + DI2_KeyList dbgi_keys = {0}; if(!file_is_missing) { RD_CodeViewBuildFlags flags = RD_CodeViewBuildFlag_All; @@ -2156,7 +2155,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) { flags &= ~RD_CodeViewBuildFlag_Margins; } - RD_CodeViewBuildResult result = rd_code_view_build(scratch.arena, cv, flags, code_area_rect, data, &info, 0, r1u64(0, 0), di_key_zero()); + RD_CodeViewBuildResult result = rd_code_view_build(scratch.arena, cv, flags, code_area_rect, data, &info, 0, r1u64(0, 0), di2_key_zero()); dbgi_keys = result.dbgi_keys; } @@ -2166,7 +2165,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) if(rd_regs()->file_path.size != 0) { CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); rd_regs()->lines = d_lines_from_dbgi_key_file_path_line_num(rd_frame_arena(), dbgi_key, rd_regs()->file_path, rd_regs()->cursor.line); } @@ -2179,15 +2178,18 @@ RD_VIEW_UI_FUNCTION_DEF(text) U64 file_timestamp = os_properties_from_file_path(rd_regs()->file_path).modified; if(file_timestamp != 0) { - for(DI_KeyNode *n = dbgi_keys.first; n != 0; n = n->next) + for(DI2_KeyNode *n = dbgi_keys.first; n != 0; n = n->next) { - DI_Key key = n->v; + DI2_Key key = n->v; + // TODO(rjf): @dbgi2 +#if 0 if(key.min_timestamp < file_timestamp && key.min_timestamp != 0 && key.path.size != 0) { file_is_out_of_date = 1; out_of_date_dbgi_name = str8_skip_last_slash(key.path); break; } +#endif } } } @@ -2356,7 +2358,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) Arch arch = rd_arch_from_eval(eval); CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(space); CTRL_Entity *dasm_module = &ctrl_entity_nil; - DI_Key dbgi_key = {0}; + DI2_Key dbgi_key = {0}; U64 base_vaddr = 0; switch(space_entity->kind) { @@ -2455,7 +2457,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) rd_regs()->vaddr = range.min+off; rd_regs()->vaddr_range = r1u64(range.min+off, range.min+off); rd_regs()->voff_range = ctrl_voff_range_from_vaddr_range(dasm_module, rd_regs()->vaddr_range); - rd_regs()->lines = d_lines_from_dbgi_key_voff(rd_frame_arena(), &dbgi_key, rd_regs()->voff_range.min); + rd_regs()->lines = d_lines_from_dbgi_key_voff(rd_frame_arena(), dbgi_key, rd_regs()->voff_range.min); } ////////////////////////////// @@ -2952,16 +2954,16 @@ RD_VIEW_UI_FUNCTION_DEF(memory) last_stack_top = f_stack_top; if(dim_1u64(frame_vaddr_range_in_viz) != 0) { - DI_Scope *scope = di_scope_open(); + Access *access = access_open(); U64 f_rip_vaddr = regs_rip_from_arch_block(selected_thread->arch, f->regs); CTRL_Entity *module = ctrl_module_from_process_vaddr(selected_process, f_rip_vaddr); U64 f_rip_voff = ctrl_voff_from_vaddr(module, f_rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, f_rip_voff); String8 procedure_name = {0}; procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size); - di_scope_close(scope); + access_close(access); if(procedure_name.size != 0) { Annotation *annotation = push_array(scratch.arena, Annotation, 1); @@ -3008,7 +3010,6 @@ RD_VIEW_UI_FUNCTION_DEF(memory) //- rjf: fill local variable annotations if(e_space_match(rd_eval_space_from_ctrl_entity(selected_process, RD_EvalSpaceKind_CtrlEntity), eval.space)) { - DI_Scope *scope = di_scope_open(); Vec4F32 local_color = ui_color_from_name(str8_lit("code_local")); Vec4F32 color_gen_table[] = { @@ -3047,7 +3048,6 @@ RD_VIEW_UI_FUNCTION_DEF(memory) } } } - di_scope_close(scope); } //- rjf: fill procedures annotations @@ -3066,13 +3066,13 @@ RD_VIEW_UI_FUNCTION_DEF(memory) vaddr = next_vaddr) { next_vaddr = vaddr+1; - DI_Scope *scope = di_scope_open(); + Access *access = access_open(); CTRL_Entity *module = ctrl_module_from_process_vaddr(eval_process, vaddr); if(module != &ctrl_entity_nil) { U64 voff = ctrl_voff_from_vaddr(module, vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); RDI_Scope *root_scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx); if(procedure->root_scope_idx != 0) @@ -3103,7 +3103,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) } } } - di_scope_close(scope); + access_close(access); } } @@ -3123,13 +3123,13 @@ RD_VIEW_UI_FUNCTION_DEF(memory) vaddr = next_vaddr) { next_vaddr = vaddr+1; - DI_Scope *scope = di_scope_open(); + Access *access = access_open(); CTRL_Entity *module = ctrl_module_from_process_vaddr(eval_process, vaddr); if(module != &ctrl_entity_nil) { U64 voff = ctrl_voff_from_vaddr(module, vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); RDI_GlobalVariable *gvar = rdi_global_variable_from_voff(rdi, voff); if(gvar->voff != 0) { @@ -3159,7 +3159,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) } } } - di_scope_close(scope); + access_close(access); } } diff --git a/src/raddbg/raddbg_views.h b/src/raddbg/raddbg_views.h index f13b2ecc..9ac7da52 100644 --- a/src/raddbg/raddbg_views.h +++ b/src/raddbg/raddbg_views.h @@ -67,7 +67,7 @@ struct RD_CodeViewState typedef struct RD_CodeViewBuildResult RD_CodeViewBuildResult; struct RD_CodeViewBuildResult { - DI_KeyList dbgi_keys; + DI2_KeyList dbgi_keys; }; //////////////////////////////// @@ -199,7 +199,7 @@ struct RD_WatchViewState //~ rjf: Code View Functions internal void rd_code_view_init(RD_CodeViewState *cv); -internal RD_CodeViewBuildResult rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags flags, Rng2F32 rect, String8 text_data, TXT_TextInfo *text_info, DASM_LineArray *dasm_lines, Rng1U64 dasm_vaddr_range, DI_Key dasm_dbgi_key); +internal RD_CodeViewBuildResult rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags flags, Rng2F32 rect, String8 text_data, TXT_TextInfo *text_info, DASM_LineArray *dasm_lines, Rng1U64 dasm_vaddr_range, DI2_Key dasm_dbgi_key); //////////////////////////////// //~ rjf: Watch View Functions diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 77cde640..ac5d94cf 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -548,7 +548,6 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); Access *access = access_open(); - DI_Scope *di_scope = di_scope_open(); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); Arch arch = entity->arch; B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); @@ -564,8 +563,8 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); String8 name = {0}; { - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); if(rdi != &rdi_parsed_nil) { RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, rip_voff); @@ -591,22 +590,21 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e } } } - di_scope_close(di_scope); access_close(access); } //- rjf: modules get debug info status extras if(entity->kind == CTRL_EntityKind_Module && include_extras) { - DI_Scope *di_scope = di_scope_open(); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(entity); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0); + Access *access = access_open(); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(entity); + RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); if(rdi->raw_data_size == 0) { dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Symbols not found)"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .size = extras_size, .color = secondary_color); } - di_scope_close(di_scope); + access_close(access); } return result; @@ -1419,7 +1417,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe U64 thread_rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, thread_rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color @@ -1490,7 +1488,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe D_Line *line = 0; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - if(di_key_match(&n->v.dbgi_key, &dbgi_key)) + if(di2_key_match(n->v.dbgi_key, dbgi_key)) { line = &n->v; break; @@ -1575,7 +1573,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe U64 thread_rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, thread_rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color @@ -1644,7 +1642,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe D_Line *line = 0; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - if(di_key_match(&n->v.dbgi_key, &dbgi_key)) + if(di2_key_match(n->v.dbgi_key, dbgi_key)) { line = &n->v; break; @@ -1867,19 +1865,14 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // rjf: line info on this line -> adjust bg color to visualize B32 has_line_info = 0; { - U64 best_stamp = 0; S64 line_info_line_num = 0; F32 line_info_t = 0; D_LineList *lines = ¶ms->line_infos[line_idx]; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - if(n->v.dbgi_key.min_timestamp >= best_stamp) - { - has_line_info = (n->v.pt.line == line_num || params->line_vaddrs[line_idx] != 0); - line_info_line_num = n->v.pt.line; - best_stamp = n->v.dbgi_key.min_timestamp; - line_info_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "dbgi_alive_t_%S", n->v.dbgi_key.path), 1.f); - } + has_line_info = (has_line_info || n->v.pt.line == line_num || params->line_vaddrs[line_idx] != 0); + line_info_line_num = n->v.pt.line; + line_info_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "dbgi_alive_t_%I64x_%I64x", n->v.dbgi_key.u64[0], n->v.dbgi_key.u64[1]), 1.f); } if(has_line_info) { @@ -2019,7 +2012,6 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // UI_Focus(UI_FocusKind_Off) { - DI_Scope *scope = di_scope_open(); U64 line_idx = 0; for(S64 line_num = params->line_num_range.min; line_num < params->line_num_range.max; @@ -2152,7 +2144,6 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } } } - di_scope_close(scope); } ////////////////////////////// @@ -2275,7 +2266,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe D_LineList *lines = ¶ms->line_infos[line_idx]; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, n->v.dbgi_key); CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules); if(module != &ctrl_entity_nil) { @@ -2805,7 +2796,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe for(D_LineNode *n = lines->first; n != 0; n = n->next) { if((n->v.pt.line == line_num || params->line_vaddrs[line_idx] != 0) && - ((di_key_match(&n->v.dbgi_key, &hover_regs->dbgi_key) && + ((di2_key_match(n->v.dbgi_key, hover_regs->dbgi_key) && n->v.voff_range.min <= hover_voff_range.min && hover_voff_range.min < n->v.voff_range.max) || (params->line_vaddrs[line_idx] == hover_regs->vaddr_range.min && hover_regs->vaddr_range.min != 0))) { diff --git a/src/raddbg/raddbg_widgets.h b/src/raddbg/raddbg_widgets.h index 88678f99..ce426e18 100644 --- a/src/raddbg/raddbg_widgets.h +++ b/src/raddbg/raddbg_widgets.h @@ -104,7 +104,7 @@ struct RD_CodeSliceParams RD_CfgList *line_pins; U64 *line_vaddrs; D_LineList *line_infos; - DI_KeyList relevant_dbgi_keys; + DI2_KeyList relevant_dbgi_keys; TXT_TextInfo *text_info; String8 text_data; From 5b00aaadafbe9a94c3a0967ba25ecf1cce692c14 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 14:18:11 -0700 Subject: [PATCH 006/133] debugging / fixes --- src/artifact_cache/artifact_cache.c | 10 +++++++--- src/dbg_info/dbg_info2.c | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 2993b3be..6733f213 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -340,13 +340,17 @@ ac_async_tick(void) AC_Request *r = &task->wide[idx]; // rjf: any new higher priority tasks? -> cancel - if(task_idx == 1 && idx != 0) MutexScope(ac_shared->req_batches[0].mutex) + if(lane_idx() == 0) { - if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0) + if(task_idx == 1 && idx != 0) MutexScope(ac_shared->req_batches[0].mutex) { - ins_atomic_u64_eval_assign(cancelled_ptr, 1); + if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0) + { + ins_atomic_u64_eval_assign(cancelled_ptr, 1); + } } } + lane_sync(); // rjf: cancelled? -> exit if(ins_atomic_u64_eval(cancelled_ptr)) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 7ada292f..84c1e75a 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -1401,6 +1401,7 @@ di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) artifact.u64[3] = match.idx; } + lane_sync(); scratch_end(scratch); return artifact; } From d5ea64a72da32f37c27ff3cb32799c3c711c18c7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 15:25:15 -0700 Subject: [PATCH 007/133] merge blob & key storage locking scopes in content layer - keep both blob & key cache updates 'atomic' --- src/content/content.c | 196 +++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 96 deletions(-) diff --git a/src/content/content.c b/src/content/content.c index 8e554b94..cde216cd 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -188,123 +188,127 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; //- rjf: commit data to cache - if already there, just bump key refcount - ProfScope("commit data to cache - if already there, just bump key refcount") MutexScopeW(stripe->rw_mutex) + U128 key_expired_hash = {0}; + ProfScope("commit data to cache - if already there, just bump key refcount") + MutexScopeW(stripe->rw_mutex) + MutexScopeW(key_stripe->rw_mutex) { - C_BlobNode *existing_node = 0; - for(C_BlobNode *n = slot->first; n != 0; n = n->next) + //- rjf: commit data to (hash -> data) cache { - if(u128_match(n->hash, hash)) + C_BlobNode *existing_node = 0; + for(C_BlobNode *n = slot->first; n != 0; n = n->next) { - existing_node = n; - break; + if(u128_match(n->hash, hash)) + { + existing_node = n; + break; + } } - } - if(existing_node == 0) - { - C_BlobNode *node = c_shared->blob_stripes_free_nodes[stripe_idx]; - if(node) + if(existing_node == 0) { - SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]); + C_BlobNode *node = c_shared->blob_stripes_free_nodes[stripe_idx]; + if(node) + { + SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]); + } + else + { + node = push_array_no_zero(stripe->arena, C_BlobNode, 1); + } + MemoryZeroStruct(node); + node->hash = hash; + if(data_arena != 0) + { + node->arena = *data_arena; + } + node->data = data; + node->key_ref_count = 1; + DLLPushBack(slot->first, slot->last, node); } else { - node = push_array_no_zero(stripe->arena, C_BlobNode, 1); + existing_node->key_ref_count += 1; + if(data_arena != 0) + { + arena_release(*data_arena); + } } - MemoryZeroStruct(node); - node->hash = hash; if(data_arena != 0) { - node->arena = *data_arena; - } - node->data = data; - node->key_ref_count = 1; - DLLPushBack(slot->first, slot->last, node); - } - else - { - existing_node->key_ref_count += 1; - if(data_arena != 0) - { - arena_release(*data_arena); - } - } - if(data_arena != 0) - { - *data_arena = 0; - } - } - - //- rjf: commit this hash to key cache - U128 key_expired_hash = {0}; - ProfScope("commit this hash to key cache") MutexScopeW(key_stripe->rw_mutex) - { - // rjf: find existing key - B32 key_is_new = 0; - C_KeyNode *key_node = 0; - for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) - { - if(c_key_match(n->key, key)) - { - key_node = n; - break; + *data_arena = 0; } } - // rjf: create key node if it doesn't exist - if(!key_node) + //- rjf: commit hash to key cache { - key_is_new = 1; - key_node = c_shared->key_stripes_free_nodes[key_stripe_idx]; + // rjf: find existing key + B32 key_is_new = 0; + C_KeyNode *key_node = 0; + for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(c_key_match(n->key, key)) + { + key_node = n; + break; + } + } + + // rjf: create key node if it doesn't exist + if(!key_node) + { + key_is_new = 1; + key_node = c_shared->key_stripes_free_nodes[key_stripe_idx]; + if(key_node) + { + SLLStackPop(c_shared->key_stripes_free_nodes[key_stripe_idx]); + } + else + { + key_node = push_array(key_stripe->arena, C_KeyNode, 1); + } + key_node->key = key; + DLLPushBack(key_slot->first, key_slot->last, key_node); + } + + // rjf: push hash into key's history if(key_node) { - SLLStackPop(c_shared->key_stripes_free_nodes[key_stripe_idx]); - } - else - { - key_node = push_array(key_stripe->arena, C_KeyNode, 1); - } - key_node->key = key; - DLLPushBack(key_slot->first, key_slot->last, key_node); - } - - // rjf: push hash into key's history - if(key_node) - { - if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) - { - key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; - } - key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; - key_node->hash_history_gen += 1; - } - - // rjf: key is new -> add this key to the associated root - if(key_is_new) - { - U64 root_hash = u64_hash_from_str8(str8_struct(&key.root)); - U64 root_slot_idx = root_hash%c_shared->root_slots_count; - U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count; - C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx]; - C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx]; - MutexScopeW(root_stripe->rw_mutex) - { - for(C_RootNode *n = root_slot->first; n != 0; n = n->next) + if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) { - if(MemoryMatchStruct(&n->root, &key.root)) + key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; + } + key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; + key_node->hash_history_gen += 1; + } + + // rjf: key is new -> add this key to the associated root + if(key_is_new) + { + U64 root_hash = u64_hash_from_str8(str8_struct(&key.root)); + U64 root_slot_idx = root_hash%c_shared->root_slots_count; + U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count; + C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx]; + C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx]; + MutexScopeW(root_stripe->rw_mutex) + { + for(C_RootNode *n = root_slot->first; n != 0; n = n->next) { - C_RootIDChunkNode *chunk = n->ids.last; - if(chunk == 0 || chunk->count >= chunk->cap) + if(MemoryMatchStruct(&n->root, &key.root)) { - chunk = push_array(n->arena, C_RootIDChunkNode, 1); - SLLQueuePush(n->ids.first, n->ids.last, chunk); - n->ids.chunk_count += 1; - chunk->cap = 1024; - chunk->v = push_array_no_zero(n->arena, C_ID, chunk->cap); + C_RootIDChunkNode *chunk = n->ids.last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(n->arena, C_RootIDChunkNode, 1); + SLLQueuePush(n->ids.first, n->ids.last, chunk); + n->ids.chunk_count += 1; + chunk->cap = 1024; + chunk->v = push_array_no_zero(n->arena, C_ID, chunk->cap); + } + chunk->v[chunk->count] = key.id; + chunk->count += 1; + n->ids.total_count += 1; + break; } - chunk->v[chunk->count] = key.id; - chunk->count += 1; - n->ids.total_count += 1; - break; } } } From 89a026e2a69b14b62130be7a9fd8b8aafa7615d7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 15:55:22 -0700 Subject: [PATCH 008/133] fix content cache submission - theory is that non-zeroed keys were causing double-decs of history! --- src/content/content.c | 213 +++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 106 deletions(-) diff --git a/src/content/content.c b/src/content/content.c index cde216cd..1136f1af 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -187,128 +187,130 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; - //- rjf: commit data to cache - if already there, just bump key refcount - U128 key_expired_hash = {0}; - ProfScope("commit data to cache - if already there, just bump key refcount") - MutexScopeW(stripe->rw_mutex) - MutexScopeW(key_stripe->rw_mutex) + //- rjf: commit to (hash -> data) cache + ProfScope("commit to (hash -> data) cache") RWMutexScope(stripe->rw_mutex, 1) { - //- rjf: commit data to (hash -> data) cache + // rjf: find existing node + C_BlobNode *node = 0; + for(C_BlobNode *n = slot->first; n != 0; n = n->next) { - C_BlobNode *existing_node = 0; - for(C_BlobNode *n = slot->first; n != 0; n = n->next) + if(u128_match(n->hash, hash)) { - if(u128_match(n->hash, hash)) - { - existing_node = n; - break; - } - } - if(existing_node == 0) - { - C_BlobNode *node = c_shared->blob_stripes_free_nodes[stripe_idx]; - if(node) - { - SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]); - } - else - { - node = push_array_no_zero(stripe->arena, C_BlobNode, 1); - } - MemoryZeroStruct(node); - node->hash = hash; - if(data_arena != 0) - { - node->arena = *data_arena; - } - node->data = data; - node->key_ref_count = 1; - DLLPushBack(slot->first, slot->last, node); - } - else - { - existing_node->key_ref_count += 1; - if(data_arena != 0) - { - arena_release(*data_arena); - } - } - if(data_arena != 0) - { - *data_arena = 0; + node = n; + break; } } - //- rjf: commit hash to key cache + // rjf: release duplicate data if node already exists + if(node != 0) { - // rjf: find existing key - B32 key_is_new = 0; - C_KeyNode *key_node = 0; - for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) + arena_release(*data_arena); + } + + // rjf: allocate node if needed + if(node == 0) + { + node = c_shared->blob_stripes_free_nodes[stripe_idx]; + if(node) { - if(c_key_match(n->key, key)) - { - key_node = n; - break; - } + SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]); } - - // rjf: create key node if it doesn't exist - if(!key_node) + else { - key_is_new = 1; - key_node = c_shared->key_stripes_free_nodes[key_stripe_idx]; - if(key_node) - { - SLLStackPop(c_shared->key_stripes_free_nodes[key_stripe_idx]); - } - else - { - key_node = push_array(key_stripe->arena, C_KeyNode, 1); - } - key_node->key = key; - DLLPushBack(key_slot->first, key_slot->last, key_node); + node = push_array_no_zero(stripe->arena, C_BlobNode, 1); } - - // rjf: push hash into key's history + MemoryZeroStruct(node); + node->hash = hash; + if(data_arena != 0) + { + node->arena = *data_arena; + } + node->data = data; + DLLPushBack(slot->first, slot->last, node); + } + + // rjf: bump key ref count + node->key_ref_count += 1; + + // rjf "steal" arena from caller + if(data_arena != 0) + { + *data_arena = 0; + } + } + + //- rjf: commit to (key -> list(hash)) cache + U128 key_expired_hash = {0}; + ProfScope("commit to (key -> list(hash)) cache") RWMutexScope(key_stripe->rw_mutex, 1) + { + // rjf: find existing key + C_KeyNode *key_node = 0; + for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(c_key_match(n->key, key)) + { + key_node = n; + break; + } + } + + // rjf: create key node if it doesn't exist + B32 key_is_new = 0; + if(!key_node) + { + key_is_new = 1; + key_node = c_shared->key_stripes_free_nodes[key_stripe_idx]; if(key_node) { - if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) - { - key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; - } - key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; - key_node->hash_history_gen += 1; + SLLStackPop(c_shared->key_stripes_free_nodes[key_stripe_idx]); } - - // rjf: key is new -> add this key to the associated root - if(key_is_new) + else { - U64 root_hash = u64_hash_from_str8(str8_struct(&key.root)); - U64 root_slot_idx = root_hash%c_shared->root_slots_count; - U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count; - C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx]; - C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx]; - MutexScopeW(root_stripe->rw_mutex) + key_node = push_array_no_zero(key_stripe->arena, C_KeyNode, 1); + } + MemoryZeroStruct(key_node); + key_node->key = key; + DLLPushBack(key_slot->first, key_slot->last, key_node); + } + + // rjf: push hash into key's history + if(key_node) + { + if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) + { + key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; + } + key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; + key_node->hash_history_gen += 1; + } + + // rjf: key is new -> add this key to the associated root + if(key_is_new) + { + U64 root_hash = u64_hash_from_str8(str8_struct(&key.root)); + U64 root_slot_idx = root_hash%c_shared->root_slots_count; + U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count; + C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx]; + C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx]; + RWMutexScope(root_stripe->rw_mutex, 1) + { + for(C_RootNode *n = root_slot->first; n != 0; n = n->next) { - for(C_RootNode *n = root_slot->first; n != 0; n = n->next) + if(MemoryMatchStruct(&n->root, &key.root)) { - if(MemoryMatchStruct(&n->root, &key.root)) + C_RootIDChunkNode *chunk = n->ids.last; + if(chunk == 0 || chunk->count >= chunk->cap) { - C_RootIDChunkNode *chunk = n->ids.last; - if(chunk == 0 || chunk->count >= chunk->cap) - { - chunk = push_array(n->arena, C_RootIDChunkNode, 1); - SLLQueuePush(n->ids.first, n->ids.last, chunk); - n->ids.chunk_count += 1; - chunk->cap = 1024; - chunk->v = push_array_no_zero(n->arena, C_ID, chunk->cap); - } - chunk->v[chunk->count] = key.id; - chunk->count += 1; - n->ids.total_count += 1; - break; + chunk = push_array(n->arena, C_RootIDChunkNode, 1); + SLLQueuePush(n->ids.first, n->ids.last, chunk); + n->ids.chunk_count += 1; + chunk->cap = 1024; + chunk->v = push_array_no_zero(n->arena, C_ID, chunk->cap); } + chunk->v[chunk->count] = key.id; + chunk->count += 1; + n->ids.total_count += 1; + break; } } } @@ -316,14 +318,13 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) } //- rjf: decrement key ref count of expired hash - ProfScope("decrement key ref count of expired hash") - if(!u128_match(key_expired_hash, u128_zero())) + if(!u128_match(key_expired_hash, u128_zero())) ProfScope("decrement key ref count of expired hash") { U64 old_hash_slot_idx = key_expired_hash.u64[1]%c_shared->blob_slots_count; U64 old_hash_stripe_idx = old_hash_slot_idx%c_shared->blob_stripes_count; C_BlobSlot *old_hash_slot = &c_shared->blob_slots[old_hash_slot_idx]; C_Stripe *old_hash_stripe = &c_shared->blob_stripes[old_hash_stripe_idx]; - MutexScopeR(old_hash_stripe->rw_mutex) + RWMutexScope(old_hash_stripe->rw_mutex, 0) { for(C_BlobNode *n = old_hash_slot->first; n != 0; n = n->next) { From 628eaf84eecc81902884b0ffb982c883935b01b4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 16:47:26 -0700 Subject: [PATCH 009/133] fix release order in dbg_info2 --- src/dbg_info/dbg_info2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 84c1e75a..7800dd36 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -352,13 +352,13 @@ di2_close(DI2_Key key) //- rjf: release node's resources if needed if(node_released) { + os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); + os_file_map_close(file_map); + os_file_close(file); if(arena != 0) { arena_release(arena); } - os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); - os_file_map_close(file_map); - os_file_close(file); } } From cd048a878b4c3715718e7c10d006210511a72bac Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 30 Sep 2025 17:54:31 -0700 Subject: [PATCH 010/133] fix module req cache bug; fall back on exe path as debug info --- src/ctrl/ctrl_core.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 774ad4b8..4d98d111 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3084,12 +3084,15 @@ ctrl_thread__entry_point(void *p) } //- rjf: reset per-message state - arena_clear(ctrl_state->ctrl_thread_msg_process_arena); - ctrl_state->module_req_cache_slots_count = 1024; - ctrl_state->module_req_cache_slots = push_array(ctrl_state->ctrl_thread_msg_process_arena, CTRL_ModuleReqCacheNode *, ctrl_state->module_req_cache_slots_count); - MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_files); - MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_symbols); - MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters); + ProfScope("reset per-message state") + { + arena_clear(ctrl_state->ctrl_thread_msg_process_arena); + ctrl_state->module_req_cache_slots_count = 4096; + ctrl_state->module_req_cache_slots = push_array(ctrl_state->ctrl_thread_msg_process_arena, CTRL_ModuleReqCacheNode *, ctrl_state->module_req_cache_slots_count); + MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_files); + MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_symbols); + MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters); + } //- rjf: gather all touched symbols by user breakpoints { @@ -3655,6 +3658,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.pdb", path); str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", str8_chop_last_dot(path)); str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", path); + str8_list_push(scratch.arena, &dbg_path_candidates, path); for(String8Node *n = dbg_path_candidates.first; n != 0; n = n->next) { String8 candidate_path = n->string; @@ -4283,7 +4287,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C U64 slot_idx = hash%ctrl_state->module_req_cache_slots_count; CTRL_ModuleReqCacheNode *slot = ctrl_state->module_req_cache_slots[slot_idx]; CTRL_ModuleReqCacheNode *node = 0; - for(CTRL_ModuleReqCacheNode *n = slot; slot != 0; slot = slot->next) + for(CTRL_ModuleReqCacheNode *n = slot; n != 0; n = n->next) { if(ctrl_handle_match(n->module, mod->handle)) { @@ -4303,6 +4307,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C { CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath); OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, debug_info_path->string); + ProfScope("determine if %.*s is necessary", str8_varg(debug_info_path->string)) { //- rjf: determine if file is PDB B32 file_is_pdb = 0; From 24406d1e4eb8fd4ff7689ec75ef22e8931105a3f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 11:24:37 -0700 Subject: [PATCH 011/133] use lack of user bps as hint that no rdis are necessary to wait on --- src/ctrl/ctrl_core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 4d98d111..56c42063 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -4232,6 +4232,7 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) internal CTRL_EvalScope * ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, CTRL_Entity *thread) { + ProfBeginFunction(); CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; CTRL_EvalScope *scope = push_array(arena, CTRL_EvalScope, 1); scope->access = access_open(); @@ -4280,7 +4281,11 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C // (we *always* wait for the initial module) // B32 rdi_is_necessary = 1; - if(rdi == &rdi_parsed_nil) ProfScope("determine if RDI is necessary") + if(user_bps->count == 0) + { + rdi_is_necessary = 0; + } + else if(rdi == &rdi_parsed_nil) ProfScope("determine if RDI is necessary") { // rjf: find cached result U64 hash = ctrl_hash_from_handle(mod->handle); @@ -4438,6 +4443,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C } e_select_interpret_ctx(&scope->interpret_ctx, eval_modules_primary->rdi, thread_rip_voff); + ProfEnd(); return scope; } From b92821b503bd5f5a8c73f15da8feac37cbfec9d6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 11:44:47 -0700 Subject: [PATCH 012/133] convert less aggressively, fix incorrect di2 request batch clearing --- src/dbg_info/dbg_info2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 7800dd36..34ac44a9 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -517,10 +517,10 @@ di2_async_tick(void) MemoryCopyStruct(&n_copy->v, &n->v); SLLQueuePush(first_req, last_req, n_copy); } + arena_clear(b->arena); + b->first = b->last = 0; + b->count = 0; } - arena_clear(b->arena); - b->first = b->last = 0; - b->count = 0; } //////////////////////////// @@ -673,7 +673,7 @@ di2_async_tick(void) //- rjf: determine if there are threads available B32 threads_available = 0; { - U64 max_threads = os_get_system_info()->logical_processor_count*8; + U64 max_threads = os_get_system_info()->logical_processor_count*2; U64 current_threads = di2_shared->conversion_thread_count; U64 needed_threads = (current_threads + t->thread_count); threads_available = (max_threads >= needed_threads); From db66beaf222d1f8db6c187d492538cab449bdbdf Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 14:32:44 -0700 Subject: [PATCH 013/133] correctly interpret conversion completions; single high priority re-loop bit for async threads --- src/artifact_cache/artifact_cache.c | 21 ++++---- src/base/base_entry_point.c | 1 + src/ctrl/ctrl_core.c | 3 +- src/dbg_info/dbg_info2.c | 82 +++++++++++++++++++++++++++-- src/dbg_info/dbg_info2.h | 19 +++++++ src/raddbg/raddbg_main.c | 2 - 6 files changed, 108 insertions(+), 20 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 6733f213..4b78d1db 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -166,6 +166,10 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 } cond_var_broadcast(async_tick_start_cond_var); ins_atomic_u32_eval_assign(&async_loop_again, 1); + if(params->flags & AC_Flag_HighPriority) + { + ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1); + } } // rjf: get value from node, if possible @@ -342,18 +346,15 @@ ac_async_tick(void) // rjf: any new higher priority tasks? -> cancel if(lane_idx() == 0) { - if(task_idx == 1 && idx != 0) MutexScope(ac_shared->req_batches[0].mutex) + if(task_idx == 1 && idx != 0 && ins_atomic_u32_eval(&async_loop_again_high_priority)) { - if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0) - { - ins_atomic_u64_eval_assign(cancelled_ptr, 1); - } + ins_atomic_u64_eval_assign(cancelled_ptr, 1); } } lane_sync(); // rjf: cancelled? -> exit - if(ins_atomic_u64_eval(cancelled_ptr)) + if(ins_atomic_u32_eval(cancelled_ptr)) { break; } @@ -441,12 +442,10 @@ ac_async_tick(void) for(;;) { // rjf: any new higher priority tasks? -> cancel - if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2) MutexScope(ac_shared->req_batches[0].mutex) + if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2 && + ins_atomic_u32_eval(&async_loop_again_high_priority)) { - if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0) - { - ins_atomic_u64_eval_assign(cancelled_ptr, 1); - } + ins_atomic_u64_eval_assign(cancelled_ptr, 1); } // rjf: cancelled? -> exit diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 7411e32c..e3e54172 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -7,6 +7,7 @@ global CondVar async_tick_start_cond_var = {0}; global Mutex async_tick_start_mutex = {0}; global Mutex async_tick_stop_mutex = {0}; global B32 async_loop_again = 0; +global B32 async_loop_again_high_priority = 0; global B32 global_async_exit = 0; thread_static B32 is_async_thread = 0; diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 56c42063..1a015a2f 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3658,7 +3658,6 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.pdb", path); str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", str8_chop_last_dot(path)); str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", path); - str8_list_push(scratch.arena, &dbg_path_candidates, path); for(String8Node *n = dbg_path_candidates.first; n != 0; n = n->next) { String8 candidate_path = n->string; @@ -4360,7 +4359,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C } //- rjf: if this RDI is necessary, but we do not have it => wait for it forever - if(rdi == &rdi_parsed_nil && rdi_is_necessary) + if(rdi == &rdi_parsed_nil && rdi_is_necessary) ProfScope("RDI is necessary -> wait") { rdi = di2_rdi_from_key(scope->access, dbgi_key, 1, max_U64); } diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 34ac44a9..1a72cd85 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -73,16 +73,29 @@ di2_init(CmdLine *cmdline) has_parent = 0; signal_pid = os_get_process_info()->pid; } + U64 signal_code = 0; + String8 signal_code_string = cmd_line_string(cmdline, str8_lit("signal_code")); + try_u64_from_str8_c_rules(signal_code_string, &signal_code); + di2_shared->conversion_completion_code = signal_code; + di2_shared->conversion_completion_lock_semaphore_name = str8f(arena, "conversion_completion_lock_pid_%I64u", signal_pid); di2_shared->conversion_completion_signal_semaphore_name = str8f(arena, "conversion_completion_signal_pid_%I64u", signal_pid); + di2_shared->conversion_completion_shared_memory_name = str8f(arena, "conversion_completion_shared_memory_pid_%I64u", signal_pid); if(has_parent) { + di2_shared->conversion_completion_lock_semaphore = semaphore_open(di2_shared->conversion_completion_lock_semaphore_name); di2_shared->conversion_completion_signal_semaphore = semaphore_open(di2_shared->conversion_completion_signal_semaphore_name); + di2_shared->conversion_completion_shared_memory = os_shared_memory_open(di2_shared->conversion_completion_shared_memory_name); } else { + di2_shared->conversion_completion_lock_semaphore = semaphore_alloc(1, 1, di2_shared->conversion_completion_lock_semaphore_name); di2_shared->conversion_completion_signal_semaphore = semaphore_alloc(0, 65536, di2_shared->conversion_completion_signal_semaphore_name); + di2_shared->conversion_completion_shared_memory = os_shared_memory_alloc(KB(4), di2_shared->conversion_completion_shared_memory_name); di2_shared->conversion_completion_signal_receiver_thread = thread_launch(di2_conversion_completion_signal_receiver_thread_entry_point, 0); } + di2_shared->conversion_completion_shared_memory_base = (U64 *)os_shared_memory_view_open(di2_shared->conversion_completion_shared_memory, r1u64(0, KB(4))); + di2_shared->completion_mutex = mutex_alloc(); + di2_shared->completion_arena = arena_alloc(); } //////////////////////////////// @@ -456,6 +469,7 @@ di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us) } cond_var_broadcast(async_tick_start_cond_var); ins_atomic_u32_eval_assign(&async_loop_again, 1); + ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1); } // rjf: found current results, or out-of-time? abort @@ -523,6 +537,23 @@ di2_async_tick(void) } } + //////////////////////////// + //- rjf: gather all completions + // + DI2_LoadCompletion *first_completion = 0; + DI2_LoadCompletion *last_completion = 0; + MutexScope(di2_shared->completion_mutex) + { + for EachNode(c, DI2_LoadCompletion, di2_shared->first_completion) + { + DI2_LoadCompletion *dst_c = push_array(scratch.arena, DI2_LoadCompletion, 1); + SLLQueuePush(first_completion, last_completion, dst_c); + dst_c->code = c->code; + } + arena_clear(di2_shared->completion_arena); + di2_shared->first_completion = di2_shared->last_completion = 0; + } + //////////////////////////// //- rjf: generate load tasks for all unique requests // @@ -699,7 +730,9 @@ di2_async_tick(void) str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--out:%S", rdi_path); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--thread_count:%I64u", t->thread_count); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_pid:%I64u", (U64)os_get_process_info()->pid); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_code:%I64u", (U64)t); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "%S", og_path); + ProfMsg("launch creation for %.*s", str8_varg(rdi_path)); t->process = os_process_launch(¶ms); t->status = DI2_LoadTaskStatus_Active; di2_shared->conversion_process_count += 1; @@ -709,11 +742,27 @@ di2_async_tick(void) //- rjf: if active & process has completed, mark as done { U64 exit_code = 0; - if(t->status == DI2_LoadTaskStatus_Active && os_process_join(t->process, 0, &exit_code)) + if(t->status == DI2_LoadTaskStatus_Active) { - t->status = DI2_LoadTaskStatus_Done; - di2_shared->conversion_process_count -= 1; - di2_shared->conversion_thread_count -= t->thread_count; + B32 task_is_done = 0; + for(DI2_LoadCompletion *c = first_completion; c != 0; c = c->next) + { + if(c->code == (U64)t) + { + task_is_done = 1; + break; + } + } + if(!task_is_done) + { + task_is_done = os_process_join(t->process, 0, 0); + } + if(task_is_done) + { + t->status = DI2_LoadTaskStatus_Done; + di2_shared->conversion_process_count -= 1; + di2_shared->conversion_thread_count -= t->thread_count; + } } } @@ -823,6 +872,7 @@ di2_async_tick(void) //- rjf: commit parsed info to cache { + ProfMsg("commit %.*s", str8_varg(rdi_path)); U64 hash = u64_hash_from_str8(str8_struct(&key)); U64 slot_idx = hash%di2_shared->slots_count; DI2_Slot *slot = &di2_shared->slots[slot_idx]; @@ -878,6 +928,9 @@ di2_async_tick(void) internal void di2_signal_completion(void) { + semaphore_take(di2_shared->conversion_completion_lock_semaphore, max_U64); + di2_shared->conversion_completion_shared_memory_base[0] = di2_shared->conversion_completion_code; + semaphore_drop(di2_shared->conversion_completion_lock_semaphore); semaphore_drop(di2_shared->conversion_completion_signal_semaphore); } @@ -889,8 +942,25 @@ di2_conversion_completion_signal_receiver_thread_entry_point(void *p) { if(semaphore_take(di2_shared->conversion_completion_signal_semaphore, max_U64)) { - cond_var_broadcast(async_tick_start_cond_var); + // rjf: get the next retired code + U64 retired_code = 0; + semaphore_take(di2_shared->conversion_completion_lock_semaphore, max_U64); + retired_code = di2_shared->conversion_completion_shared_memory_base[0]; + semaphore_drop(di2_shared->conversion_completion_lock_semaphore); + + // rjf: push completion record + MutexScope(di2_shared->completion_mutex) + { + DI2_LoadCompletion *c = push_array(di2_shared->completion_arena, DI2_LoadCompletion, 1); + SLLQueuePush(di2_shared->first_completion, di2_shared->last_completion, c); + c->code = retired_code; + } + + // rjf: signal async system to resume + ProfMsg("signal conversion completion"); ins_atomic_u32_eval_assign(&async_loop_again, 1); + ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1); + cond_var_broadcast(async_tick_start_cond_var); } } } @@ -1312,6 +1382,7 @@ di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, internal AC_Artifact di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { + ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); //- rjf: unpack key @@ -1403,6 +1474,7 @@ di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) lane_sync(); scratch_end(scratch); + ProfEnd(); return artifact; } diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index 96671f1e..f406d825 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -148,6 +148,13 @@ struct DI2_LoadTask OS_Handle process; }; +typedef struct DI2_LoadCompletion DI2_LoadCompletion; +struct DI2_LoadCompletion +{ + DI2_LoadCompletion *next; + U64 code; +}; + //////////////////////////////// //~ rjf: Search Types @@ -232,9 +239,21 @@ struct DI2_Shared U64 conversion_thread_count; // rjf: conversion completion receiving thread + U64 conversion_completion_code; + String8 conversion_completion_lock_semaphore_name; String8 conversion_completion_signal_semaphore_name; + String8 conversion_completion_shared_memory_name; + Semaphore conversion_completion_lock_semaphore; Semaphore conversion_completion_signal_semaphore; + OS_Handle conversion_completion_shared_memory; + U64 *conversion_completion_shared_memory_base; Thread conversion_completion_signal_receiver_thread; + + // rjf: completion batch + Mutex completion_mutex; + Arena *completion_arena; + DI2_LoadCompletion *first_completion; + DI2_LoadCompletion *last_completion; }; //////////////////////////////// diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 27745928..2dc89e6c 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -248,7 +248,6 @@ #include "radbin/radbin.h" #include "regs/regs.h" #include "regs/rdi/regs_rdi.h" -// #include "dbg_info/dbg_info.h" #include "dbg_info/dbg_info2.h" #include "disasm/disasm.h" #include "demon/demon_inc.h" @@ -296,7 +295,6 @@ #include "radbin/radbin.c" #include "regs/regs.c" #include "regs/rdi/regs_rdi.c" -// #include "dbg_info/dbg_info.c" #include "dbg_info/dbg_info2.c" #include "disasm/disasm.c" #include "demon/demon_inc.c" From 7707ba1d60bbeaaed21e5a78b4f7c97fe3873418 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 15:36:36 -0700 Subject: [PATCH 014/133] dwarf debug info option in builds, fix heuristic to try to load debug info from exe itself --- build.bat | 12 +++++++----- src/ctrl/ctrl_core.c | 37 ++++++++++++++++++++++++++++--------- src/dwarf/dwarf_coff.c | 22 +++++++++------------- src/dwarf/dwarf_coff.h | 2 +- src/radbin/radbin.c | 2 +- src/raddbg/raddbg_core.c | 2 +- 6 files changed, 47 insertions(+), 30 deletions(-) diff --git a/build.bat b/build.bat index 81427182..77784200 100644 --- a/build.bat +++ b/build.bat @@ -39,10 +39,12 @@ if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && :: --- Unpack Command Line Build Arguments ------------------------------------ set auto_compile_flags= -if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled] -if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled] -if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled] -if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend] +if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled] +if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled] +if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled] +if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend] +if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info] +if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview if "%pgo%"=="1" ( if "%no_meta%"=="" echo ERROR: PGO build must have no_meta argument || exit /b 1 where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1 @@ -70,7 +72,7 @@ set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf set cl_out= /out: set cl_linker= -set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 +set clang_common= -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 1a015a2f..ae3c131b 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3399,11 +3399,12 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ U32 pdb_dbg_time = 0; U32 pdb_dbg_age = 0; Guid pdb_dbg_guid = {0}; - String8 pdb_dbg_path = str8_zero(); + String8 pdb_dbg_path = {0}; U32 rdi_dbg_time = 0; Guid rdi_dbg_guid = {0}; - String8 rdi_dbg_path = str8_zero(); - String8 raddbg_data = str8_zero(); + String8 exe_dbg_path = {0}; + String8 rdi_dbg_path = {0}; + String8 raddbg_data = {0}; Rng1U64 raddbg_section_voff_range = r1u64(0, 0); Rng1U64 raddbg_is_attached_section_voff_range = r1u64(0, 0); ProfScope("unpack relevant PE info") @@ -3453,6 +3454,8 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ U32 data_dir_count = 0; if(opt_ext_size > 0) { + Temp scratch = scratch_begin(0, 0); + // rjf: read magic number U16 opt_ext_magic = 0; dmn_process_read_struct(process.dmn_handle, vaddr_range.min + opt_ext_off_range.min, &opt_ext_magic); @@ -3523,6 +3526,12 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ } } + // rjf: extract sections + U64 sec_array_off = opt_ext_off_range.max; + U64 sec_count = file_header.section_count; + COFF_SectionHeader *sec = push_array(scratch.arena, COFF_SectionHeader, sec_count); + dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + sec_array_off, vaddr_range.min + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec); + // rjf: grab entry point vaddr entry_point_voff = entry_point; @@ -3589,13 +3598,18 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ } } + // rjf: look for DWARF debug info + { + U64 symbol_array_off = file_header.symbol_table_foff; + U64 symbol_count = file_header.symbol_count; + if(symbol_array_off != 0) + { + exe_dbg_path = path; + } + } + // rjf: extract copy of module's raddbg data { - Temp scratch = scratch_begin(0, 0); - U64 sec_array_off = opt_ext_off_range.max; - U64 sec_count = file_header.section_count; - COFF_SectionHeader *sec = push_array(scratch.arena, COFF_SectionHeader, sec_count); - dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + sec_array_off, vaddr_range.min + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec); for EachIndex(idx, sec_count) { String8 section_name = str8_cstring((char *)sec[idx].name); @@ -3614,7 +3628,6 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ raddbg_data.str = push_array(arena, U8, raddbg_data.size); dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + raddbg_section_voff_range.min, vaddr_range.min + raddbg_section_voff_range.max), raddbg_data.str); - scratch_end(scratch); } // rjf: if we have a "raddbg is attached" section, mark the first byte as 1, to signify attachment @@ -3623,6 +3636,8 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ U8 new_value = 1; dmn_process_write_struct(process.dmn_handle, vaddr_range.min + raddbg_is_attached_section_voff_range.min, &new_value); } + + scratch_end(scratch); } } @@ -3649,6 +3664,10 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, rdi_dbg_path); str8_list_push(scratch.arena, &dbg_path_candidates, rdi_dbg_path); } + if(exe_dbg_path.size != 0) + { + str8_list_push(scratch.arena, &dbg_path_candidates, path); + } if(pdb_dbg_path.size != 0) { str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, pdb_dbg_path); diff --git a/src/dwarf/dwarf_coff.c b/src/dwarf/dwarf_coff.c index 9ddbcd89..2c6614f9 100644 --- a/src/dwarf/dwarf_coff.c +++ b/src/dwarf/dwarf_coff.c @@ -2,28 +2,24 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) internal B32 -dw_is_dwarf_present_coff_section_table(String8 raw_image, - String8 string_table, - U64 section_count, - COFF_SectionHeader *section_table) +dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table) { B32 is_dwarf_present = 0; - - for (U64 i = 0; i < section_count; ++i) { - COFF_SectionHeader *header = §ion_table[i]; - String8 name = coff_name_from_section_header(string_table, header); - + for EachIndex(idx, section_count) + { + COFF_SectionHeader *header = §ion_table[idx]; + String8 name = coff_name_from_section_header(string_table, header); DW_SectionKind s = dw_section_kind_from_string(name); - if (s == DW_Section_Null) { + if(s == DW_Section_Null) + { s = dw_section_dwo_kind_from_string(name); } - is_dwarf_present = s != DW_Section_Null; - if (is_dwarf_present) { + if(is_dwarf_present) + { break; } } - return is_dwarf_present; } diff --git a/src/dwarf/dwarf_coff.h b/src/dwarf/dwarf_coff.h index 27f637d6..79cd37c3 100644 --- a/src/dwarf/dwarf_coff.h +++ b/src/dwarf/dwarf_coff.h @@ -4,7 +4,7 @@ #ifndef DWARF_COFF_H #define DWARF_COFF_H -internal B32 dw_is_dwarf_present_coff_section_table(String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table); +internal B32 dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table); internal DW_Input dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table); #endif // DWARF_COFF_H diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 77d59968..dfa3fec2 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -331,7 +331,7 @@ rb_thread_entry_point(void *p) String8 string_table = str8_substr(file_data, pe_bin_info.string_table_range); U64 section_count = raw_section_table.size / sizeof(COFF_SectionHeader); COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str; - if(dw_is_dwarf_present_coff_section_table(file_data, string_table, section_count, section_table)) + if(dw_is_dwarf_present_coff_section_table(string_table, section_count, section_table)) { file_format_flags |= RB_FileFormatFlag_HasDWARF; } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 911a7134..4147365d 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1251,7 +1251,7 @@ rd_target_from_cfg(Arena *arena, RD_Cfg *cfg) target.stdout_path = rd_cfg_child_from_string(cfg, str8_lit("stdout_path"))->first->string; target.stderr_path = rd_cfg_child_from_string(cfg, str8_lit("stderr_path"))->first->string; target.stdin_path = rd_cfg_child_from_string(cfg, str8_lit("stdin_path"))->first->string; - target.debug_subprocesses = (rd_cfg_child_from_string(cfg, str8_lit("debug_subprocesses")) != &rd_nil_cfg); + target.debug_subprocesses = !!e_value_from_string(rd_cfg_child_from_string(cfg, str8_lit("debug_subprocesses"))->first->string).u64; for(RD_Cfg *child = cfg->first; child != &rd_nil_cfg; child = child->next) { if(str8_match(child->string, str8_lit("environment"), 0)) From 24670e3095a57a8d8d9a083330cf671a4c82b2d2 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 15:46:42 -0700 Subject: [PATCH 015/133] fix di2 successful search continuity --- src/raddbg/raddbg_core.h | 4 ++++ src/raddbg/raddbg_eval.c | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index ad58381e..485593e0 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -230,6 +230,10 @@ struct RD_ViewState U8 query_buffer[KB(1)]; U64 query_string_size; + // rjf: last successful query string state + U8 last_successful_query_buffer[KB(1)]; + U64 last_successful_query_string_size; + // rjf: contents are focused (disables query focus) B32 contents_are_focused; }; diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 698d5675..23df8995 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1660,12 +1660,22 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) if(section != RDI_SectionKind_NULL) { U64 endt_us = rd_state->frame_eval_memread_endt_us; - - //- rjf: query all filtered items from dbgi searching system U128 fuzzy_search_key = {d_hash_from_string(str8_struct(&rd_regs()->view)), (U64)section}; accel->section = section; accel->items = di2_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us); + RD_ViewState *vs = rd_view_state_from_cfg(rd_cfg_from_id(rd_regs()->view)); + if(accel->items.count == 0) + { + String8 last_query = str8(vs->last_successful_query_buffer, vs->last_successful_query_string_size); + accel->items = di2_search_item_array_from_target_query(rd_state->frame_access, section, last_query, endt_us); + } + else + { + vs->last_successful_query_string_size = Min(sizeof(vs->last_successful_query_buffer), filter.size); + MemoryCopy(vs->last_successful_query_buffer, filter.str, vs->last_successful_query_string_size); + } } + E_TypeExpandInfo info = {accel, accel->items.count}; scratch_end(scratch); return info; @@ -1796,6 +1806,7 @@ E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(debug_info_table) hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].key.u64[0])); hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].key.u64[1])); hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].idx)); + id = hash; } return id; } From 47e20142502bd0896f1ddbbc9aca19b509a8e9d5 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 15:53:58 -0700 Subject: [PATCH 016/133] reset high priority bit --- src/base/base_entry_point.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index e3e54172..ddebe2e1 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -195,6 +195,7 @@ async_thread_entry_point(void *params) MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); } ins_atomic_u32_eval_assign(&async_loop_again, 0); + ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0); } lane_sync(); From 2cb94c422a3539a09d170cc9e0f5b2e8f59ce711 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 16:36:45 -0700 Subject: [PATCH 017/133] update key -> path and path -> key records on debug info closing --- src/dbg_info/dbg_info2.c | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 1a72cd85..c3e25df9 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -362,6 +362,57 @@ di2_close(DI2_Key key) } } + //- rjf: remove (path -> key) and (key -> path) records + if(node_released) + { + Temp scratch = scratch_begin(0, 0); + + // rjf: remove from key -> path cache; obtain path + String8 path = {0}; + { + U64 key2path_slot_idx = hash%di2_shared->key2path_slots_count; + DI2_KeySlot *key2path_slot = &di2_shared->key2path_slots[key2path_slot_idx]; + Stripe *key2path_stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, key2path_slot_idx); + RWMutexScope(key2path_stripe->rw_mutex, 1) + { + for(DI2_KeyPathNode *n = key2path_slot->first; n != 0; n = n->next) + { + if(di2_key_match(n->key, key)) + { + DLLRemove(key2path_slot->first, key2path_slot->last, n); + n->next = key2path_stripe->free; + key2path_stripe->free = n; + path = str8_copy(scratch.arena, n->path); + break; + } + } + } + } + + // rjf: remove from path -> key cache + { + U64 path_hash = u64_hash_from_str8(path); + U64 path2key_slot_idx = path_hash%di2_shared->path2key_slots_count; + DI2_KeySlot *path2key_slot = &di2_shared->path2key_slots[path2key_slot_idx]; + Stripe *path2key_stripe = stripe_from_slot_idx(&di2_shared->path2key_stripes, path2key_slot_idx); + RWMutexScope(path2key_stripe->rw_mutex, 1) + { + for(DI2_KeyPathNode *n = path2key_slot->first; n != 0; n = n->next) + { + if(str8_match(n->path, path, 0) && di2_key_match(n->key, key)) + { + DLLRemove(path2key_slot->first, path2key_slot->last, n); + n->next = path2key_stripe->free; + path2key_stripe->free = n; + break; + } + } + } + } + + scratch_end(scratch); + } + //- rjf: release node's resources if needed if(node_released) { From 544fea092994b8447adb8fba9781a86a8417e21b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 17:19:15 -0700 Subject: [PATCH 018/133] actually - keep (path * stamp -> key) and (key -> path * stamp) history - we do not need to evict these. also fix incorrect file map view closure on debug info close --- src/dbg_info/dbg_info2.c | 56 ++----------------------------- src/os/core/win32/os_core_win32.c | 5 +++ 2 files changed, 8 insertions(+), 53 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index c3e25df9..e95d18dd 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -268,7 +268,7 @@ di2_open(DI2_Key key) DI2_Node *node = 0; for(DI2_Node *n = slot->first; n != 0; n = n->next) { - if(di2_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) > 0) + if(di2_key_match(n->key, key)) { node = n; break; @@ -353,6 +353,7 @@ di2_close(DI2_Key key) file = node->file; file_map = node->file_map; file_props = node->file_props; + file_base = node->file_base; arena = node->arena; break; } @@ -362,57 +363,6 @@ di2_close(DI2_Key key) } } - //- rjf: remove (path -> key) and (key -> path) records - if(node_released) - { - Temp scratch = scratch_begin(0, 0); - - // rjf: remove from key -> path cache; obtain path - String8 path = {0}; - { - U64 key2path_slot_idx = hash%di2_shared->key2path_slots_count; - DI2_KeySlot *key2path_slot = &di2_shared->key2path_slots[key2path_slot_idx]; - Stripe *key2path_stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, key2path_slot_idx); - RWMutexScope(key2path_stripe->rw_mutex, 1) - { - for(DI2_KeyPathNode *n = key2path_slot->first; n != 0; n = n->next) - { - if(di2_key_match(n->key, key)) - { - DLLRemove(key2path_slot->first, key2path_slot->last, n); - n->next = key2path_stripe->free; - key2path_stripe->free = n; - path = str8_copy(scratch.arena, n->path); - break; - } - } - } - } - - // rjf: remove from path -> key cache - { - U64 path_hash = u64_hash_from_str8(path); - U64 path2key_slot_idx = path_hash%di2_shared->path2key_slots_count; - DI2_KeySlot *path2key_slot = &di2_shared->path2key_slots[path2key_slot_idx]; - Stripe *path2key_stripe = stripe_from_slot_idx(&di2_shared->path2key_stripes, path2key_slot_idx); - RWMutexScope(path2key_stripe->rw_mutex, 1) - { - for(DI2_KeyPathNode *n = path2key_slot->first; n != 0; n = n->next) - { - if(str8_match(n->path, path, 0) && di2_key_match(n->key, key)) - { - DLLRemove(path2key_slot->first, path2key_slot->last, n); - n->next = path2key_stripe->free; - path2key_stripe->free = n; - break; - } - } - } - } - - scratch_end(scratch); - } - //- rjf: release node's resources if needed if(node_released) { @@ -624,7 +574,7 @@ di2_async_tick(void) { for(DI2_Node *n = slot->first; n != 0; n = n->next) { - if(di2_key_match(n->key, key)) + if(di2_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) == 0) { request_is_duplicate = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) != 0); break; diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index a2e8cd9f..13602237 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -336,6 +336,11 @@ os_file_open(OS_AccessFlags flags, String8 path) { result.u64[0] = (U64)file; } + else + { + DWORD err = GetLastError(); + (void)err; + } scratch_end(scratch); return result; } From a58c23754aae60e33bfec09862b29b1e438b5c80 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 17:30:08 -0700 Subject: [PATCH 019/133] di2 -> di; delete old dbg info layer, delete async layer --- src/async/async.c | 286 --- src/async/async.h | 162 -- src/base/base_entry_point.c | 9 +- src/ctrl/ctrl_core.c | 48 +- src/ctrl/ctrl_core.h | 4 +- src/dbg_engine/dbg_engine_core.c | 46 +- src/dbg_engine/dbg_engine_core.h | 18 +- src/dbg_info/dbg_info.c | 2898 ++++++++++++---------------- src/dbg_info/dbg_info.h | 468 ++--- src/dbg_info/dbg_info2.c | 1503 --------------- src/dbg_info/dbg_info2.h | 319 --- src/disasm/disasm.c | 6 +- src/disasm/disasm.h | 2 +- src/eval/eval_ir.c | 6 +- src/eval/eval_parse.c | 4 +- src/raddbg/generated/raddbg.meta.c | 2 +- src/raddbg/generated/raddbg.meta.h | 2 +- src/raddbg/raddbg.mdesk | 2 +- src/raddbg/raddbg_core.c | 34 +- src/raddbg/raddbg_eval.c | 10 +- src/raddbg/raddbg_main.c | 8 +- src/raddbg/raddbg_views.c | 38 +- src/raddbg/raddbg_views.h | 4 +- src/raddbg/raddbg_widgets.c | 18 +- src/raddbg/raddbg_widgets.h | 2 +- src/scratch/ryan_scratch.c | 18 +- 26 files changed, 1539 insertions(+), 4378 deletions(-) delete mode 100644 src/async/async.c delete mode 100644 src/async/async.h delete mode 100644 src/dbg_info/dbg_info2.c delete mode 100644 src/dbg_info/dbg_info2.h diff --git a/src/async/async.c b/src/async/async.c deleted file mode 100644 index eeef9054..00000000 --- a/src/async/async.c +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#undef LAYER_COLOR -#define LAYER_COLOR 0x59b6c3ff - -//////////////////////////////// -//~ rjf: Top-Level Layer Initialization - -internal void -async_init(CmdLine *cmdline) -{ - Arena *arena = arena_alloc(); - async_shared = push_array(arena, ASYNC_Shared, 1); - async_shared->arena = arena; - for EachEnumVal(ASYNC_Priority, p) - { - ASYNC_Ring *ring = &async_shared->rings[p]; - ring->ring_size = MB(8); - ring->ring_base = push_array_no_zero(arena, U8, ring->ring_size); - ring->ring_mutex = mutex_alloc(); - ring->ring_cv = cond_var_alloc(); - } - async_shared->ring_mutex = mutex_alloc(); - async_shared->ring_cv = cond_var_alloc(); - String8 work_thread_count_string = cmd_line_string(cmdline, str8_lit("work_threads_count")); - if(work_thread_count_string.size == 0 || !try_u64_from_str8_c_rules(work_thread_count_string, &async_shared->work_threads_count)) - { - async_shared->work_threads_count = Max(4, os_get_system_info()->logical_processor_count-1); - } - async_shared->work_threads_count = Max(4, async_shared->work_threads_count); - async_shared->work_threads = push_array(arena, Thread, async_shared->work_threads_count); - for EachIndex(idx, async_shared->work_threads_count) - { - async_shared->work_threads[idx] = thread_launch(async_work_thread__entry_point, (void *)idx); - } -} - -//////////////////////////////// -//~ rjf: Top-Level Accessors - -internal U64 -async_thread_count(void) -{ - return async_shared->work_threads_count; -} - -//////////////////////////////// -//~ rjf: Work Kickoffs - -internal B32 -async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params) -{ - // rjf: choose ring - ASYNC_Ring *ring = &async_shared->rings[params->priority]; - - // rjf: build work package - ASYNC_Work work = {0}; - work.work_function = work_function; - work.input = params->input; - work.output = params->output; - work.semaphore = params->semaphore; - work.completion_counter = params->completion_counter; - work.working_counter = params->working_counter; - - // rjf: loop; try to write into user -> writer ring buffer. if we're on a - // worker thread, determine if we need to execute this task locally on this - // thread, and skip ring buffer if so. - B32 queued_in_ring_buffer = 0; - B32 need_to_execute_on_this_thread = 0; - MutexScope(ring->ring_mutex) for(;;) - { - U64 num_available_work_threads = (async_shared->work_threads_count - ins_atomic_u64_eval(&async_shared->work_threads_live_count)); - if(num_available_work_threads == 0 && async_work_thread_depth > 0) - { - need_to_execute_on_this_thread = 1; - break; - } - U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos; - U64 available_size = ring->ring_size - unconsumed_size; - if(available_size >= sizeof(work)) - { - queued_in_ring_buffer = 1; - if(!MemoryIsZeroStruct(¶ms->semaphore)) - { - os_semaphore_take(params->semaphore, max_U64); - } - ring->ring_write_pos += ring_write_struct(ring->ring_base, ring->ring_size, ring->ring_write_pos, &work); - break; - } - if(os_now_microseconds() >= params->endt_us) - { - break; - } - cond_var_wait(ring->ring_cv, ring->ring_mutex, params->endt_us); - } - - // rjf: broadcast ring buffer cv if we wrote successfully - if(queued_in_ring_buffer) - { - cond_var_broadcast(ring->ring_cv); - cond_var_broadcast(async_shared->ring_cv); - } - - // rjf: if we did not queue successfully, and we have determined that - // we need to execute this work on the current thread, then execute the - // work before returning - if(need_to_execute_on_this_thread) - { - async_execute_work(work); - } - - // rjf: return success signal - B32 result = (queued_in_ring_buffer || need_to_execute_on_this_thread); - return result; -} - -//////////////////////////////// -//~ rjf: Task-Based Work Helper - -internal void -async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t) -{ - ASYNC_TaskNode *n = push_array(arena, ASYNC_TaskNode, 1); - SLLQueuePush(list->first, list->last, n); - n->v = t; - list->count += 1; -} - -internal ASYNC_Task * -async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params) -{ - ASYNC_Task *task = push_array(arena, ASYNC_Task, 1); - task->semaphore = os_semaphore_alloc(1, 1, str8_zero()); - ASYNC_WorkParams params_refined = {0}; - MemoryCopyStruct(¶ms_refined, params); - params_refined.endt_us = max_U64; - params_refined.semaphore = task->semaphore; - if(params_refined.output == 0) - { - params_refined.output = &task->output; - } - async_push_work_(work_function, ¶ms_refined); - return task; -} - -internal void * -async_task_join(ASYNC_Task *task) -{ - void *result = 0; - if(task != 0 && !MemoryIsZeroStruct(&task->semaphore)) - { - os_semaphore_take(task->semaphore, max_U64); - os_semaphore_release(task->semaphore); - MemoryZeroStruct(&task->semaphore); - result = (void *)ins_atomic_u64_eval(&task->output); - } - return result; -} - -//////////////////////////////// -//~ rjf: Work Execution - -internal ASYNC_Work -async_pop_work(void) -{ - ASYNC_Work work = {0}; - B32 done = 0; - ASYNC_Priority taken_priority = ASYNC_Priority_Low; - MutexScope(async_shared->ring_mutex) for(;!done;) - { - for(ASYNC_Priority priority = ASYNC_Priority_High;; priority = (ASYNC_Priority)(priority - 1)) - { - ASYNC_Ring *ring = &async_shared->rings[priority]; - MutexScope(ring->ring_mutex) - { - U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos; - if(unconsumed_size >= sizeof(work)) - { - ring->ring_read_pos += ring_read_struct(ring->ring_base, ring->ring_size, ring->ring_read_pos, &work); - done = 1; - taken_priority = priority; - } - } - if(done) - { - break; - } - if(priority == ASYNC_Priority_Low) - { - break; - } - } - if(!done) - { - cond_var_wait(async_shared->ring_cv, async_shared->ring_mutex, max_U64); - } - } - cond_var_broadcast(async_shared->ring_cv); - cond_var_broadcast(async_shared->rings[taken_priority].ring_cv); - return work; -} - -internal void -async_execute_work(ASYNC_Work work) -{ - //- rjf: run work - async_work_thread_depth += 1; - void *work_out = work.work_function(async_work_thread_idx, work.input); - async_work_thread_depth -= 1; - - //- rjf: store output - if(work.output != 0) - { - ins_atomic_u64_eval_assign((U64 *)work.output, (U64)work_out); - } - - //- rjf: release semaphore - if(!MemoryIsZeroStruct(&work.semaphore)) - { - os_semaphore_drop(work.semaphore); - } - - //- rjf: increment completion counter - if(work.completion_counter != 0) - { - ins_atomic_u64_inc_eval(work.completion_counter); - } - - //- rjf: decrement working counter - if(work.working_counter != 0) - { - ins_atomic_u64_dec_eval(work.working_counter); - } -} - -//////////////////////////////// -//~ rjf: Root Allocation/Deallocation - -internal ASYNC_Root * -async_root_alloc(void) -{ - Arena *arena = arena_alloc(); - ASYNC_Root *root = push_array(arena, ASYNC_Root, 1); - root->arenas = push_array(arena, Arena *, async_thread_count()); - root->arenas[0] = arena; - for(U64 idx = 1; idx < async_thread_count(); idx += 1) - { - root->arenas[idx] = arena_alloc(); - } - return root; -} - -internal void -async_root_release(ASYNC_Root *root) -{ - for(U64 idx = 1; idx < async_thread_count(); idx += 1) - { - arena_release(root->arenas[idx]); - } - arena_release(root->arenas[0]); -} - -internal Arena * -async_root_thread_arena(ASYNC_Root *root) -{ - return root->arenas[async_work_thread_idx]; -} - -//////////////////////////////// -//~ rjf: Work Thread Entry Point - -internal void -async_work_thread__entry_point(void *p) -{ - U64 thread_idx = (U64)p; - ThreadNameF("async_work_thread_%I64u", thread_idx); - async_work_thread_idx = thread_idx; - for(;;) - { - ASYNC_Work work = async_pop_work(); - ins_atomic_u64_inc_eval(&async_shared->work_threads_live_count); - async_execute_work(work); - ins_atomic_u64_dec_eval(&async_shared->work_threads_live_count); - } -} diff --git a/src/async/async.h b/src/async/async.h deleted file mode 100644 index cf905e5a..00000000 --- a/src/async/async.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef ASYNC_H -#define ASYNC_H - -//////////////////////////////// -//~ rjf: Work Function Type - -#define ASYNC_WORK_SIG(name) void *name(U64 thread_idx, void *input) -#define ASYNC_WORK_DEF(name) internal ASYNC_WORK_SIG(name) -typedef ASYNC_WORK_SIG(ASYNC_WorkFunctionType); - -//////////////////////////////// -//~ rjf: Work Types - -typedef enum ASYNC_Priority -{ - ASYNC_Priority_Low, - ASYNC_Priority_High, - ASYNC_Priority_COUNT -} -ASYNC_Priority; - -typedef struct ASYNC_WorkParams ASYNC_WorkParams; -struct ASYNC_WorkParams -{ - void *input; - void **output; - Semaphore semaphore; - U64 *completion_counter; - U64 *working_counter; - U64 endt_us; - ASYNC_Priority priority; -}; - -typedef struct ASYNC_Work ASYNC_Work; -struct ASYNC_Work -{ - ASYNC_WorkFunctionType *work_function; - void *input; - void **output; - Semaphore semaphore; - U64 *completion_counter; - U64 *working_counter; -}; - -//////////////////////////////// -//~ rjf: Task-Based Work Types - -typedef struct ASYNC_Task ASYNC_Task; -struct ASYNC_Task -{ - Semaphore semaphore; - void *output; -}; - -typedef struct ASYNC_TaskNode ASYNC_TaskNode; -struct ASYNC_TaskNode -{ - ASYNC_TaskNode *next; - ASYNC_Task *v; -}; - -typedef struct ASYNC_TaskList ASYNC_TaskList; -struct ASYNC_TaskList -{ - ASYNC_TaskNode *first; - ASYNC_TaskNode *last; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Root (Per-Worker-Thread Arena Bundle) - -typedef struct ASYNC_Root ASYNC_Root; -struct ASYNC_Root -{ - Arena **arenas; -}; - -//////////////////////////////// -//~ rjf: Shared State Bundle - -typedef struct ASYNC_Ring ASYNC_Ring; -struct ASYNC_Ring -{ - U64 ring_size; - U8 *ring_base; - U64 ring_write_pos; - U64 ring_read_pos; - Mutex ring_mutex; - CondVar ring_cv; -}; - -typedef struct ASYNC_Shared ASYNC_Shared; -struct ASYNC_Shared -{ - Arena *arena; - - // rjf: user -> work thread ring buffers - ASYNC_Ring rings[ASYNC_Priority_COUNT]; - Mutex ring_mutex; - CondVar ring_cv; - - // rjf: work threads - Thread *work_threads; - U64 work_threads_count; - U64 work_threads_live_count; -}; - -//////////////////////////////// -//~ rjf: Globals - -thread_static B32 async_work_thread_depth = 0; -thread_static U64 async_work_thread_idx = 0; -global ASYNC_Shared *async_shared = 0; - -//////////////////////////////// -//~ rjf: Top-Level Layer Initialization - -internal void async_init(CmdLine *cmdline); - -//////////////////////////////// -//~ rjf: Top-Level Accessors - -internal U64 async_thread_count(void); - -//////////////////////////////// -//~ rjf: Work Kickoffs - -internal B32 async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params); -#define async_push_work(function, ...) async_push_work_((function), &(ASYNC_WorkParams){.endt_us = max_U64, .priority = ASYNC_Priority_High, __VA_ARGS__}) - -//////////////////////////////// -//~ rjf: Task-Based Work Helper - -internal void async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t); -internal ASYNC_Task *async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params); -#define async_task_launch(arena, work_function, ...) async_task_launch_((arena), (work_function), &(ASYNC_WorkParams){.endt_us = max_U64, __VA_ARGS__}) -internal void *async_task_join(ASYNC_Task *task); -#define async_task_join_struct(task, T) (T *)async_task_join(task) - -//////////////////////////////// -//~ rjf: Work Execution - -internal ASYNC_Work async_pop_work(void); -internal void async_execute_work(ASYNC_Work work); - -//////////////////////////////// -//~ rjf: Root Allocation/Deallocation - -internal ASYNC_Root *async_root_alloc(void); -internal void async_root_release(ASYNC_Root *root); -internal Arena *async_root_thread_arena(ASYNC_Root *root); - -//////////////////////////////// -//~ rjf: Work Thread Entry Point - -internal void async_work_thread__entry_point(void *p); - -#endif // ASYNC_H diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index ddebe2e1..97fd4e2d 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -70,10 +70,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments) mtx_init(); #endif #if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL) - di_init(); -#endif -#if defined(DBG_INFO2_H) && !defined(DI_INIT_MANUAL) - di2_init(&cmdline); + di_init(&cmdline); #endif #if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) dmn_init(); @@ -211,8 +208,8 @@ async_thread_entry_point(void *params) #if defined(FILE_STREAM_H) fs_async_tick(); #endif -#if defined(DBG_INFO2_H) - di2_async_tick(); +#if defined(DBG_INFO_H) + di_async_tick(); #endif } diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index ae3c131b..5dbaaacd 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -786,11 +786,11 @@ ctrl_module_from_process_vaddr(CTRL_Entity *process, U64 vaddr) return result; } -internal DI2_Key +internal DI_Key ctrl_dbgi_key_from_module(CTRL_Entity *module) { CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - DI2_Key dbgi_key = di2_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp); + DI_Key dbgi_key = di_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp); return dbgi_key; } @@ -1176,15 +1176,15 @@ ctrl_entity_array_from_kind(CTRL_EntityCtx *ctx, CTRL_EntityKind kind) } internal CTRL_EntityList -ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI2_Key dbgi_key) +ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key dbgi_key) { CTRL_EntityList list = {0}; CTRL_EntityArray all_modules = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Module); for EachIndex(idx, all_modules.count) { CTRL_Entity *module = all_modules.v[idx]; - DI2_Key module_dbgi_key = ctrl_dbgi_key_from_module(module); - if(di2_key_match(module_dbgi_key, dbgi_key)) + DI_Key module_dbgi_key = ctrl_dbgi_key_from_module(module); + if(di_key_match(module_dbgi_key, dbgi_key)) { ctrl_entity_list_push(arena, &list, module); } @@ -2778,8 +2778,8 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas U64 rip_vaddr = regs_rip_from_arch_block(arch, src->regs); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); RDI_Scope *scope = rdi_scope_from_voff(rdi, rip_voff); // rjf: build inline frames (minus parent & inline depth) @@ -3188,16 +3188,16 @@ ctrl_thread__entry_point(void *p) String8 path = msg->path; CTRL_Entity *module = ctrl_entity_from_handle(entity_ctx, msg->entity); CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); - DI2_Key old_dbgi_key = di2_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp); - di2_close(old_dbgi_key); + DI_Key old_dbgi_key = di_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp); + di_close(old_dbgi_key); MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) { ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path_normalized_from_string(scratch.arena, path)); } U64 new_dbgi_timestamp = os_properties_from_file_path(path).modified; debug_info_path->timestamp = new_dbgi_timestamp; - DI2_Key new_dbgi_key = di2_key_from_path_timestamp(debug_info_path->string, new_dbgi_timestamp); - di2_open(new_dbgi_key); + DI_Key new_dbgi_key = di_key_from_path_timestamp(debug_info_path->string, new_dbgi_timestamp); + di_open(new_dbgi_key); CTRL_EventList evts = {0}; CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); evt->kind = CTRL_EventKind_ModuleDebugInfoPathChange; @@ -3266,8 +3266,8 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope * CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; CTRL_Entity *module_entity = ctrl_entity_from_handle(entity_ctx, module); CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module_entity); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module_entity); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); U64 base_vaddr = module_entity->vaddr_range.min; for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { @@ -3866,8 +3866,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, // rjf: determine base address of asan shadow space U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, max_U64); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, max_U64); RDI_NameMap *unparsed_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_GlobalVariables); { RDI_ParsedNameMap map = {0}; @@ -4078,8 +4078,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt2->parent = process_handle; out_evt2->timestamp = debug_info_timestamp; out_evt2->string = initial_debug_info_path; - DI2_Key initial_dbgi_key = di2_key_from_path_timestamp(initial_debug_info_path, debug_info_timestamp); - di2_open(initial_dbgi_key); + DI_Key initial_dbgi_key = di_key_from_path_timestamp(initial_debug_info_path, debug_info_timestamp); + di_open(initial_dbgi_key); }break; case DMN_EventKind_ExitProcess: { @@ -4111,8 +4111,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt->msg_id = msg->msg_id; out_evt->entity = module_handle; out_evt->string = module_path; - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module_ent); - di2_close(dbgi_key); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module_ent); + di_close(dbgi_key); }break; case DMN_EventKind_DebugString: { @@ -4289,10 +4289,10 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C mod = mod->next) { if(mod->kind != CTRL_EntityKind_Module) { continue; } - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(mod); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(mod); //- rjf: try to obtain this module's RDI - RDI_Parsed *rdi = di2_rdi_from_key(scope->access, dbgi_key, 0, 0); + RDI_Parsed *rdi = di_rdi_from_key(scope->access, dbgi_key, 0, 0); //- rjf: if this RDI is not yet ready => determine if we need to wait for it // @@ -4380,7 +4380,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C //- rjf: if this RDI is necessary, but we do not have it => wait for it forever if(rdi == &rdi_parsed_nil && rdi_is_necessary) ProfScope("RDI is necessary -> wait") { - rdi = di2_rdi_from_key(scope->access, dbgi_key, 1, max_U64); + rdi = di_rdi_from_key(scope->access, dbgi_key, 1, max_U64); } //- rjf: fill evaluation module info @@ -5200,8 +5200,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->process)); CTRL_Entity *module = ctrl_entity_child_from_kind(process, CTRL_EntityKind_Module); U64 module_base_vaddr = module->vaddr_range.min; - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, max_U64); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, max_U64); RDI_NameMap *unparsed_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures); RDI_ParsedNameMap map = {0}; rdi_parsed_from_name_map(rdi, unparsed_map, &map); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 36db33cd..60e0729f 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -845,7 +845,7 @@ internal CTRL_Entity *ctrl_entity_child_from_kind(CTRL_Entity *parent, CTRL_Enti internal CTRL_Entity *ctrl_entity_ancestor_from_kind(CTRL_Entity *entity, CTRL_EntityKind kind); internal CTRL_Entity *ctrl_process_from_entity(CTRL_Entity *entity); internal CTRL_Entity *ctrl_module_from_process_vaddr(CTRL_Entity *process, U64 vaddr); -internal DI2_Key ctrl_dbgi_key_from_module(CTRL_Entity *module); +internal DI_Key ctrl_dbgi_key_from_module(CTRL_Entity *module); internal CTRL_Entity *ctrl_module_from_thread_candidates(CTRL_EntityCtx *ctx, CTRL_Entity *thread, CTRL_EntityList *candidates); internal U64 ctrl_vaddr_from_voff(CTRL_Entity *module, U64 voff); internal U64 ctrl_voff_from_vaddr(CTRL_Entity *module, U64 vaddr); @@ -877,7 +877,7 @@ internal void ctrl_entity_equip_string(CTRL_EntityCtxRWStore *store, CTRL_Entity //- rjf: accelerated entity context lookups internal CTRL_EntityCtxLookupAccel *ctrl_thread_entity_ctx_lookup_accel(void); internal CTRL_EntityArray ctrl_entity_array_from_kind(CTRL_EntityCtx *ctx, CTRL_EntityKind kind); -internal CTRL_EntityList ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI2_Key dbgi_key); +internal CTRL_EntityList ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key dbgi_key); internal CTRL_Entity *ctrl_thread_from_id(CTRL_EntityCtx *ctx, U64 id); //- rjf: applying events to entity caches diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index 9895bd6a..6643359e 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -339,7 +339,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) U64 ip_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ip_vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); log_infof("ip_vaddr: 0x%I64x\n", ip_vaddr); log_infof("dbgi_key: {0x%I64x, 0x%I64x}\n", dbgi_key.u64[0], dbgi_key.u64[1]); @@ -502,7 +502,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) U64 ip_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ip_vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -585,7 +585,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) U64 jump_dest_vaddr = point->jump_dest_vaddr; CTRL_Entity *jump_dest_module = ctrl_module_from_process_vaddr(process, jump_dest_vaddr); U64 jump_dest_voff = ctrl_voff_from_vaddr(jump_dest_module, jump_dest_vaddr); - DI2_Key jump_dest_dbgi_key = ctrl_dbgi_key_from_module(jump_dest_module); + DI_Key jump_dest_dbgi_key = ctrl_dbgi_key_from_module(jump_dest_module); D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, jump_dest_dbgi_key, jump_dest_voff); if(lines.count == 0) { @@ -646,11 +646,11 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) //- rjf: voff -> line info internal D_LineList -d_lines_from_dbgi_key_voff(Arena *arena, DI2_Key dbgi_key, U64 voff) +d_lines_from_dbgi_key_voff(Arena *arena, DI_Key dbgi_key, U64 voff) { Temp scratch = scratch_begin(&arena, 1); Access *access = access_open(); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0); D_LineList result = {0}; { //- rjf: gather line tables @@ -739,13 +739,13 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI2_Key dbgi_key, U64 voff) // TODO(rjf): this depends on file path maps, needs to move internal D_LineListArray -d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI2_Key dbgi_key, String8 file_path, Rng1S64 line_num_range) +d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range) { D_LineListArray array = {0}; { array.count = dim_1s64(line_num_range)+1; array.v = push_array(arena, D_LineList, array.count); - di2_key_list_push(arena, &array.dbgi_keys, dbgi_key); + di_key_list_push(arena, &array.dbgi_keys, dbgi_key); } Temp scratch = scratch_begin(&arena, 1); U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count); @@ -759,7 +759,7 @@ d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI2_Key dbgi_key, String8 file_path_normalized = lower_from_str8(scratch.arena, path_normalized_from_string(scratch.arena, file_path)); // rjf: binary -> rdi - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; @@ -842,7 +842,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 } Temp scratch = scratch_begin(&arena, 1); U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count); - DI2_KeyArray dbgi_keys = di2_push_all_loaded_keys(scratch.arena); + DI_KeyArray dbgi_keys = di_push_all_loaded_keys(scratch.arena); String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path); for(String8Node *override_n = overrides.first; override_n != 0; @@ -855,8 +855,8 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 Access *access = access_open(); // rjf: binary -> rdi - DI2_Key key = dbgi_keys.v[idx]; - RDI_Parsed *rdi = di2_rdi_from_key(access, key, 1, 0); + DI_Key key = dbgi_keys.v[idx]; + RDI_Parsed *rdi = di_rdi_from_key(access, key, 1, 0); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; @@ -927,7 +927,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 // rjf: good src id -> push to relevant dbgi keys if(good_src_id) { - di2_key_list_push(arena, &array.dbgi_keys, key); + di_key_list_push(arena, &array.dbgi_keys, key); } access_close(access); @@ -938,7 +938,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 } internal D_LineList -d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI2_Key dbgi_key, String8 file_path, S64 line_num) +d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num) { D_LineListArray array = d_lines_array_from_dbgi_key_file_path_line_range(arena, dbgi_key, file_path, r1s64(line_num, line_num+1)); D_LineList list = {0}; @@ -1091,16 +1091,16 @@ d_ctrl_targets_running(void) //- rjf: active entity based queries -internal DI2_KeyList +internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena) { - DI2_KeyList dbgis = {0}; + DI_KeyList dbgis = {0}; CTRL_EntityArray modules = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Module); for EachIndex(idx, modules.count) { CTRL_Entity *module = modules.v[idx]; - DI2_Key key = ctrl_dbgi_key_from_module(module); - di2_key_list_push(arena, &dbgis, key); + DI_Key key = ctrl_dbgi_key_from_module(module); + di_key_list_push(arena, &dbgis, key); } return dbgis; } @@ -1187,7 +1187,7 @@ d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 ro } internal E_String2NumMap * -d_query_cached_locals_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) +d_query_cached_locals_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff) { ProfBeginFunction(); E_String2NumMap *map = &e_string2num_map_nil; @@ -1209,7 +1209,7 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) D_RunLocalsCacheNode *node = 0; for(D_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(di2_key_match(n->dbgi_key, dbgi_key) && n->voff == voff) + if(di_key_match(n->dbgi_key, dbgi_key) && n->voff == voff) { node = n; break; @@ -1218,7 +1218,7 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) if(node == 0) { Access *access = access_open(); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0); E_String2NumMap *map = e_push_locals_map_from_rdi_voff(cache->arena, rdi, voff); if(map->slots_count != 0) { @@ -1241,7 +1241,7 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) } internal E_String2NumMap * -d_query_cached_member_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) +d_query_cached_member_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff) { ProfBeginFunction(); E_String2NumMap *map = &e_string2num_map_nil; @@ -1263,7 +1263,7 @@ d_query_cached_member_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) D_RunLocalsCacheNode *node = 0; for(D_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(di2_key_match(n->dbgi_key, dbgi_key) && n->voff == voff) + if(di_key_match(n->dbgi_key, dbgi_key) && n->voff == voff) { node = n; break; @@ -1272,7 +1272,7 @@ d_query_cached_member_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff) if(node == 0) { Access *access = access_open(); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0); E_String2NumMap *map = e_push_member_map_from_rdi_voff(cache->arena, rdi, voff); if(map->slots_count != 0) { diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index d39e3237..1385e213 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -126,7 +126,7 @@ struct D_Line String8 file_path; TxtPt pt; Rng1U64 voff_range; - DI2_Key dbgi_key; + DI_Key dbgi_key; }; typedef struct D_LineNode D_LineNode; @@ -149,7 +149,7 @@ struct D_LineListArray { D_LineList *v; U64 count; - DI2_KeyList dbgi_keys; + DI_KeyList dbgi_keys; }; //////////////////////////////// @@ -248,7 +248,7 @@ typedef struct D_RunLocalsCacheNode D_RunLocalsCacheNode; struct D_RunLocalsCacheNode { D_RunLocalsCacheNode *hash_next; - DI2_Key dbgi_key; + DI_Key dbgi_key; U64 voff; E_String2NumMap *locals_map; }; @@ -366,14 +366,14 @@ internal CTRL_TrapList d_trap_net_from_thread__step_into_line(Arena *arena, CTRL //~ rjf: Debug Info Lookups //- rjf: voff -> line info -internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI2_Key dbgi_key, U64 voff); +internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key dbgi_key, U64 voff); //- rjf: file:line -> line info // TODO(rjf): this depends on file path maps, needs to move // TODO(rjf): need to clean this up & dedup -internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI2_Key dbgi_key, String8 file_path, Rng1S64 line_num_range); +internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range); internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range); -internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI2_Key dbgi_key, String8 file_path, S64 line_num); +internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num); internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num); //////////////////////////////// @@ -399,14 +399,14 @@ internal U64 d_ctrl_last_run_frame_idx(void); internal B32 d_ctrl_targets_running(void); //- rjf: active entity based queries -internal DI2_KeyList d_push_active_dbgi_key_list(Arena *arena); +internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena); //- rjf: per-run caches internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread); internal U64 d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count); internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr); -internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff); -internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI2_Key dbgi_key, U64 voff); +internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff); +internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff); //- rjf: top-level command dispatch internal void d_push_cmd(D_CmdKind kind, D_CmdParams *params); diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 07a10bd5..e6a42707 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -1,36 +1,8 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#undef LAYER_COLOR -#define LAYER_COLOR 0x7c4ce3ff - //////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 -di_hash_from_seed_string(U64 seed, String8 string, StringMatchFlags match_flags) -{ - U64 result = seed; - for(U64 i = 0; i < string.size; i += 1) - { - result = ((result << 5) + result) + ((match_flags & StringMatchFlag_CaseInsensitive) ? lower_from_char(string.str[i]) : string.str[i]); - } - return result; -} - -internal U64 -di_hash_from_string(String8 string, StringMatchFlags match_flags) -{ - U64 hash = di_hash_from_seed_string(5381, string, match_flags); - return hash; -} - -internal U64 -di_hash_from_key(DI_Key *k) -{ - U64 hash = di_hash_from_string(k->path, StringMatchFlag_CaseInsensitive); - return hash; -} +//~ rjf: Helpers internal DI_Key di_key_zero(void) @@ -40,34 +12,17 @@ di_key_zero(void) } internal B32 -di_key_match(DI_Key *a, DI_Key *b) +di_key_match(DI_Key a, DI_Key b) { - return (str8_match(a->path, b->path, StringMatchFlag_CaseInsensitive) && a->min_timestamp == b->min_timestamp); -} - -internal DI_Key -di_key_copy(Arena *arena, DI_Key *src) -{ - DI_Key dst = {0}; - MemoryCopyStruct(&dst, src); - dst.path = push_str8_copy(arena, src->path); - return dst; -} - -internal DI_Key -di_normalized_key_from_key(Arena *arena, DI_Key *src) -{ - ProfBeginFunction(); - DI_Key dst = {path_normalized_from_string(arena, src->path), src->min_timestamp}; - ProfEnd(); - return dst; + B32 result = MemoryMatchStruct(&a, &b); + return result; } internal void -di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key) +di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key key) { DI_KeyNode *n = push_array(arena, DI_KeyNode, 1); - MemoryCopyStruct(&n->v, key); + n->v = key; SLLQueuePush(list->first, list->last, n); list->count += 1; } @@ -77,946 +32,689 @@ di_key_array_from_list(Arena *arena, DI_KeyList *list) { DI_KeyArray array = {0}; array.count = list->count; - array.v = push_array_no_zero(arena, DI_Key, array.count); + array.v = push_array(arena, DI_Key, array.count); U64 idx = 0; - for(DI_KeyNode *n = list->first; n != 0; n = n->next, idx += 1) + for EachNode(n, DI_KeyNode, list->first) { - MemoryCopyStruct(&array.v[idx], &n->v); + array.v[idx] = n->v; + idx += 1; } return array; } -internal DI_KeyArray -di_key_array_copy(Arena *arena, DI_KeyArray *src) -{ - DI_KeyArray dst = {0}; - dst.count = src->count; - dst.v = push_array(arena, DI_Key, dst.count); - for EachIndex(idx, dst.count) - { - dst.v[idx] = di_key_copy(arena, &src->v[idx]); - } - return dst; -} - -internal DI_SearchParams -di_search_params_copy(Arena *arena, DI_SearchParams *src) -{ - DI_SearchParams dst = {0}; - MemoryCopyStruct(&dst, src); - dst.dbgi_keys = di_key_array_copy(arena, &dst.dbgi_keys); - return dst; -} - -internal U64 -di_hash_from_search_params(DI_SearchParams *params) -{ - U64 hash = 5381; - hash = di_hash_from_seed_string(hash, str8_struct(¶ms->target), 0); - for(U64 idx = 0; idx < params->dbgi_keys.count; idx += 1) - { - hash = di_hash_from_seed_string(hash, str8_struct(¶ms->dbgi_keys.v[idx].min_timestamp), 0); - hash = di_hash_from_seed_string(hash, params->dbgi_keys.v[idx].path, StringMatchFlag_CaseInsensitive); - } - return hash; -} - -internal void -di_search_item_chunk_list_concat_in_place(DI_SearchItemChunkList *dst, DI_SearchItemChunkList *to_push) -{ - if(dst->first && to_push->first) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - } - else if(dst->first == 0) - { - MemoryCopyStruct(dst, to_push); - } - MemoryZeroStruct(to_push); -} - -internal U64 -di_search_item_num_from_array_element_idx__linear_search(DI_SearchItemArray *array, U64 element_idx) -{ - U64 fuzzy_item_num = 0; - for(U64 idx = 0; idx < array->count; idx += 1) - { - if(array->v[idx].idx == element_idx) - { - fuzzy_item_num = idx+1; - break; - } - } - return fuzzy_item_num; -} - -internal String8 -di_search_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx) -{ - String8 result = {0}; - switch(target) - { - default:{}break; - case RDI_SectionKind_Procedures: - { - RDI_Procedure *proc = rdi_element_from_name_idx(rdi, Procedures, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case RDI_SectionKind_GlobalVariables: - { - RDI_GlobalVariable *gvar = rdi_element_from_name_idx(rdi, GlobalVariables, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case RDI_SectionKind_ThreadVariables: - { - RDI_ThreadVariable *tvar = rdi_element_from_name_idx(rdi, ThreadVariables, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case RDI_SectionKind_UDTs: - { - RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, element_idx); - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - } - return result; -} - //////////////////////////////// //~ rjf: Main Layer Initialization internal void -di_init(void) +di_init(CmdLine *cmdline) { Arena *arena = arena_alloc(); di_shared = push_array(arena, DI_Shared, 1); di_shared->arena = arena; + di_shared->key2path_slots_count = 4096; + di_shared->key2path_slots = push_array(arena, DI_KeySlot, di_shared->key2path_slots_count); + di_shared->key2path_stripes = stripe_array_alloc(arena); + di_shared->path2key_slots_count = 4096; + di_shared->path2key_slots = push_array(arena, DI_KeySlot, di_shared->path2key_slots_count); + di_shared->path2key_stripes = stripe_array_alloc(arena); di_shared->slots_count = 4096; di_shared->slots = push_array(arena, DI_Slot, di_shared->slots_count); - di_shared->stripes_count = Min(di_shared->slots_count, os_get_system_info()->logical_processor_count); - di_shared->stripes = push_array(arena, DI_Stripe, di_shared->stripes_count); - for(U64 idx = 0; idx < di_shared->stripes_count; idx += 1) + di_shared->stripes = stripe_array_alloc(arena); + for EachElement(idx, di_shared->req_batches) { - di_shared->stripes[idx].arena = arena_alloc(); - di_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); - di_shared->stripes[idx].cv = cond_var_alloc(); + di_shared->req_batches[idx].mutex = mutex_alloc(); + di_shared->req_batches[idx].arena = arena_alloc(); } - di_shared->search_slots_count = 512; - di_shared->search_slots = push_array(arena, DI_SearchSlot, di_shared->search_slots_count); - di_shared->search_stripes_count = Min(di_shared->search_slots_count, os_get_system_info()->logical_processor_count); - di_shared->search_stripes = push_array(arena, DI_SearchStripe, di_shared->search_stripes_count); - for(U64 idx = 0; idx < di_shared->search_stripes_count; idx += 1) + U64 signal_pid = 0; + String8 signal_pid_string = cmd_line_string(cmdline, str8_lit("signal_pid")); + B32 has_parent = 1; + if(!try_u64_from_str8_c_rules(signal_pid_string, &signal_pid)) { - di_shared->search_stripes[idx].arena = arena_alloc(); - di_shared->search_stripes[idx].rw_mutex = rw_mutex_alloc(); - di_shared->search_stripes[idx].cv = cond_var_alloc(); + has_parent = 0; + signal_pid = os_get_process_info()->pid; } - di_shared->u2p_ring_mutex = mutex_alloc(); - di_shared->u2p_ring_cv = cond_var_alloc(); - di_shared->u2p_ring_size = KB(64); - di_shared->u2p_ring_base = push_array_no_zero(arena, U8, di_shared->u2p_ring_size); - di_shared->p2u_ring_mutex = mutex_alloc(); - di_shared->p2u_ring_cv = cond_var_alloc(); - di_shared->p2u_ring_size = KB(64); - di_shared->p2u_ring_base = push_array_no_zero(arena, U8, di_shared->p2u_ring_size); - di_shared->search_threads_count = 1; - di_shared->search_threads = push_array(arena, DI_SearchThread, di_shared->search_threads_count); - for EachIndex(idx, di_shared->search_threads_count) + U64 signal_code = 0; + String8 signal_code_string = cmd_line_string(cmdline, str8_lit("signal_code")); + try_u64_from_str8_c_rules(signal_code_string, &signal_code); + di_shared->conversion_completion_code = signal_code; + di_shared->conversion_completion_lock_semaphore_name = str8f(arena, "conversion_completion_lock_pid_%I64u", signal_pid); + di_shared->conversion_completion_signal_semaphore_name = str8f(arena, "conversion_completion_signal_pid_%I64u", signal_pid); + di_shared->conversion_completion_shared_memory_name = str8f(arena, "conversion_completion_shared_memory_pid_%I64u", signal_pid); + if(has_parent) { - di_shared->search_threads[idx].ring_mutex = mutex_alloc(); - di_shared->search_threads[idx].ring_cv = cond_var_alloc(); - di_shared->search_threads[idx].ring_size = KB(64); - di_shared->search_threads[idx].ring_base = push_array_no_zero(arena, U8, di_shared->search_threads[idx].ring_size); - di_shared->search_threads[idx].thread = thread_launch(di_search_thread__entry_point, (void *)idx); - } - di_shared->search_evictor_thread = thread_launch(di_search_evictor_thread__entry_point, 0); -} - -//////////////////////////////// -//~ rjf: Scope Functions - -internal DI_Scope * -di_scope_open(void) -{ - if(di_tctx == 0) - { - Arena *arena = arena_alloc(); - di_tctx = push_array(arena, DI_TCTX, 1); - di_tctx->arena = arena; - } - DI_Scope *scope = di_tctx->free_scope; - if(scope != 0) - { - SLLStackPop(di_tctx->free_scope); + di_shared->conversion_completion_lock_semaphore = semaphore_open(di_shared->conversion_completion_lock_semaphore_name); + di_shared->conversion_completion_signal_semaphore = semaphore_open(di_shared->conversion_completion_signal_semaphore_name); + di_shared->conversion_completion_shared_memory = os_shared_memory_open(di_shared->conversion_completion_shared_memory_name); } else { - scope = push_array_no_zero(di_tctx->arena, DI_Scope, 1); + di_shared->conversion_completion_lock_semaphore = semaphore_alloc(1, 1, di_shared->conversion_completion_lock_semaphore_name); + di_shared->conversion_completion_signal_semaphore = semaphore_alloc(0, 65536, di_shared->conversion_completion_signal_semaphore_name); + di_shared->conversion_completion_shared_memory = os_shared_memory_alloc(KB(4), di_shared->conversion_completion_shared_memory_name); + di_shared->conversion_completion_signal_receiver_thread = thread_launch(di_conversion_completion_signal_receiver_thread_entry_point, 0); } - MemoryZeroStruct(scope); - DLLPushBack(di_tctx->first_scope, di_tctx->last_scope, scope); - return scope; -} - -internal void -di_scope_close(DI_Scope *scope) -{ - DLLRemove(di_tctx->first_scope, di_tctx->last_scope, scope); - for(DI_Touch *t = scope->first_touch, *next = 0; t != 0; t = next) - { - next = t->next; - if(t->node != 0) - { - ins_atomic_u64_dec_eval(&t->node->touch_count); - cond_var_broadcast(t->stripe->cv); - } - if(t->search_node != 0) - { - ins_atomic_u64_dec_eval(&t->search_node->scope_refcount); - cond_var_broadcast(t->search_stripe->cv); - } - SLLStackPush(di_tctx->free_touch, t); - } - SLLStackPush(di_tctx->free_scope, scope); -} - -internal void -di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Stripe *stripe, DI_Node *node) -{ - if(node != 0) - { - ins_atomic_u64_inc_eval(&node->touch_count); - } - DI_Touch *touch = di_tctx->free_touch; - if(touch != 0) - { - SLLStackPop(di_tctx->free_touch); - } - else - { - touch = push_array_no_zero(di_tctx->arena, DI_Touch, 1); - } - MemoryZeroStruct(touch); - SLLQueuePush(scope->first_touch, scope->last_touch, touch); - touch->node = node; - touch->stripe = stripe; -} - -internal void -di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchStripe *stripe, DI_SearchNode *node) -{ - if(node != 0) - { - ins_atomic_u64_inc_eval(&node->scope_refcount); - } - DI_Touch *touch = di_tctx->free_touch; - if(touch != 0) - { - SLLStackPop(di_tctx->free_touch); - } - else - { - touch = push_array_no_zero(di_tctx->arena, DI_Touch, 1); - } - MemoryZeroStruct(touch); - SLLQueuePush(scope->first_touch, scope->last_touch, touch); - touch->search_node = node; - touch->search_stripe = stripe; + di_shared->conversion_completion_shared_memory_base = (U64 *)os_shared_memory_view_open(di_shared->conversion_completion_shared_memory, r1u64(0, KB(4))); + di_shared->completion_mutex = mutex_alloc(); + di_shared->completion_arena = arena_alloc(); } //////////////////////////////// -//~ rjf: Per-Slot Functions +//~ rjf: Path * Timestamp Cache Submission & Lookup -internal DI_Node * -di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key) +internal DI_Key +di_key_from_path_timestamp(String8 path, U64 min_timestamp) { - ProfBeginFunction(); - DI_Node *node = 0; - StringMatchFlags match_flags = path_match_flags_from_os(OperatingSystem_CURRENT); - U64 most_recent_timestamp = max_U64; - for(DI_Node *n = slot->first; n != 0; n = n->next) - { - if(str8_match(n->key.path, key->path, match_flags) && - key->min_timestamp <= n->key.min_timestamp && - (n->key.min_timestamp - key->min_timestamp) <= most_recent_timestamp) - { - node = n; - most_recent_timestamp = (n->key.min_timestamp - key->min_timestamp); - } - } - ProfEnd(); - return node; -} - -//////////////////////////////// -//~ rjf: Per-Stripe Functions - -internal U64 -di_string_bucket_idx_from_string_size(U64 size) -{ - U64 size_rounded = u64_up_to_pow2(size+1); - size_rounded = ClampBot((1<<4), size_rounded); - U64 bucket_idx = 0; - switch(size_rounded) - { - case 1<<4: {bucket_idx = 0;}break; - case 1<<5: {bucket_idx = 1;}break; - case 1<<6: {bucket_idx = 2;}break; - case 1<<7: {bucket_idx = 3;}break; - case 1<<8: {bucket_idx = 4;}break; - case 1<<9: {bucket_idx = 5;}break; - case 1<<10:{bucket_idx = 6;}break; - default:{bucket_idx = ArrayCount(((DI_Stripe *)0)->free_string_chunks)-1;}break; - } - return bucket_idx; -} - -internal String8 -di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) -{ - if(string.size == 0) {return str8_zero();} - U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); - DI_StringChunkNode *node = stripe->free_string_chunks[bucket_idx]; + //- rjf: unpack key + U64 hash = u64_hash_from_str8(path); + U64 slot_idx = hash%di_shared->path2key_slots_count; + DI_KeySlot *slot = &di_shared->path2key_slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di_shared->path2key_stripes, slot_idx); - // rjf: pull from bucket free list - if(node != 0) + //- rjf: look up key, create if needed + DI_Key key = {0}; + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { - if(bucket_idx == ArrayCount(stripe->free_string_chunks)-1) + // rjf: look up node, with this write mode, to find existing key computation + B32 found = 0; + RWMutexScope(stripe->rw_mutex, write_mode) { - node = 0; - DI_StringChunkNode *prev = 0; - for(DI_StringChunkNode *n = stripe->free_string_chunks[bucket_idx]; - n != 0; - prev = n, n = n->next) + DI_KeyPathNode *node = 0; + for(DI_KeyPathNode *n = slot->first; n != 0; n = n->next) { - if(n->size >= string.size+1) + if(str8_match(n->path, path, 0) && min_timestamp <= n->min_timestamp) { - if(prev == 0) - { - stripe->free_string_chunks[bucket_idx] = n->next; - } - else - { - prev->next = n->next; - } + found = 1; node = n; + key = node->key; break; } } - } - else - { - SLLStackPop(stripe->free_string_chunks[bucket_idx]); - } - } - - // rjf: no found node -> allocate new - if(node == 0) - { - U64 chunk_size = 0; - if(bucket_idx < ArrayCount(stripe->free_string_chunks)-1) - { - chunk_size = 1<<(bucket_idx+4); - } - else - { - chunk_size = u64_up_to_pow2(string.size); - } - U8 *chunk_memory = push_array(stripe->arena, U8, chunk_size); - node = (DI_StringChunkNode *)chunk_memory; - } - - // rjf: fill string & return - String8 allocated_string = str8((U8 *)node, string.size); - MemoryCopy((U8 *)node, string.str, string.size); - return allocated_string; -} - -internal void -di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) -{ - if(string.size == 0) {return;} - U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); - DI_StringChunkNode *node = (DI_StringChunkNode *)string.str; - node->size = u64_up_to_pow2(string.size); - SLLStackPush(stripe->free_string_chunks[bucket_idx], node); -} - -//////////////////////////////// -//~ rjf: Key Opening/Closing - -internal void -di_open(DI_Key *key) -{ - Temp scratch = scratch_begin(0, 0); - if(key->path.size != 0) - { - U64 hash = di_hash_from_key(key); - U64 slot_idx = hash%di_shared->slots_count; - U64 stripe_idx = slot_idx%di_shared->stripes_count; - DI_Slot *slot = &di_shared->slots[slot_idx]; - DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - log_infof("open_debug_info: {\"%S\", 0x%I64x}\n", key->path, key->min_timestamp); - MutexScopeW(stripe->rw_mutex) - { - //- rjf: find existing node - DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key); - - //- rjf: allocate node if none exists; insert into slot - if(node == 0) + if(!found && write_mode) { - U64 current_timestamp = os_properties_from_file_path(key->path).modified; - if(current_timestamp == 0) - { - current_timestamp = key->min_timestamp; - } - node = stripe->free_node; - if(node != 0) - { - SLLStackPop(stripe->free_node); - } - else - { - node = push_array_no_zero(stripe->arena, DI_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, key->path); - node->key.path = path_stored; - node->key.min_timestamp = current_timestamp; - } - - //- rjf: increment node reference count - if(node != 0) - { - node->ref_count += 1; - if(node->ref_count == 1) - { - di_u2p_enqueue_key(key, max_U64); - ins_atomic_u64_eval_assign(&node->is_working, 1); - DeferLoop(rw_mutex_drop_w(stripe->rw_mutex), rw_mutex_take_w(stripe->rw_mutex)) - { - async_push_work(di_parse_work); - } - } - } - } - } - scratch_end(scratch); -} - -internal void -di_close(DI_Key *key) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - if(key->path.size != 0) - { - U64 hash = di_hash_from_key(key); - U64 slot_idx = hash%di_shared->slots_count; - U64 stripe_idx = slot_idx%di_shared->stripes_count; - DI_Slot *slot = &di_shared->slots[slot_idx]; - DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - log_infof("close_debug_info: {\"%S\", 0x%I64x}\n", key->path, key->min_timestamp); - MutexScopeW(stripe->rw_mutex) - { - //- rjf: find existing node - DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key); - - //- rjf: node exists -> decrement reference count; release - if(node != 0) - { - node->ref_count -= 1; - if(node->ref_count == 0) for(;;) - { - //- rjf: release - if(ins_atomic_u64_eval(&node->touch_count) == 0) - { - di_string_release__stripe_mutex_w_guarded(stripe, node->key.path); - if(node->file_base != 0) - { - os_file_map_view_close(node->file_map, node->file_base, r1u64(0, node->file_props.size)); - } - if(!os_handle_match(node->file_map, os_handle_zero())) - { - os_file_map_close(node->file_map); - } - if(!os_handle_match(node->file, os_handle_zero())) - { - os_file_close(node->file); - } - if(node->arena != 0) - { - arena_release(node->arena); - } - DLLRemove(slot->first, slot->last, node); - SLLStackPush(stripe->free_node, node); - break; - } - - //- rjf: wait for touch count / working marker to go to 0 - cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64); - } - } - } - } - ProfEnd(); - scratch_end(scratch); -} - -//////////////////////////////// -//~ rjf: Debug Info Cache Lookups - -internal RDI_Parsed * -di_rdi_from_key(DI_Scope *scope, DI_Key *key, B32 high_priority, U64 endt_us) -{ - ProfBeginFunction(); - RDI_Parsed *result = &rdi_parsed_nil; - if(key->path.size != 0) - { - Temp scratch = scratch_begin(0, 0); - U64 hash = di_hash_from_key(key); - U64 slot_idx = hash%di_shared->slots_count; - U64 stripe_idx = slot_idx%di_shared->stripes_count; - DI_Slot *slot = &di_shared->slots[slot_idx]; - DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - ProfScope("grab node") MutexScopeR(stripe->rw_mutex) for(;;) - { - //- rjf: find existing node - DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key); - - //- rjf: no node? this path is not opened - if(node == 0) - { - break; - } - - //- rjf: node refcount == 0? this node is being destroyed - if(node->ref_count == 0) - { - break; - } - - //- rjf: parse done -> touch, grab result - if(node != 0 && node->parse_done) - { - di_scope_touch_node__stripe_mutex_r_guarded(scope, stripe, node); - result = &node->rdi; - break; - } - - //- rjf: parse not done, not working -> ask for parse - if(node != 0 && - !node->parse_done && - !ins_atomic_u64_eval(&node->is_working) && - di_u2p_enqueue_key(key, endt_us)) - { - ProfScope("ask for parse") - { - ins_atomic_u64_eval_assign(&node->is_working, 1); - DeferLoop(rw_mutex_drop_r(stripe->rw_mutex), rw_mutex_take_r(stripe->rw_mutex)) - { - async_push_work(di_parse_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low); - } - } - } - - //- rjf: time expired -> break - if(os_now_microseconds() >= endt_us) - { - break; - } - - //- rjf: wait on this stripe - { - cond_var_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); - } - } - scratch_end(scratch); - } - ProfEnd(); - return result; -} - -//////////////////////////////// -//~ rjf: Search Cache Lookups - -internal DI_SearchItemArray -di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams *params, String8 query, U64 endt_us, B32 *stale_out) -{ - DI_SearchItemArray items = {0}; - { - U64 params_hash = di_hash_from_search_params(params); - U64 slot_idx = key.u64[0]%di_shared->search_slots_count; - U64 stripe_idx = slot_idx%di_shared->search_stripes_count; - DI_SearchSlot * slot = &di_shared->search_slots[slot_idx]; - DI_SearchStripe * stripe = &di_shared->search_stripes[stripe_idx]; - MutexScopeW(stripe->rw_mutex) for(;;) - { - // rjf: map key -> node - DI_SearchNode *node = 0; - for(DI_SearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - node = n; - break; - } - } - - // rjf: no node? -> allocate - if(node == 0) - { - node = stripe->free_node; + node = stripe->free; if(node) { - SLLStackPop(stripe->free_node); - MemoryZeroStruct(node); + stripe->free = node->next; } else { - node = push_array(stripe->arena, DI_SearchNode, 1); + node = push_array(stripe->arena, DI_KeyPathNode, 1); } - DLLPushBack(slot->first, slot->last, node); + node->path = str8_copy(stripe->arena, path); + node->min_timestamp = min_timestamp; node->key = key; - for(U64 idx = 0; idx < ArrayCount(node->buckets); idx += 1) + DLLPushBack(slot->first, slot->last, node); + } + } + + // rjf: found the key? abort + if(found) + { + break; + } + + // rjf: didn't find the key on our read lookup? compute the key before entering + // write mode + if(!found && !write_mode) + { + B32 made_key = 0; + + //- rjf: try to make key from file's contents + if(!made_key) + { + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path); + FileProperties props = os_properties_from_file(file); + if(min_timestamp <= props.modified) { - node->buckets[idx].arena = arena_alloc(); + //- rjf: PDB magic => use GUID for key + if(!made_key) + { + B32 is_pdb = 0; + if(!is_pdb) + { + read_only local_persist char msf_msf20_magic[] = "Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"; + U8 msf20_magic_maybe[sizeof(msf_msf20_magic)] = {0}; + os_file_read(file, r1u64(0, sizeof(msf20_magic_maybe)), msf20_magic_maybe); + if(MemoryMatch(msf20_magic_maybe, msf_msf20_magic, sizeof(msf20_magic_maybe))) + { + is_pdb = 1; + } + } + if(!is_pdb) + { + read_only local_persist char msf_msf70_magic[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"; + U8 msf70_magic_maybe[sizeof(msf_msf70_magic)] = {0}; + os_file_read(file, r1u64(0, sizeof(msf70_magic_maybe)), msf70_magic_maybe); + if(MemoryMatch(msf70_magic_maybe, msf_msf70_magic, sizeof(msf70_magic_maybe))) + { + is_pdb = 1; + } + } + if(is_pdb) + { + // TODO(rjf) + } + } + } + os_file_close(file); + } + + //- rjf: fallback: hash from path/timestamp + if(!made_key) + { + made_key = 1; + U128 hash = u128_hash_from_seed_str8(min_timestamp, path); + MemoryCopy(&key, &hash, Min(sizeof(hash), sizeof(key))); + } + + //- rjf: made key -> store in (key -> path/timestamp) table + if(made_key) + { + U64 key_hash = u64_hash_from_str8(str8_struct(&key)); + U64 key_slot_idx = key_hash%di_shared->key2path_slots_count; + DI_KeySlot *key_slot = &di_shared->key2path_slots[key_slot_idx]; + Stripe *key_stripe = stripe_from_slot_idx(&di_shared->key2path_stripes, key_slot_idx); + RWMutexScope(key_stripe->rw_mutex, 1) + { + DI_KeyPathNode *node = 0; + for EachNode(n, DI_KeyPathNode, key_slot->first) + { + if(di_key_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = key_stripe->free; + if(node != 0) + { + key_stripe->free = node->next; + } + else + { + node = push_array(key_stripe->arena, DI_KeyPathNode, 1); + } + DLLPushBack(key_slot->first, key_slot->last, node); + node->path = str8_copy(key_stripe->arena, path); + node->min_timestamp = min_timestamp; + node->key = key; + } } } - - // rjf: record update idx info - node->last_update_tick_idx = update_tick_idx(); - - // rjf: try to grab last valid results for this key/query; determine if stale - B32 params_stale = 1; - B32 query_stale = 1; - B32 results_stale = 1; - if(node->bucket_read_gen != 0) - { - di_scope_touch_search_node__stripe_mutex_r_guarded(scope, stripe, node); - items = node->items; - params_stale = (params_hash != node->buckets[node->bucket_read_gen%ArrayCount(node->buckets)].params_hash); - query_stale = !str8_match(query, node->buckets[node->bucket_read_gen%ArrayCount(node->buckets)].query, 0); - results_stale = (node->bucket_read_gen < node->bucket_write_gen); - } - if(stale_out != 0) - { - *stale_out = (params_stale || query_stale || results_stale); - } - - // rjf: if query or params stale -> request again - if((query_stale || params_stale) && node->bucket_read_gen <= node->bucket_write_gen && node->bucket_write_gen < node->bucket_read_gen + ArrayCount(node->buckets)-1) - { - node->bucket_write_gen += 1; - if(node->bucket_write_gen >= node->bucket_items_gen + ArrayCount(node->buckets)) - { - MemoryZeroStruct(&node->items); - MemoryZeroStruct(&items); - } - U64 new_bucket_idx = node->bucket_write_gen%ArrayCount(node->buckets); - arena_clear(node->buckets[new_bucket_idx].arena); - node->buckets[new_bucket_idx].query = push_str8_copy(node->buckets[new_bucket_idx].arena, query); - node->buckets[new_bucket_idx].params = di_search_params_copy(node->buckets[new_bucket_idx].arena, params); - node->buckets[new_bucket_idx].params_hash = params_hash; - di_u2s_enqueue_req(key, endt_us); - } - - // rjf: not stale, or timeout -> break - if((!query_stale && !params_stale && !results_stale) || os_now_microseconds() >= endt_us) - { - break; - } - - // rjf: no results, but have time to wait -> wait - cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, endt_us); } } - return items; + + return key; } //////////////////////////////// -//~ rjf: Parse Threads - -internal B32 -di_u2p_enqueue_key(DI_Key *key, U64 endt_us) -{ - B32 sent = 0; - MutexScope(di_shared->u2p_ring_mutex) for(;;) - { - U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; - U64 available_size = di_shared->u2p_ring_size - unconsumed_size; - U64 needed_size = sizeof(key->min_timestamp) + sizeof(key->path.size) + key->path.size; - if(available_size >= needed_size) - { - di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &key->min_timestamp); - di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &key->path.size); - di_shared->u2p_ring_write_pos += ring_write(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, key->path.str, key->path.size); - sent = 1; - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, endt_us); - } - if(sent) - { - cond_var_broadcast(di_shared->u2p_ring_cv); - } - return sent; -} +//~ rjf: Debug Info Opening / Closing internal void -di_u2p_dequeue_key(Arena *arena, DI_Key *out_key) +di_open(DI_Key key) { - MutexScope(di_shared->u2p_ring_mutex) for(;;) - { - U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; - if(unconsumed_size >= sizeof(out_key->path.size) + sizeof(out_key->min_timestamp)) - { - di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_key->min_timestamp); - di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_key->path.size); - out_key->path.str = push_array(arena, U8, out_key->path.size); - di_shared->u2p_ring_read_pos += ring_read(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_key->path.str, out_key->path.size); - break; - } - cond_var_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, max_U64); - } - cond_var_broadcast(di_shared->u2p_ring_cv); -} - -internal void -di_p2u_push_event(DI_Event *event) -{ - MutexScope(di_shared->p2u_ring_mutex) for(;;) - { - U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); - U64 available_size = di_shared->p2u_ring_size-unconsumed_size; - U64 needed_size = sizeof(event->kind) + sizeof(event->string.size) + event->string.size; - if(available_size >= needed_size) - { - di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->kind); - di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->string.size); - di_shared->p2u_ring_write_pos += ring_write(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, event->string.str, event->string.size); - break; - } - cond_var_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, max_U64); - } - cond_var_broadcast(di_shared->p2u_ring_cv); -} - -internal DI_EventList -di_p2u_pop_events(Arena *arena, U64 endt_us) -{ - DI_EventList events = {0}; - MutexScope(di_shared->p2u_ring_mutex) for(;;) - { - U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); - if(unconsumed_size >= sizeof(DI_EventKind) + sizeof(U64)) - { - DI_EventNode *n = push_array(arena, DI_EventNode, 1); - SLLQueuePush(events.first, events.last, n); - events.count += 1; - di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.kind); - di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.string.size); - n->v.string.str = push_array_no_zero(arena, U8, n->v.string.size); - di_shared->p2u_ring_read_pos += ring_read(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, n->v.string.str, n->v.string.size); - } - else if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, endt_us); - } - cond_var_broadcast(di_shared->p2u_ring_cv); - return events; -} - -ASYNC_WORK_DEF(di_parse_work) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - //////////////////////////// - //- rjf: grab next key - // - DI_Key key = {0}; - di_u2p_dequeue_key(scratch.arena, &key); - ProfBegin("di_parse_work: %.*s", str8_varg(key.path)); - String8 og_path = key.path; - U64 min_timestamp = key.min_timestamp; - - //////////////////////////// //- rjf: unpack key - // - U64 hash = di_hash_from_string(og_path, StringMatchFlag_CaseInsensitive); + U64 hash = u64_hash_from_str8(str8_struct(&key)); U64 slot_idx = hash%di_shared->slots_count; - U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; - DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + Stripe *stripe = stripe_from_slot_idx(&di_shared->stripes, slot_idx); - //////////////////////////// - //- rjf: open O.G. file (may or may not be RDI) - // - B32 og_format_is_known = 0; - B32 og_is_pe = 0; - B32 og_is_pdb = 0; - B32 og_is_elf = 0; - B32 og_is_rdi = 0; - FileProperties og_props = {0}; - ProfScope("analyze %.*s", str8_varg(og_path)) + //- rjf: bump this key's node's refcount; create if needed + B32 node_is_new = 0; + RWMutexScope(stripe->rw_mutex, 1) { - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, og_path); - OS_Handle file_map = os_file_map_open(OS_AccessFlag_Read, file); - FileProperties props = og_props = os_properties_from_file(file); - void *base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, props.size)); - String8 data = str8((U8 *)base, props.size); - if(!og_format_is_known) + DI_Node *node = 0; + for(DI_Node *n = slot->first; n != 0; n = n->next) { - String8 msf20_magic = str8_lit("Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"); - String8 msf70_magic = str8_lit("Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"); - String8 msfxx_magic = str8_lit("Microsoft C/C++"); - if((data.size >= msf20_magic.size && str8_match(data, msf20_magic, StringMatchFlag_RightSideSloppy)) || - (data.size >= msf70_magic.size && str8_match(data, msf70_magic, StringMatchFlag_RightSideSloppy)) || - (data.size >= msfxx_magic.size && str8_match(data, msfxx_magic, StringMatchFlag_RightSideSloppy))) + if(di_key_match(n->key, key)) { - og_format_is_known = 1; - og_is_pdb = 1; + node = n; + break; } } - if(!og_format_is_known) + if(node == 0) { - if(data.size >= 8 && *(U64 *)data.str == RDI_MAGIC_CONSTANT) + node_is_new = 1; + node = stripe->free; + if(node) { - og_format_is_known = 1; - og_is_rdi = 1; + stripe->free = node->next; } - } - if(!og_format_is_known) - { - if(data.size >= 4 && - data.str[0] == 0x7f && - data.str[1] == 'E' && - data.str[2] == 'L' && - data.str[3] == 'F') + else { - og_format_is_known = 1; - og_is_elf = 1; + node = push_array_no_zero(stripe->arena, DI_Node, 1); } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->key = key; + node->batch_request_counts[1] = 1; } - if(!og_format_is_known) - { - if(data.size >= 2 && *(U16 *)data.str == 0x5a4d) - { - og_format_is_known = 1; - og_is_pe = 1; - } - } - os_file_map_view_close(file_map, base, r1u64(0, props.size)); - os_file_map_close(file_map); - os_file_close(file); + node->refcount += 1; } - //////////////////////////// - //- rjf: given O.G. path & analysis, determine RDI path - // - String8 rdi_path = {0}; + //- rjf: if new, submit low-priority request to load this key + if(node_is_new) { - if(og_is_rdi) + DI_RequestBatch *batch = &di_shared->req_batches[1]; + MutexScope(batch->mutex) { - rdi_path = og_path; + DI_RequestNode *n = push_array(batch->arena, DI_RequestNode, 1); + SLLQueuePush(batch->first, batch->last, n); + n->v.key = key; + batch->count += 1; } - else if(og_format_is_known && og_is_pdb) + cond_var_broadcast(async_tick_start_cond_var); + ins_atomic_u32_eval_assign(&async_loop_again, 1); + } +} + +internal void +di_close(DI_Key key) +{ + //- rjf: unpack key + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di_shared->slots_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di_shared->stripes, slot_idx); + + //- rjf: decrement this key's node's refcount; remove if needed + B32 node_released = 0; + OS_Handle file = {0}; + OS_Handle file_map = {0}; + FileProperties file_props = {0}; + void *file_base = 0; + Arena *arena = 0; + RWMutexScope(stripe->rw_mutex, 1) + { + DI_Node *node = 0; + for(DI_Node *n = slot->first; n != 0; n = n->next) { - rdi_path = push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); + if(di_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) > 0) + { + node = n; + break; + } + } + if(node) + { + node->refcount -= 1; + if(node->refcount == 0) + { + for(;;) + { + if(access_pt_is_expired(&node->access_pt, .time = 0, .update_idxs = 0)) + { + node_released = 1; + DLLRemove(slot->first, slot->last, node); + node->next = stripe->free; + stripe->free = node; + file = node->file; + file_map = node->file_map; + file_props = node->file_props; + file_base = node->file_base; + arena = node->arena; + break; + } + cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64); + } + } } } - //////////////////////////// - //- rjf: check if rdi file is up-to-date - // - B32 rdi_file_is_up_to_date = 0; + //- rjf: release node's resources if needed + if(node_released) { - if(rdi_path.size != 0) ProfScope("check %.*s is up-to-date", str8_varg(rdi_path)) - { - FileProperties props = os_properties_from_file_path(rdi_path); - rdi_file_is_up_to_date = (props.modified > og_props.modified); - } - } - - //////////////////////////// - //- rjf: if raddbg file is up to date based on timestamp, check the - // encoding generation number & size, to see if we need to regenerate it - // regardless - // - if(rdi_file_is_up_to_date) ProfScope("check %.*s version matches our's", str8_varg(rdi_path)) - { - OS_Handle file = {0}; - OS_Handle file_map = {0}; - FileProperties file_props = {0}; - void *file_base = 0; - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, rdi_path); - file_map = os_file_map_open(OS_AccessFlag_Read, file); - file_props = os_properties_from_file(file); - file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); - if(sizeof(RDI_Header) <= file_props.size) - { - RDI_Header *header = (RDI_Header*)file_base; - if(header->encoding_version != RDI_ENCODING_VERSION) - { - rdi_file_is_up_to_date = 0; - } - } - else - { - rdi_file_is_up_to_date = 0; - } os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); os_file_map_close(file_map); os_file_close(file); - } - - //////////////////////////// - //- rjf: heuristically choose compression settings - // - B32 should_compress = 0; -#if 0 - if(og_dbg_props.size > MB(64)) - { - should_compress = 1; - } -#endif - - //////////////////////////// - //- rjf: rdi file not up-to-date? we need to generate it - // - if(!rdi_file_is_up_to_date) ProfScope("generate %.*s", str8_varg(rdi_path)) - { - if(og_is_pdb) + if(arena != 0) { - //- rjf: push conversion task begin event + arena_release(arena); + } + } +} + +//////////////////////////////// +//~ rjf: Debug Info Lookups + +internal U64 +di_load_gen(void) +{ + U64 result = ins_atomic_u64_eval(&di_shared->load_gen); + return result; +} + +internal DI_KeyArray +di_push_all_loaded_keys(Arena *arena) +{ + Temp scratch = scratch_begin(&arena, 1); + DI_KeyList list = {0}; + { + for EachIndex(slot_idx, di_shared->key2path_slots_count) + { + DI_KeySlot *slot = &di_shared->key2path_slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di_shared->key2path_stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 0) { - DI_Event event = {DI_EventKind_ConversionStarted}; - event.string = rdi_path; - di_p2u_push_event(&event); + for(DI_KeyPathNode *n = slot->first; n != 0; n = n->next) + { + DI_KeyNode *dst_n = push_array(scratch.arena, DI_KeyNode, 1); + SLLQueuePush(list.first, list.last, dst_n); + list.count += 1; + dst_n->v = n->key; + } + } + } + } + DI_KeyArray array = {0}; + array.count = list.count; + array.v = push_array(arena, DI_Key, array.count); + { + U64 idx = 0; + for EachNode(n, DI_KeyNode, list.first) + { + array.v[idx] = n->v; + idx += 1; + } + } + scratch_end(scratch); + return array; +} + +internal RDI_Parsed * +di_rdi_from_key(Access *access, DI_Key key, B32 high_priority, U64 endt_us) +{ + RDI_Parsed *rdi = &rdi_parsed_nil; + { + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di_shared->slots_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 0) for(;;) + { + // rjf: try to grab current results + B32 found = 0; + B32 need_hi_request = 0; + B32 grabbed = 0; + for(DI_Node *n = slot->first; n != 0; n = n->next) + { + if(di_key_match(n->key, key) && ins_atomic_u64_eval(&n->refcount) > 0) + { + found = 1; + if(high_priority && ins_atomic_u64_eval_cond_assign(&n->batch_request_counts[0], 1, 0) == 0) + { + need_hi_request = 1; + } + if(ins_atomic_u64_eval(&n->completion_count) > 0) + { + grabbed = 1; + rdi = &n->rdi; + access_touch(access, &n->access_pt, stripe->cv); + } + break; + } } - //- rjf: kick off process - OS_Handle process = {0}; + // rjf: push high-priority request if needed + if(need_hi_request) { + DI_RequestBatch *batch = &di_shared->req_batches[0]; + MutexScope(batch->mutex) + { + DI_RequestNode *n = push_array(batch->arena, DI_RequestNode, 1); + SLLQueuePush(batch->first, batch->last, n); + n->v.key = key; + batch->count += 1; + } + cond_var_broadcast(async_tick_start_cond_var); + ins_atomic_u32_eval_assign(&async_loop_again, 1); + ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1); + } + + // rjf: found current results, or out-of-time? abort + if(grabbed || os_now_microseconds() >= endt_us) + { + break; + } + + // rjf: wait on stripe change + cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 0, endt_us); + } + } + return rdi; +} + +//////////////////////////////// +//~ rjf: Asynchronous Tick + +internal void +di_async_tick(void) +{ + Temp scratch = scratch_begin(0, 0); + + ////////////////////////////// + //- rjf: do single-lane update: pop requests, update tasks, gather RDI paths to parse wide + // + typedef struct ParseTask ParseTask; + struct ParseTask + { + DI_Key key; + String8 rdi_path; + }; + ParseTask *parse_tasks = 0; + U64 parse_tasks_count = 0; + if(lane_idx() == 0) + { + typedef struct ParseTaskNode ParseTaskNode; + struct ParseTaskNode + { + ParseTaskNode *next; + ParseTask v; + }; + ParseTaskNode *first_parse_task = 0; + ParseTaskNode *last_parse_task = 0; + + //////////////////////////// + //- rjf: pop all requests, high priority first + // + DI_RequestNode *first_req = 0; + DI_RequestNode *last_req = 0; + for EachElement(idx, di_shared->req_batches) + { + DI_RequestBatch *b = &di_shared->req_batches[idx]; + MutexScope(b->mutex) + { + for EachNode(n, DI_RequestNode, b->first) + { + DI_RequestNode *n_copy = push_array(scratch.arena, DI_RequestNode, 1); + MemoryCopyStruct(&n_copy->v, &n->v); + SLLQueuePush(first_req, last_req, n_copy); + } + arena_clear(b->arena); + b->first = b->last = 0; + b->count = 0; + } + } + + //////////////////////////// + //- rjf: gather all completions + // + DI_LoadCompletion *first_completion = 0; + DI_LoadCompletion *last_completion = 0; + MutexScope(di_shared->completion_mutex) + { + for EachNode(c, DI_LoadCompletion, di_shared->first_completion) + { + DI_LoadCompletion *dst_c = push_array(scratch.arena, DI_LoadCompletion, 1); + SLLQueuePush(first_completion, last_completion, dst_c); + dst_c->code = c->code; + } + arena_clear(di_shared->completion_arena); + di_shared->first_completion = di_shared->last_completion = 0; + } + + //////////////////////////// + //- rjf: generate load tasks for all unique requests + // + for EachNode(n, DI_RequestNode, first_req) + { + // rjf: unpack request + DI_Key key = n->v.key; + + // rjf: determine if this request is a duplicate + B32 request_is_duplicate = 1; + { + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di_shared->slots_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 0) + { + for(DI_Node *n = slot->first; n != 0; n = n->next) + { + if(di_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) == 0) + { + request_is_duplicate = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) != 0); + break; + } + } + } + } + + // rjf: if not a duplicate, create new task + if(!request_is_duplicate) + { + DI_LoadTask *t = di_shared->free_load_task; + if(t) + { + SLLStackPop(di_shared->free_load_task); + } + else + { + t = push_array_no_zero(di_shared->arena, DI_LoadTask, 1); + } + MemoryZeroStruct(t); + DLLPushBack(di_shared->first_load_task, di_shared->last_load_task, t); + t->key = key; + } + } + + //////////////////////////// + //- rjf: update tasks: configure, launch if we can, & retire if we can + // + for(DI_LoadTask *t = di_shared->first_load_task, *next = 0; t != 0; t = next) + { + next = t->next; + + //- rjf: unpack key + DI_Key key = t->key; + U64 key_hash = u64_hash_from_str8(str8_struct(&key)); + U64 key_slot_idx = key_hash%di_shared->key2path_slots_count; + DI_KeySlot *key_slot = &di_shared->key2path_slots[key_slot_idx]; + Stripe *key_stripe = stripe_from_slot_idx(&di_shared->key2path_stripes, key_slot_idx); + + //- rjf: get key's O.G. path + String8 og_path = {0}; + U64 og_min_timestamp = 0; + RWMutexScope(key_stripe->rw_mutex, 0) + { + for(DI_KeyPathNode *n = key_slot->first; n != 0; n = n->next) + { + if(di_key_match(n->key, key)) + { + og_path = str8_copy(scratch.arena, n->path); + og_min_timestamp = n->min_timestamp; + break; + } + } + } + + //- rjf: analyze O.G. debug info + if(!t->og_analyzed) + { + t->og_analyzed = 1; + OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, og_path); + FileProperties props = os_properties_from_file(file); + t->og_size = props.size; + U64 rdi_magic_maybe = 0; + if(os_file_read_struct(file, 0, &rdi_magic_maybe) == 8 && + rdi_magic_maybe == RDI_MAGIC_CONSTANT) + { + t->og_is_rdi = 1; + } + os_file_close(file); + } + U64 og_size = t->og_size; + B32 og_is_rdi = t->og_is_rdi; + + //- rjf: compute key's RDI path + String8 rdi_path = {0}; + { + if(og_is_rdi) + { + rdi_path = og_path; + } + else + { + rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); + } + } + + //- rjf: determine if RDI is stale + if(!t->rdi_analyzed) + { + t->rdi_analyzed = 1; + OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, rdi_path); + FileProperties props = os_properties_from_file(file); + if(props.modified < og_min_timestamp) + { + t->rdi_is_stale = 1; + } + else + { + t->rdi_is_stale = 1; + RDI_Header header = {0}; + if(os_file_read_struct(file, 0, &header) == sizeof(header)) + { + t->rdi_is_stale = (header.encoding_version != RDI_ENCODING_VERSION); + } + } + os_file_close(file); + } + B32 rdi_is_stale = t->rdi_is_stale; + + //- rjf: calculate thread counts for conversion processes + if(!og_is_rdi && rdi_is_stale && t->thread_count == 0) + { + U64 thread_count = 1; + U64 max_thread_count = os_get_system_info()->logical_processor_count; + { + if(0){} + else if(og_size <= MB(4)) {thread_count = 1;} + else if(og_size <= MB(256)) {thread_count = max_thread_count/4;} + else if(og_size <= MB(512)) {thread_count = max_thread_count/3;} + else if(og_size <= GB(1)) {thread_count = max_thread_count/2;} + else {thread_count = max_thread_count;} + } + thread_count = Max(1, thread_count); + t->thread_count = thread_count; + } + + //- rjf: determine if there are threads available + B32 threads_available = 0; + { + U64 max_threads = os_get_system_info()->logical_processor_count*2; + U64 current_threads = di_shared->conversion_thread_count; + U64 needed_threads = (current_threads + t->thread_count); + threads_available = (max_threads >= needed_threads); + } + + //- rjf: launch conversion processes + if(threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI_LoadTaskStatus_Active) + { + B32 should_compress = 0; OS_ProcessLaunchParams params = {0}; params.path = os_get_process_info()->binary_path; params.inherit_env = 1; @@ -1031,813 +729,686 @@ ASYNC_WORK_DEF(di_parse_work) // str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--capture"); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--rdi"); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--out:%S", rdi_path); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--thread_count:%I64u", t->thread_count); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_pid:%I64u", (U64)os_get_process_info()->pid); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_code:%I64u", (U64)t); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "%S", og_path); - process = os_process_launch(¶ms); + ProfMsg("launch creation for %.*s", str8_varg(rdi_path)); + t->process = os_process_launch(¶ms); + t->status = DI_LoadTaskStatus_Active; + di_shared->conversion_process_count += 1; + di_shared->conversion_thread_count += t->thread_count; } - //- rjf: wait for process to complete + //- rjf: if active & process has completed, mark as done { - U64 start_wait_t = os_now_microseconds(); - for(;;) + U64 exit_code = 0; + if(t->status == DI_LoadTaskStatus_Active) { - B32 wait_done = os_process_join(process, os_now_microseconds()+1000, 0); - if(wait_done) + B32 task_is_done = 0; + for(DI_LoadCompletion *c = first_completion; c != 0; c = c->next) { - rdi_file_is_up_to_date = 1; - break; + if(c->code == (U64)t) + { + task_is_done = 1; + break; + } + } + if(!task_is_done) + { + task_is_done = os_process_join(t->process, 0, 0); + } + if(task_is_done) + { + t->status = DI_LoadTaskStatus_Done; + di_shared->conversion_process_count -= 1; + di_shared->conversion_thread_count -= t->thread_count; } } } - //- rjf: push conversion task end event + //- rjf: if the RDI for this task is not stale, then we're already done - mark this + // task as done & prepped for storing into the cache + if(!rdi_is_stale) { - DI_Event event = {DI_EventKind_ConversionEnded}; - event.string = rdi_path; - di_p2u_push_event(&event); + t->status = DI_LoadTaskStatus_Done; + } + + //- rjf: if the RDI for this task *is* stale, but the O.G. path is actually RDI, + // then we can't actually re-convert to produce a non-stale RDI. in this case, just + // mark as done. + if(rdi_is_stale && og_is_rdi) + { + t->status = DI_LoadTaskStatus_Done; + } + + //- rjf: if task is done, retire & recycle task; gather path to load + if(t->status == DI_LoadTaskStatus_Done) + { + DLLRemove(di_shared->first_load_task, di_shared->last_load_task, t); + SLLStackPush(di_shared->free_load_task, t); + ParseTaskNode *n = push_array(scratch.arena, ParseTaskNode, 1); + n->v.key = key; + n->v.rdi_path = rdi_path; + SLLQueuePush(first_parse_task, last_parse_task, n); + parse_tasks_count += 1; } } - else + + //////////////////////////// + //- rjf: join all parse tasks + // + parse_tasks = push_array(scratch.arena, ParseTask, parse_tasks_count); { - // NOTE(rjf): we cannot convert from this O.G. debug info format right now. - //- rjf: push conversion task failure event + U64 idx = 0; + for EachNode(n, ParseTaskNode, first_parse_task) { - DI_Event event = {DI_EventKind_ConversionFailureUnsupportedFormat}; - event.string = rdi_path; - di_p2u_push_event(&event); + parse_tasks[idx] = n->v; + idx += 1; } } } + lane_sync_u64(&parse_tasks, 0); + lane_sync_u64(&parse_tasks_count, 0); + lane_sync(); - //////////////////////////// - //- rjf: got task -> open file + ////////////////////////////// + //- rjf: do wide load of all prepped RDIs // - OS_Handle file = {0}; - OS_Handle file_map = {0}; - FileProperties file_props = {0}; - void *file_base = 0; + U64 parse_task_take_counter = 0; + U64 *parse_task_take_counter_ptr = 0; + if(lane_idx() == 0) { - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path); - file_map = os_file_map_open(OS_AccessFlag_Read, file); - file_props = os_properties_from_file(file); - file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); + parse_task_take_counter_ptr = &parse_task_take_counter; } - - //////////////////////////// - //- rjf: do initial parse of rdi - // - RDI_Parsed rdi_parsed_maybe_compressed = rdi_parsed_nil; + lane_sync_u64(&parse_task_take_counter_ptr, 0); { - RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); - (void)parse_status; - } - - //////////////////////////// - //- rjf: decompress & re-parse, if necessary - // - Arena *rdi_parsed_arena = 0; - RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed; - { - U64 decompressed_size = rdi_decompressed_size_from_parsed(&rdi_parsed_maybe_compressed); - if(decompressed_size > file_props.size) + for(;;) { - rdi_parsed_arena = arena_alloc(); - U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size); - rdi_decompress_parsed(decompressed_data, decompressed_size, &rdi_parsed_maybe_compressed); - RDI_ParseStatus parse_status = rdi_parse(decompressed_data, decompressed_size, &rdi_parsed); - (void)parse_status; - } - } - - //////////////////////////// - //- rjf: commit parsed info to cache - // - MutexScopeW(stripe->rw_mutex) - { - DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key); - if(node != 0) - { - node->is_working = 0; - node->file = file; - node->file_map = file_map; - node->file_base = file_base; - node->file_props = file_props; - node->arena = rdi_parsed_arena; - node->rdi = rdi_parsed; - node->parse_done = 1; - } - else - { - if(rdi_parsed_arena != 0) + //- rjf: take next task + U64 parse_task_idx = ins_atomic_u64_inc_eval(parse_task_take_counter_ptr) - 1; + if(parse_task_idx >= parse_tasks_count) { - arena_release(rdi_parsed_arena); + break; } - os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); - os_file_map_close(file_map); - os_file_close(file); + + //- rjf: unpack task + DI_Key key = parse_tasks[parse_task_idx].key; + String8 rdi_path = parse_tasks[parse_task_idx].rdi_path; + ProfBegin("parse %.*s", str8_varg(rdi_path)); + + //- rjf: open file + OS_Handle file = {0}; + OS_Handle file_map = {0}; + FileProperties file_props = {0}; + void *file_base = 0; + { + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path); + file_map = os_file_map_open(OS_AccessFlag_Read, file); + file_props = os_properties_from_file(file); + file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); + } + + //- rjf: do initial parse of rdi + RDI_Parsed rdi_parsed_maybe_compressed = rdi_parsed_nil; + { + RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); + (void)parse_status; + } + + //- rjf: decompress & re-parse, if necessary + Arena *rdi_parsed_arena = 0; + RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed; + { + U64 decompressed_size = rdi_decompressed_size_from_parsed(&rdi_parsed_maybe_compressed); + if(decompressed_size > file_props.size) + { + rdi_parsed_arena = arena_alloc(); + U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size); + rdi_decompress_parsed(decompressed_data, decompressed_size, &rdi_parsed_maybe_compressed); + RDI_ParseStatus parse_status = rdi_parse(decompressed_data, decompressed_size, &rdi_parsed); + (void)parse_status; + } + } + + //- rjf: commit parsed info to cache + { + ProfMsg("commit %.*s", str8_varg(rdi_path)); + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di_shared->slots_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 1) + { + DI_Node *node = 0; + for(DI_Node *n = slot->first; n != 0; n = n->next) + { + if(di_key_match(n->key, key)) + { + node = n; + break; + } + } + if(node) + { + node->file = file; + node->file_map = file_map; + node->file_props = file_props; + node->file_base = file_base; + node->arena = rdi_parsed_arena; + MemoryCopyStruct(&node->rdi, &rdi_parsed); + node->completion_count += 1; + node->working_count -= 1; + ins_atomic_u64_inc_eval(&di_shared->load_gen); + } + else + { + if(rdi_parsed_arena != 0) + { + arena_release(rdi_parsed_arena); + } + os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); + os_file_map_close(file_map); + os_file_close(file); + } + } + cond_var_broadcast(stripe->cv); + } + + ProfEnd(); } } - cond_var_broadcast(stripe->cv); + lane_sync(); scratch_end(scratch); - ProfEnd(); - ProfEnd(); - return 0; } //////////////////////////////// -//~ rjf: Search Threads +//~ rjf: Conversion Completion Signal Receiver Thread -internal B32 -di_u2s_enqueue_req(U128 key, U64 endt_us) +internal void +di_signal_completion(void) { - B32 result = 0; - U64 thread_idx = key.u64[0]%di_shared->search_threads_count; - DI_SearchThread *thread = &di_shared->search_threads[thread_idx]; - MutexScope(thread->ring_mutex) for(;;) - { - U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos; - U64 available_size = thread->ring_size - unconsumed_size; - if(available_size >= sizeof(key)) - { - result = 1; - thread->ring_write_pos += ring_write_struct(thread->ring_base, thread->ring_size, thread->ring_write_pos, &key); - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(thread->ring_cv, thread->ring_mutex, endt_us); - } - if(result) - { - cond_var_broadcast(thread->ring_cv); - } - return result; + semaphore_take(di_shared->conversion_completion_lock_semaphore, max_U64); + di_shared->conversion_completion_shared_memory_base[0] = di_shared->conversion_completion_code; + semaphore_drop(di_shared->conversion_completion_lock_semaphore); + semaphore_drop(di_shared->conversion_completion_signal_semaphore); } -internal U128 -di_u2s_dequeue_req(U64 thread_idx) +internal void +di_conversion_completion_signal_receiver_thread_entry_point(void *p) { - U128 key = {0}; - DI_SearchThread *thread = &di_shared->search_threads[thread_idx]; - MutexScope(thread->ring_mutex) for(;;) + ThreadNameF("di_conversion_completion_signal_receiver_thread"); + for(;;) { - U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos; - if(unconsumed_size >= sizeof(key)) + if(semaphore_take(di_shared->conversion_completion_signal_semaphore, max_U64)) { - thread->ring_read_pos += ring_read_struct(thread->ring_base, thread->ring_size, thread->ring_read_pos, &key); - break; + // rjf: get the next retired code + U64 retired_code = 0; + semaphore_take(di_shared->conversion_completion_lock_semaphore, max_U64); + retired_code = di_shared->conversion_completion_shared_memory_base[0]; + semaphore_drop(di_shared->conversion_completion_lock_semaphore); + + // rjf: push completion record + MutexScope(di_shared->completion_mutex) + { + DI_LoadCompletion *c = push_array(di_shared->completion_arena, DI_LoadCompletion, 1); + SLLQueuePush(di_shared->first_completion, di_shared->last_completion, c); + c->code = retired_code; + } + + // rjf: signal async system to resume + ProfMsg("signal conversion completion"); + ins_atomic_u32_eval_assign(&async_loop_again, 1); + ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1); + cond_var_broadcast(async_tick_start_cond_var); } - cond_var_wait(thread->ring_cv, thread->ring_mutex, max_U64); } - cond_var_broadcast(thread->ring_cv); - return key; } -typedef struct DI_SearchWorkIn DI_SearchWorkIn; -struct DI_SearchWorkIn -{ - U128 key; - U64 initial_bucket_write_gen; - Arena **work_thread_arenas; - RDI_Parsed *rdi; - RDI_SectionKind section_kind; - Rng1U64 element_range; - String8 query; - U64 dbgi_idx; -}; -typedef struct DI_SearchWorkOut DI_SearchWorkOut; -struct DI_SearchWorkOut -{ - B32 cancelled; - DI_SearchItemChunkList items; -}; -ASYNC_WORK_DEF(di_search_work) +//////////////////////////////// +//~ rjf: Search Artifact Cache Hooks / Lookups + +internal AC_Artifact +di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); - - //- rjf: unpack parameters - DI_SearchWorkIn *in = (DI_SearchWorkIn *)input; - if(in->work_thread_arenas[thread_idx] == 0) + Access *access = access_open(); + Temp scratch = scratch_begin(0, 0); + AC_Artifact artifact = {0}; { - in->work_thread_arenas[thread_idx] = arena_alloc(); - } - Arena *arena = in->work_thread_arenas[thread_idx]; - U128 key = in->key; - U64 slot_idx = key.u64[0]%di_shared->search_slots_count; - U64 stripe_idx = slot_idx%di_shared->search_stripes_count; - DI_SearchSlot * slot = &di_shared->search_slots[slot_idx]; - DI_SearchStripe * stripe = &di_shared->search_stripes[stripe_idx]; - - //- rjf: setup output - DI_SearchWorkOut *out = push_array(arena, DI_SearchWorkOut, 1); - - //- rjf: unpack table info - U64 element_count = 0; - void *table_base = rdi_section_raw_table_from_kind(in->rdi, in->section_kind, &element_count); - U64 element_size = rdi_section_element_size_table[in->section_kind]; - - //- rjf: determine name string index offset, depending on table kind - U64 element_name_idx_off = 0; - switch(in->section_kind) - { - default:{}break; - case RDI_SectionKind_Procedures: + //- rjf: unpack key + RDI_SectionKind section_kind = RDI_SectionKind_NULL; + String8 query = {0}; { - element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); - }break; - case RDI_SectionKind_GlobalVariables: + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, §ion_kind); + key_read_off += str8_deserial_read_struct(key, key_read_off, &query.size); + query.str = push_array(scratch.arena, U8, query.size); + key_read_off += str8_deserial_read(key, key_read_off, query.str, query.size, 1); + } + + //- rjf: gather all debug info keys we'll search on + DI_KeyArray keys = {0}; + ProfScope("gather all debug info keys we'll search on") { - element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); - }break; - case RDI_SectionKind_ThreadVariables: - { - element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); - }break; - case RDI_SectionKind_UDTs: - { - // NOTE(rjf): name must be determined from self_type_idx - }break; - case RDI_SectionKind_SourceFiles: - { - // NOTE(rjf): name must be determined from file path node chain - }break; - } - - //- rjf: loop through table, gather matches - B32 cancelled = 0; - for(U64 idx = in->element_range.min; (idx < in->element_range.max && idx < element_count); idx += 1) - { - //- rjf: every so often, check the key's write gen - if it has been bumped, then cancel - if(idx%100 == 0) - { - MutexScopeR(stripe->rw_mutex) + if(lane_idx() == 0) { - for(DI_SearchNode *n = slot->first; n != 0; n = n->next) + keys = di_push_all_loaded_keys(scratch.arena); + } + lane_sync_u64(&keys.v, 0); + lane_sync_u64(&keys.count, 0); + } + + //- rjf: map all debug info keys -> RDIs + RDI_Parsed **rdis = 0; + ProfScope("map all debug info keys -> RDIs") + { + if(lane_idx() == 0) + { + rdis = push_array(scratch.arena, RDI_Parsed *, keys.count); + } + lane_sync_u64(&rdis, 0); + { + Rng1U64 range = lane_range(keys.count); + for EachInRange(idx, range) { - if(u128_match(n->key, key) && n->bucket_write_gen != in->initial_bucket_write_gen) + rdis[idx] = di_rdi_from_key(access, keys.v[idx], 0, 0); + } + } + } + lane_sync(); + + //- rjf: do wide search on all lanes + Arena *arena = arena_alloc(); + DI_SearchItemChunkList *lanes_items = 0; + ProfScope("do wide search on all lanes") + { + if(lane_idx() == 0) + { + lanes_items = push_array(scratch.arena, DI_SearchItemChunkList, lane_count()); + } + lane_sync_u64(&lanes_items, 0); + { + DI_SearchItemChunkList *lane_items = &lanes_items[lane_idx()]; + for EachIndex(rdi_idx, keys.count) + { + DI_Key key = keys.v[rdi_idx]; + RDI_Parsed *rdi = rdis[rdi_idx]; + + // rjf: unpack table info + U64 element_count = 0; + void *table_base = rdi_section_raw_table_from_kind(rdi, section_kind, &element_count); + U64 element_size = rdi_section_element_size_table[section_kind]; + + // rjf: determine name string index offset, depending on table kind + U64 element_name_idx_off = 0; + switch(section_kind) { - cancelled = 1; - break; + default:{}break; + case RDI_SectionKind_Procedures: + { + element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); + }break; + case RDI_SectionKind_GlobalVariables: + { + element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); + }break; + case RDI_SectionKind_ThreadVariables: + { + element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); + }break; + case RDI_SectionKind_UDTs: + { + // NOTE(rjf): name must be determined from self_type_idx + }break; + case RDI_SectionKind_SourceFiles: + { + // NOTE(rjf): name must be determined from file path node chain + }break; + } + + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) + { + //- rjf: every so often, check if we need to cancel, and cancel + { + // TODO(rjf) + } + + //- rjf: get element, map to string; if empty, continue to next element + void *element = (U8 *)table_base + element_size*idx; + String8 name = {0}; + switch(section_kind) + { + case RDI_SectionKind_UDTs: + { + RDI_UDT *udt = (RDI_UDT *)element; + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); + name.str = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name.size); + name = str8_copy(arena, name); + }break; + case RDI_SectionKind_SourceFiles: + { + Temp scratch = scratch_begin(&arena, 1); + RDI_SourceFile *file = (RDI_SourceFile *)element; + String8List path_parts = {0}; + for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, file->file_path_node_idx); + fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0); + fpn = rdi_element_from_name_idx(rdi, FilePathNodes, fpn->parent_path_node)) + { + String8 path_part = {0}; + path_part.str = rdi_string_from_idx(rdi, fpn->name_string_idx, &path_part.size); + str8_list_push_front(scratch.arena, &path_parts, path_part); + } + StringJoin join = {0}; + join.sep = str8_lit("/"); + name = str8_list_join(arena, &path_parts, &join); + scratch_end(scratch); + }break; + default: + { + U32 name_idx = *(U32 *)((U8 *)element + element_name_idx_off); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); + name = str8(name_base, name_size); + }break; + } + if(name.size == 0) { continue; } + + //- rjf: fuzzy match against query + FuzzyMatchRangeList matches = fuzzy_match_find(arena, query, name); + + //- rjf: collect + if(matches.count == matches.needle_part_count) + { + DI_SearchItemChunk *chunk = lane_items->last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(scratch.arena, DI_SearchItemChunk, 1); + chunk->base_idx = lane_items->total_count; + chunk->cap = 1024; + chunk->count = 0; + chunk->v = push_array_no_zero(scratch.arena, DI_SearchItem, chunk->cap); + SLLQueuePush(lane_items->first, lane_items->last, chunk); + lane_items->chunk_count += 1; + } + chunk->v[chunk->count].idx = idx; + chunk->v[chunk->count].key = key; + chunk->v[chunk->count].match_ranges = matches; + chunk->v[chunk->count].missed_size = (name.size > matches.total_dim) ? (name.size-matches.total_dim) : 0; + chunk->count += 1; + lane_items->total_count += 1; + } } } } } - if(cancelled) - { - break; - } + lane_sync(); - //- rjf: get element, map to string; if empty, continue to next element - void *element = (U8 *)table_base + element_size*idx; - String8 name = {0}; - switch(in->section_kind) + //- rjf: join all lane chunk lists + DI_SearchItemChunkList *all_items = &lanes_items[0]; + if(lane_idx() == 0) ProfScope("join all lane chunk lists") { - case RDI_SectionKind_UDTs: + for(U64 lidx = 1; lidx < lane_count(); lidx += 1) { - RDI_UDT *udt = (RDI_UDT *)element; - RDI_TypeNode *type_node = rdi_element_from_name_idx(in->rdi, TypeNodes, udt->self_type_idx); - name.str = rdi_string_from_idx(in->rdi, type_node->user_defined.name_string_idx, &name.size); - name = str8_copy(arena, name); - }break; - case RDI_SectionKind_SourceFiles: - { - Temp scratch = scratch_begin(&arena, 1); - RDI_SourceFile *file = (RDI_SourceFile *)element; - String8List path_parts = {0}; - for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(in->rdi, FilePathNodes, file->file_path_node_idx); - fpn != rdi_element_from_name_idx(in->rdi, FilePathNodes, 0); - fpn = rdi_element_from_name_idx(in->rdi, FilePathNodes, fpn->parent_path_node)) + DI_SearchItemChunkList *dst = all_items; + DI_SearchItemChunkList *to_push = &lanes_items[lidx]; + for EachNode(n, DI_SearchItemChunk, to_push->first) { - String8 path_part = {0}; - path_part.str = rdi_string_from_idx(in->rdi, fpn->name_string_idx, &path_part.size); - str8_list_push_front(scratch.arena, &path_parts, path_part); + n->base_idx += dst->total_count; } - StringJoin join = {0}; - join.sep = str8_lit("/"); - name = str8_list_join(arena, &path_parts, &join); - scratch_end(scratch); - }break; - default: - { - U32 name_idx = *(U32 *)((U8 *)element + element_name_idx_off); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(in->rdi, name_idx, &name_size); - name = str8(name_base, name_size); - }break; - } - if(name.size == 0) { continue; } - - //- rjf: fuzzy match against query - FuzzyMatchRangeList matches = fuzzy_match_find(arena, in->query, name); - - //- rjf: collect - if(matches.count == matches.needle_part_count) - { - DI_SearchItemChunk *chunk = out->items.last; - if(chunk == 0 || chunk->count >= chunk->cap) - { - chunk = push_array(arena, DI_SearchItemChunk, 1); - chunk->cap = 1024; - chunk->count = 0; - chunk->v = push_array_no_zero(arena, DI_SearchItem, chunk->cap); - SLLQueuePush(out->items.first, out->items.last, chunk); - out->items.chunk_count += 1; + if(dst->first && to_push->first) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + MemoryCopyStruct(dst, to_push); + } + MemoryZeroStruct(to_push); } - chunk->v[chunk->count].idx = idx; - chunk->v[chunk->count].dbgi_idx = in->dbgi_idx; - chunk->v[chunk->count].match_ranges = matches; - chunk->v[chunk->count].missed_size = (name.size > matches.total_dim) ? (name.size-matches.total_dim) : 0; - chunk->count += 1; - out->items.total_count += 1; } + lane_sync(); + + //- rjf: produce sort records + typedef struct SortRecord SortRecord; + struct SortRecord + { + U64 key; + DI_SearchItem *item; + }; + U64 sort_records_count = all_items->total_count; + SortRecord *sort_records = 0; + SortRecord *sort_records__swap = 0; + ProfScope("produce sort records") + { + if(lane_idx() == 0) + { + sort_records = push_array(scratch.arena, SortRecord, sort_records_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + sort_records__swap = push_array(scratch.arena, SortRecord, sort_records_count); + } + lane_sync_u64(&sort_records, 0); + lane_sync_u64(&sort_records__swap, lane_from_task_idx(1)); + for EachNode(n, DI_SearchItemChunk, all_items->first) + { + Rng1U64 range = lane_range(n->count); + U64 dst_idx = n->base_idx + range.min; + for EachInRange(n_idx, range) + { + DI_SearchItem *item = &n->v[n_idx]; + sort_records[dst_idx].item = item; + sort_records[dst_idx].key = (((item->missed_size & 0xffffffffull) << 32) | (u64_hash_from_seed_str8(item->idx, str8_struct(&key)) & 0xffffffffull)); + dst_idx += 1; + } + } + } + lane_sync(); + + //- rjf: sort records + ProfScope("sort records") + { + //- rjf: set up common data + U64 bits_per_digit = 8; + U64 digits_count = 64 / bits_per_digit; + U64 num_possible_values_per_digit = 1 << bits_per_digit; + U32 **lanes_digit_counts = 0; + U32 **lanes_digit_offsets = 0; + if(lane_idx() == 0) + { + lanes_digit_counts = push_array(scratch.arena, U32 *, lane_count()); + lanes_digit_offsets = push_array(scratch.arena, U32 *, lane_count()); + } + lane_sync_u64(&lanes_digit_counts, 0); + lane_sync_u64(&lanes_digit_offsets, 0); + + //- rjf: set up this lane + lanes_digit_counts[lane_idx()] = push_array(scratch.arena, U32, num_possible_values_per_digit); + lanes_digit_offsets[lane_idx()] = push_array(scratch.arena, U32, num_possible_values_per_digit); + SortRecord *src = sort_records; + SortRecord *dst = sort_records__swap; + U64 count = sort_records_count; + + //- rjf: do all per-digit sorts + for EachIndex(digit_idx, digits_count) + { + // rjf: count digit value occurrences per-lane + { + U32 *digit_counts = lanes_digit_counts[lane_idx()]; + MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) + { + SortRecord *r = &src[idx]; + U16 digit_value = (U16)(U8)(r->key >> (digit_idx*bits_per_digit)); + digit_counts[digit_value] += 1; + } + } + lane_sync(); + + // rjf: compute thread * digit value *relative* offset table + { + Rng1U64 range = lane_range(num_possible_values_per_digit); + for EachInRange(value_idx, range) + { + U64 layout_off = 0; + for EachIndex(lane_idx, lane_count()) + { + lanes_digit_offsets[lane_idx][value_idx] = layout_off; + layout_off += lanes_digit_counts[lane_idx][value_idx]; + } + } + } + lane_sync(); + + // rjf: convert relative offsets -> absolute offsets + if(lane_idx() == 0) + { + U64 last_off = 0; + U64 num_of_nonzero_digit = 0; + for EachIndex(value_idx, num_possible_values_per_digit) + { + for EachIndex(lane_idx, lane_count()) + { + lanes_digit_offsets[lane_idx][value_idx] += last_off; + } + last_off = lanes_digit_offsets[lane_count()-1][value_idx] + lanes_digit_counts[lane_count()-1][value_idx]; + } + // NOTE(rjf): required that: (last_off == element_count) + } + lane_sync(); + + // rjf: move + { + U32 *lane_digit_offsets = lanes_digit_offsets[lane_idx()]; + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) + { + SortRecord *src_r = &src[idx]; + U16 digit_value = (U16)(U8)(src_r->key >> (digit_idx*bits_per_digit)); + U64 dst_off = lane_digit_offsets[digit_value]; + lane_digit_offsets[digit_value] += 1; + MemoryCopyStruct(&dst[dst_off], src_r); + } + } + lane_sync(); + + // rjf: swap + { + SortRecord *swap = src; + src = dst; + dst = swap; + } + } + } + lane_sync(); + + //- rjf: produce final array + DI_SearchItemArray items = {0}; + ProfScope("produce final array") + { + if(lane_idx() == 0) + { + items.count = all_items->total_count; + items.v = push_array(arena, DI_SearchItem, items.count); + } + lane_sync_u64(&items.count, 0); + lane_sync_u64(&items.v, 0); + Rng1U64 range = lane_range(sort_records_count); + for EachInRange(idx, range) + { + SortRecord *record = &sort_records[idx]; + DI_SearchItem *dst_item = &items.v[idx]; + MemoryCopyStruct(dst_item, record->item); + } + } + lane_sync(); + + //- rjf: bundle as artifact + artifact.u64[0] = (U64)arena; + artifact.u64[1] = (U64)items.v; + artifact.u64[2] = items.count; } - out->cancelled = cancelled; + scratch_end(scratch); + access_close(access); ProfEnd(); - return out; -} - -internal int -di_qsort_compare_search_items(DI_SearchItem *a, DI_SearchItem *b) -{ - int result = 0; - if(a->match_ranges.count > b->match_ranges.count) - { - result = -1; - } - else if(a->match_ranges.count < b->match_ranges.count) - { - result = +1; - } - else if(a->missed_size < b->missed_size) - { - result = -1; - } - else if(a->missed_size > b->missed_size) - { - result = +1; - } - return result; + return artifact; } internal void -di_search_thread__entry_point(void *p) +di_search_artifact_destroy(AC_Artifact artifact) { - U64 thread_idx = (U64)p; - ThreadNameF("di_search_thread_%I64u", thread_idx); - for(;;) + Arena *arena = (Arena *)artifact.u64[0]; + if(arena != 0) + { + arena_release(arena); + } +} + +internal DI_SearchItemArray +di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us) +{ + DI_SearchItemArray result = {0}; { Temp scratch = scratch_begin(0, 0); - //- rjf: get next key, unpack - U128 key = di_u2s_dequeue_req(thread_idx); - U64 slot_idx = key.u64[0]%di_shared->search_slots_count; - U64 stripe_idx = slot_idx%di_shared->search_stripes_count; - DI_SearchSlot * slot = &di_shared->search_slots[slot_idx]; - DI_SearchStripe * stripe = &di_shared->search_stripes[stripe_idx]; + // rjf: form key + String8List key_parts = {0}; + str8_list_push(scratch.arena, &key_parts, str8_struct(&target)); + str8_list_push(scratch.arena, &key_parts, str8_struct(&query.size)); + str8_list_push(scratch.arena, &key_parts, query); + String8 key = str8_list_join(scratch.arena, &key_parts, 0); - //- rjf: map key -> output arena & search parameters - Arena *arena = 0; - String8 query = {0}; - DI_SearchParams params = {0}; - U64 initial_bucket_write_gen = 0; - MutexScopeW(stripe->rw_mutex) - { - for(DI_SearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - U64 bucket_idx = n->bucket_write_gen%ArrayCount(n->buckets); - n->work_refcount += 1; - arena = n->buckets[bucket_idx].arena; - query = push_str8_copy(scratch.arena, n->buckets[bucket_idx].query); - params = di_search_params_copy(scratch.arena, &n->buckets[bucket_idx].params); - initial_bucket_write_gen = n->bucket_write_gen; - break; - } - } - } + // rjf: get artifact + AC_Artifact artifact = ac_artifact_from_key(access, key, di_search_artifact_create, di_search_artifact_destroy, endt_us, .gen = di_load_gen(), .flags = AC_Flag_Wide); - //- rjf: begin debug info scope - DI_Scope *di_scope = di_scope_open(); - - //- rjf: get all rdis - U64 rdis_count = params.dbgi_keys.count; - RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); - for EachIndex(idx, rdis_count) - { - rdis[idx] = di_rdi_from_key(di_scope, ¶ms.dbgi_keys.v[idx], 1, max_U64); - } - - //- rjf: kick off search tasks - ASYNC_TaskList tasks = {0}; - Arena **work_thread_arenas = 0; - if(arena != 0) - { - U64 elements_per_task = 16384; - work_thread_arenas = push_array(arena, Arena *, async_thread_count()); - for EachIndex(idx, rdis_count) - { - RDI_Parsed *rdi = rdis[idx]; - U64 element_count_in_this_rdi = 0; - rdi_section_raw_table_from_kind(rdi, params.target, &element_count_in_this_rdi); - U64 tasks_per_this_rdi = (element_count_in_this_rdi+elements_per_task-1)/elements_per_task; - for(U64 task_in_this_rdi_idx = 0; task_in_this_rdi_idx < tasks_per_this_rdi; task_in_this_rdi_idx += 1) - { - DI_SearchWorkIn *in = push_array(scratch.arena, DI_SearchWorkIn, 1); - in->key = key; - in->initial_bucket_write_gen = initial_bucket_write_gen; - in->work_thread_arenas = work_thread_arenas; - in->rdi = rdi; - in->section_kind = params.target; - in->element_range = r1u64(task_in_this_rdi_idx*elements_per_task, (task_in_this_rdi_idx+1)*elements_per_task); - in->element_range.max = ClampTop(in->element_range.max, element_count_in_this_rdi); - in->query = query; - in->dbgi_idx = idx; - async_task_list_push(scratch.arena, &tasks, async_task_launch(scratch.arena, di_search_work, .input = in)); - } - } - } - - //- rjf: join tasks, form final list - B32 cancelled = 0; - DI_SearchItemChunkList items_list = {0}; - for(ASYNC_TaskNode *n = tasks.first; n != 0; n = n->next) - { - DI_SearchWorkOut *out = async_task_join_struct(n->v, DI_SearchWorkOut); - di_search_item_chunk_list_concat_in_place(&items_list, &out->items); - cancelled = (cancelled || out->cancelled); - } - - //- rjf: end debug info scope - di_scope_close(di_scope); - - //- rjf: list -> array - DI_SearchItemArray items = {0}; - if(arena != 0 && !cancelled) - { - items.count = items_list.total_count; - items.v = push_array(arena, DI_SearchItem, items.count); - U64 off = 0; - for(DI_SearchItemChunk *chunk = items_list.first; chunk != 0; chunk = chunk->next) - { - MemoryCopy(items.v + off, chunk->v, sizeof(chunk->v[0])*chunk->count); - for EachIndex(idx, chunk->count) - { - items.v[off + idx].match_ranges = fuzzy_match_range_list_copy(arena, &items.v[off + idx].match_ranges); - } - off += chunk->count; - } - } - - //- rjf: release all search work artifact arenas - if(work_thread_arenas != 0) - { - for EachIndex(idx, async_thread_count()) - { - if(work_thread_arenas[idx] != 0) - { - arena_release(work_thread_arenas[idx]); - } - } - } - - //- rjf: array -> sorted array - if(items.count != 0 && query.size != 0) - { - quick_sort(items.v, items.count, sizeof(DI_SearchItem), di_qsort_compare_search_items); - } - - //- rjf: commit to cache - wait on scope touches - if(arena != 0) - { - MutexScopeW(stripe->rw_mutex) for(;;) - { - B32 found = 0; - B32 done = 0; - for(DI_SearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - if(n->scope_refcount == 0) - { - n->bucket_read_gen += 1; - n->work_refcount -= 1; - if(!cancelled) - { - n->items = items; - n->bucket_items_gen = initial_bucket_write_gen; - } - done = 1; - } - found = 1; - break; - } - } - if((found && done) || !found) - { - break; - } - if(found && !done) - { - cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, os_now_microseconds()+1000); - } - } - } + // rjf: unpack artifact + result.v = (DI_SearchItem *)artifact.u64[1]; + result.count = artifact.u64[2]; scratch_end(scratch); } -} - -internal void -di_search_evictor_thread__entry_point(void *p) -{ - ThreadNameF("di_search_evictor_thread"); - for(;;) - { - for(U64 slot_idx = 0; slot_idx < di_shared->search_slots_count; slot_idx += 1) - { - U64 stripe_idx = slot_idx%di_shared->search_stripes_count; - DI_SearchSlot *slot = &di_shared->search_slots[slot_idx]; - DI_SearchStripe *stripe = &di_shared->search_stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) - { - for(DI_SearchNode *n = slot->first; n != 0; n = n->next) - { - if(n->last_update_tick_idx+10 < update_tick_idx() && n->scope_refcount == 0 && n->work_refcount == 0) - { - slot_has_work = 1; - break; - } - } - } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(DI_SearchNode *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - if(n->last_update_tick_idx+10 < update_tick_idx() && n->scope_refcount == 0 && n->work_refcount == 0) - { - DLLRemove(slot->first, slot->last, n); - SLLStackPush(stripe->free_node, n); - for EachElement(idx, n->buckets) - { - arena_release(n->buckets[idx].arena); - MemoryZeroStruct(&n->buckets[idx]); - } - MemoryZeroStruct(&n->items); - } - } - } - } - os_sleep_milliseconds(100); - } -} - -//////////////////////////////// -//~ rjf: Match Store - -internal DI_MatchStore * -di_match_store_alloc(void) -{ - Arena *arena = arena_alloc(); - DI_MatchStore *store = push_array(arena, DI_MatchStore, 1); - store->arena = arena; - for EachElement(idx, store->gen_arenas) - { - store->gen_arenas[idx] = arena_alloc(); - } - store->params_arena = arena_alloc(); - store->params_rw_mutex = rw_mutex_alloc(); - store->match_name_slots_count = 4096; - store->match_name_slots = push_array(arena, DI_MatchNameSlot, store->match_name_slots_count); - store->match_rw_mutex = rw_mutex_alloc(); - store->match_cv = cond_var_alloc(); - store->u2m_ring_cv = cond_var_alloc(); - store->u2m_ring_mutex = mutex_alloc(); - store->u2m_ring_size = KB(2); - store->u2m_ring_base = push_array_no_zero(arena, U8, store->u2m_ring_size); - store->m2u_ring_cv = cond_var_alloc(); - store->m2u_ring_mutex = mutex_alloc(); - store->m2u_ring_size = KB(2); - store->m2u_ring_base = push_array_no_zero(arena, U8, store->m2u_ring_size); - return store; -} - -internal void -di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys) -{ - ProfBeginFunction(); - store->gen += 1; - arena_clear(store->gen_arenas[store->gen%ArrayCount(store->gen_arenas)]); - - // rjf: hash parameters - U64 params_hash = 5381; - for EachIndex(idx, keys.count) - { - params_hash = di_hash_from_seed_string(params_hash, str8_struct(&keys.v[idx].min_timestamp), 0); - params_hash = di_hash_from_seed_string(params_hash, keys.v[idx].path, StringMatchFlag_CaseInsensitive); - } - - // rjf: store parameters if needed - if(store->params_hash != params_hash) MutexScopeW(store->params_rw_mutex) - { - arena_clear(store->params_arena); - store->params_hash = params_hash; - store->params_keys = di_key_array_copy(store->params_arena, &keys); - } - - // rjf: prune least recently used matches - { - for(DI_MatchNameNode *node = store->last_lru_match_name, *prev = 0; node != 0; node = prev) - { - prev = node->lru_prev; - if(node->last_gen_touched+8 < store->gen) - { - node->alloc_gen += 1; - U64 slot_idx = node->hash%store->match_name_slots_count; - DI_MatchNameSlot *slot = &store->match_name_slots[slot_idx]; - DLLRemove_NP(store->first_lru_match_name, store->last_lru_match_name, node, lru_next, lru_prev); - DLLRemove(slot->first, slot->last, node); - SLLStackPush(store->first_free_match_name, node); - store->active_match_name_nodes_count -= 1; - } - else - { - break; - } - } - } - - // rjf: pop new matches -#if 0 - for(;;) - { - U64 unconsumed_size = store->m2u_ring_write_pos - store->m2u_ring_read_pos; - } -#endif - - ProfEnd(); -} - -internal DI_Match -di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us) -{ - DI_Match result = {0}; - if(name.size != 0) - { - // rjf: unpack name - U64 hash = di_hash_from_string(name, 0); - U64 slot_idx = hash%store->match_name_slots_count; - DI_MatchNameSlot *slot = &store->match_name_slots[slot_idx]; - - // rjf: get name's node, if it exists - DI_MatchNameNode *node = 0; - for(DI_MatchNameNode *n = slot->first; n != 0; n = n->next) - { - if(n->hash == hash && str8_match(n->name, name, 0)) - { - node = n; - break; - } - } - - // rjf: if node does not exist, create - if(node == 0) - { - node = store->first_free_match_name; - U64 alloc_gen = 0; - if(node) - { - SLLStackPop(store->first_free_match_name); - alloc_gen = node->alloc_gen; - } - else - { - node = push_array_no_zero(store->arena, DI_MatchNameNode, 1); - } - MemoryZeroStruct(node); - node->hash = hash; - node->alloc_gen = alloc_gen + 1; - DLLPushBack(slot->first, slot->last, node); - node->first_gen_touched = store->gen; - DLLInsert_NP(store->first_lru_match_name, store->last_lru_match_name, (DI_MatchNameNode *)0, node, lru_next, lru_prev); - store->active_match_name_nodes_count += 1; - } - - // rjf: touch node for this gen - node->last_gen_touched = store->gen; - node->name = push_str8_copy(store->gen_arenas[store->gen%ArrayCount(store->gen_arenas)], name); - DLLRemove_NP(store->first_lru_match_name, store->last_lru_match_name, node, lru_next, lru_prev); - DLLInsert_NP(store->first_lru_match_name, store->last_lru_match_name, (DI_MatchNameNode *)0, node, lru_next, lru_prev); - - // rjf: if this node is new w.r.t. the store's current parameters, request it - U64 completed_params_hash = ins_atomic_u64_eval(&node->cmp_params_hash); - if(completed_params_hash != store->params_hash && node->req_count == ins_atomic_u64_eval(&node->cmp_count)) - { - B32 sent = 0; - MutexScope(store->u2m_ring_mutex) for(;;) - { - U64 unconsumed_size = store->u2m_ring_write_pos - store->u2m_ring_read_pos; - U64 available_size = store->u2m_ring_size - unconsumed_size; - U64 needed_size = sizeof(&node) + sizeof(node->alloc_gen) + sizeof(name.size) + name.size; - if(available_size >= needed_size) - { - store->u2m_ring_write_pos += ring_write_struct(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_write_pos, &node); - store->u2m_ring_write_pos += ring_write_struct(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_write_pos, &node->alloc_gen); - store->u2m_ring_write_pos += ring_write_struct(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_write_pos, &name.size); - store->u2m_ring_write_pos += ring_write(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_write_pos, name.str, name.size); - sent = 1; - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(store->u2m_ring_cv, store->u2m_ring_mutex, endt_us); - } - if(sent) - { - cond_var_broadcast(store->u2m_ring_cv); - async_push_work(di_match_work, .input = store, .priority = ASYNC_Priority_Low, .completion_counter = &node->cmp_count); - node->req_params_hash = store->params_hash; - node->req_count += 1; - } - } - - // rjf: if this node's state is stale, wait for it if we need to - if(os_now_microseconds() < endt_us && node->req_params_hash != completed_params_hash) - { - MutexScopeR(store->match_rw_mutex) for(;;) - { - if(node->req_params_hash == ins_atomic_u64_eval(&node->cmp_params_hash)) - { - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait_rw_r(store->match_cv, store->match_rw_mutex, endt_us); - } - } - - // rjf: return node present info - result = node->primary_match; - if(node->cmp_params_hash != store->params_hash) - { - result.dbgi_idx = 0; - result.idx = 0; - } - } return result; } -ASYNC_WORK_DEF(di_match_work) +//////////////////////////////// +//~ rjf: Match Artifact Cache Hooks / Lookups + +internal AC_Artifact +di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DI_MatchStore *store = (DI_MatchStore *)input; + + //- rjf: unpack key + U64 index = 0; + String8 name = {0}; { - //- rjf: get next request - DI_MatchNameNode *node = 0; - U64 alloc_gen = 0; - String8 name = {0}; - ProfScope("get next name") MutexScope(store->u2m_ring_mutex) for(;;) - { - U64 unconsumed_size = store->u2m_ring_write_pos - store->u2m_ring_read_pos; - if(unconsumed_size >= sizeof(U64)) - { - store->u2m_ring_read_pos += ring_read_struct(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_read_pos, &node); - store->u2m_ring_read_pos += ring_read_struct(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_read_pos, &alloc_gen); - store->u2m_ring_read_pos += ring_read_struct(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_read_pos, &name.size); - name.str = push_array(scratch.arena, U8, name.size); - store->u2m_ring_read_pos += ring_read(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_read_pos, name.str, name.size); - break; - } - cond_var_wait(store->u2m_ring_cv, store->u2m_ring_mutex, max_U64); - } - cond_var_broadcast(store->u2m_ring_cv); - - //- rjf: read parameters - U64 params_hash = 0; - DI_KeyArray params_keys = {0}; - ProfScope("read parameters") MutexScopeR(store->params_rw_mutex) - { - params_keys = di_key_array_copy(scratch.arena, &store->params_keys); - params_hash = store->params_hash; - } - - //- rjf: zero match info - ins_atomic_u64_eval_assign(&node->primary_match.dbgi_idx, 0); - ins_atomic_u32_eval_assign(&node->primary_match.idx, 0); - - //- rjf: gather matches - DI_MatchNode *first_match = 0; - DI_MatchNode *last_match = 0; - RDI_NameMapKind name_map_kinds[] = + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, &index); + key_read_off += str8_deserial_read_struct(key, key_read_off, &name.size); + name.str = push_array_no_zero(scratch.arena, U8, name.size); + key_read_off += str8_deserial_read(key, key_read_off, name.str, name.size, 1); + } + + //- rjf: get all loaded keys + DI_KeyArray dbgi_keys = di_push_all_loaded_keys(scratch.arena); + + //- rjf: wide search across all debug infos + DI_Match *lane_matches = 0; + if(lane_idx() == 0) + { + lane_matches = push_array(scratch.arena, DI_Match, lane_count()); + } + lane_sync_u64(&lane_matches, 0); + { + read_only local_persist RDI_NameMapKind name_map_kinds[] = { RDI_NameMapKind_GlobalVariables, RDI_NameMapKind_ThreadVariables, @@ -1845,7 +1416,7 @@ ASYNC_WORK_DEF(di_match_work) RDI_NameMapKind_Procedures, RDI_NameMapKind_Types, }; - RDI_SectionKind name_map_section_kinds[] = + read_only local_persist RDI_SectionKind name_map_section_kinds[] = { RDI_SectionKind_GlobalVariables, RDI_SectionKind_ThreadVariables, @@ -1853,13 +1424,13 @@ ASYNC_WORK_DEF(di_match_work) RDI_SectionKind_Procedures, RDI_SectionKind_TypeNodes, }; - ProfScope("do match") + Rng1U64 range = lane_range(dbgi_keys.count); + for EachInRange(dbgi_idx, range) { - for EachIndex(dbgi_idx, params_keys.count) + Access *access = access_open(); { - DI_Scope *di_scope = di_scope_open(); - DI_Key key = params_keys.v[dbgi_idx]; - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &key, 1, os_now_microseconds()+1000); + DI_Key dbgi_key = dbgi_keys.v[dbgi_idx]; + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); for EachElement(name_map_kind_idx, name_map_kinds) { RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, name_map_kinds[name_map_kind_idx]); @@ -1870,28 +1441,63 @@ ASYNC_WORK_DEF(di_match_work) U32 *run = rdi_matches_from_map_node(rdi, map_node, &num); if(num != 0) { - // rjf: atomically update the node's primary match - ins_atomic_u64_eval_assign(&node->primary_match.dbgi_idx, dbgi_idx); - ins_atomic_u32_eval_assign(&node->primary_match.section, name_map_section_kinds[name_map_kind_idx]); - ins_atomic_u32_eval_assign(&node->primary_match.idx, run[num-1]); - - // rjf: gather all alternate matches - for(U32 match_idx = 1; match_idx < num; match_idx += 1) - { - DI_MatchNode *m = push_array(scratch.arena, DI_MatchNode, 1); - SLLQueuePush(first_match, last_match, m); - m->v.dbgi_idx = dbgi_idx; - m->v.section = name_map_section_kinds[name_map_kind_idx]; - m->v.idx = run[match_idx]; - } + lane_matches[lane_idx()].key = dbgi_key; + lane_matches[lane_idx()].section_kind = name_map_section_kinds[name_map_kind_idx]; + lane_matches[lane_idx()].idx = run[num-1]; } } - di_scope_close(di_scope); } - ins_atomic_u64_eval_assign(&node->cmp_params_hash, params_hash); + access_close(access); } } + lane_sync(); + + //- rjf: pick match + DI_Match match = {0}; + for EachIndex(idx, lane_count()) + { + if(lane_matches[idx].idx != 0) + { + match = lane_matches[idx]; + break; + } + } + + //- rjf: package as artifact + AC_Artifact artifact = {0}; + { + StaticAssert(ArrayCount(artifact.u64) >= 4, artifact_size_check); + artifact.u64[0] = match.key.u64[0]; + artifact.u64[1] = match.key.u64[1]; + artifact.u64[2] = match.section_kind; + artifact.u64[3] = match.idx; + } + + lane_sync(); scratch_end(scratch); ProfEnd(); - return 0; + return artifact; +} + +internal DI_Match +di_match_from_string(String8 string, U64 index, U64 endt_us) +{ + DI_Match result = {0}; + Access *access = access_open(); + Temp scratch = scratch_begin(0, 0); + { + String8List key_parts = {0}; + str8_list_push(scratch.arena, &key_parts, str8_struct(&index)); + str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); + str8_list_push(scratch.arena, &key_parts, string); + String8 key = str8_list_join(scratch.arena, &key_parts, 0); + AC_Artifact artifact = ac_artifact_from_key(access, key, di_match_artifact_create, 0, endt_us, .flags = AC_Flag_Wide, .gen = di_load_gen()); + result.key.u64[0] = artifact.u64[0]; + result.key.u64[1] = artifact.u64[1]; + result.section_kind = artifact.u64[2]; + result.idx = artifact.u64[3]; + } + scratch_end(scratch); + access_close(access); + return result; } diff --git a/src/dbg_info/dbg_info.h b/src/dbg_info/dbg_info.h index 22e4d8eb..49ea1341 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -5,13 +5,12 @@ #define DBG_INFO_H //////////////////////////////// -//~ rjf: Cache Key Type +//~ rjf: Unique Debug Info Key typedef struct DI_Key DI_Key; struct DI_Key { - String8 path; - U64 min_timestamp; + U64 u64[2]; }; typedef struct DI_KeyNode DI_KeyNode; @@ -37,50 +36,28 @@ struct DI_KeyArray }; //////////////////////////////// -//~ rjf: Event Types +//~ rjf: Debug Info Path / Timestamp => Key Cache Types -typedef enum DI_EventKind +typedef struct DI_KeyPathNode DI_KeyPathNode; +struct DI_KeyPathNode { - DI_EventKind_Null, - DI_EventKind_ConversionStarted, - DI_EventKind_ConversionEnded, - DI_EventKind_ConversionFailureUnsupportedFormat, - DI_EventKind_COUNT -} -DI_EventKind; - -typedef struct DI_Event DI_Event; -struct DI_Event -{ - DI_EventKind kind; - String8 string; + DI_KeyPathNode *next; + DI_KeyPathNode *prev; + String8 path; + U64 min_timestamp; + DI_Key key; }; -typedef struct DI_EventNode DI_EventNode; -struct DI_EventNode +typedef struct DI_KeySlot DI_KeySlot; +struct DI_KeySlot { - DI_EventNode *next; - DI_Event v; -}; - -typedef struct DI_EventList DI_EventList; -struct DI_EventList -{ - DI_EventNode *first; - DI_EventNode *last; - U64 count; + DI_KeyPathNode *first; + DI_KeyPathNode *last; }; //////////////////////////////// //~ rjf: Debug Info Cache Types -typedef struct DI_StringChunkNode DI_StringChunkNode; -struct DI_StringChunkNode -{ - DI_StringChunkNode *next; - U64 size; -}; - typedef struct DI_Node DI_Node; struct DI_Node { @@ -88,24 +65,23 @@ struct DI_Node DI_Node *next; DI_Node *prev; - // rjf: metadata - U64 ref_count; - U64 touch_count; - U64 is_working; - // rjf: key DI_Key key; - // rjf: file handles + // rjf: value OS_Handle file; OS_Handle file_map; void *file_base; FileProperties file_props; - - // rjf: parse artifacts Arena *arena; RDI_Parsed rdi; - B32 parse_done; + + // rjf: metadata + AccessPt access_pt; + U64 refcount; + U64 batch_request_counts[2]; + U64 working_count; + U64 completion_count; }; typedef struct DI_Slot DI_Slot; @@ -115,24 +91,78 @@ struct DI_Slot DI_Node *last; }; -typedef struct DI_Stripe DI_Stripe; -struct DI_Stripe +//////////////////////////////// +//~ rjf: Requests + +typedef struct DI_Request DI_Request; +struct DI_Request { + DI_Key key; +}; + +typedef struct DI_RequestNode DI_RequestNode; +struct DI_RequestNode +{ + DI_RequestNode *next; + DI_Request v; +}; + +typedef struct DI_RequestBatch DI_RequestBatch; +struct DI_RequestBatch +{ + Mutex mutex; Arena *arena; - DI_Node *free_node; - DI_StringChunkNode *free_string_chunks[8]; - RWMutex rw_mutex; - CondVar cv; + DI_RequestNode *first; + DI_RequestNode *last; + U64 count; }; //////////////////////////////// -//~ rjf: Search Cache Types +//~ rjf: Load Tasks + +typedef enum DI_LoadTaskStatus +{ + DI_LoadTaskStatus_Null, + DI_LoadTaskStatus_Active, + DI_LoadTaskStatus_Done, +} +DI_LoadTaskStatus; + +typedef struct DI_LoadTask DI_LoadTask; +struct DI_LoadTask +{ + DI_LoadTask *next; + DI_LoadTask *prev; + + DI_Key key; + DI_LoadTaskStatus status; + + B32 og_analyzed; + B32 og_is_rdi; + U64 og_size; + + B32 rdi_analyzed; + B32 rdi_is_stale; + + U64 thread_count; + OS_Handle process; +}; + +typedef struct DI_LoadCompletion DI_LoadCompletion; +struct DI_LoadCompletion +{ + DI_LoadCompletion *next; + U64 code; +}; + +//////////////////////////////// +//~ rjf: Search Types typedef struct DI_SearchItem DI_SearchItem; struct DI_SearchItem { U64 idx; - U64 dbgi_idx; + DI_Key key; U64 missed_size; FuzzyMatchRangeList match_ranges; }; @@ -141,6 +171,7 @@ typedef struct DI_SearchItemChunk DI_SearchItemChunk; struct DI_SearchItemChunk { DI_SearchItemChunk *next; + U64 base_idx; DI_SearchItem *v; U64 count; U64 cap; @@ -162,328 +193,127 @@ struct DI_SearchItemArray U64 count; }; -typedef struct DI_SearchParams DI_SearchParams; -struct DI_SearchParams -{ - RDI_SectionKind target; - DI_KeyArray dbgi_keys; -}; - -typedef struct DI_SearchBucket DI_SearchBucket; -struct DI_SearchBucket -{ - Arena *arena; - String8 query; - U64 params_hash; - DI_SearchParams params; -}; - -typedef struct DI_SearchNode DI_SearchNode; -struct DI_SearchNode -{ - DI_SearchNode *next; - DI_SearchNode *prev; - U128 key; - U64 scope_refcount; - U64 work_refcount; - U64 last_update_tick_idx; - U64 bucket_read_gen; - U64 bucket_write_gen; - U64 bucket_items_gen; - DI_SearchBucket buckets[6]; - DI_SearchItemArray items; -}; - -typedef struct DI_SearchSlot DI_SearchSlot; -struct DI_SearchSlot -{ - DI_SearchNode *first; - DI_SearchNode *last; -}; - -typedef struct DI_SearchStripe DI_SearchStripe; -struct DI_SearchStripe -{ - Arena *arena; - DI_SearchNode *free_node; - RWMutex rw_mutex; - CondVar cv; -}; - //////////////////////////////// -//~ rjf: Scoped Access Types - -typedef struct DI_Touch DI_Touch; -struct DI_Touch -{ - DI_Touch *next; - DI_Node *node; - DI_Stripe *stripe; - DI_SearchNode *search_node; - DI_SearchStripe *search_stripe; -}; - -typedef struct DI_Scope DI_Scope; -struct DI_Scope -{ - DI_Scope *next; - DI_Scope *prev; - DI_Touch *first_touch; - DI_Touch *last_touch; -}; - -typedef struct DI_TCTX DI_TCTX; -struct DI_TCTX -{ - Arena *arena; - DI_Scope *first_scope; - DI_Scope *last_scope; - DI_Scope *free_scope; - DI_Touch *free_touch; -}; - -//////////////////////////////// -//~ rjf: Search Thread State Types - -typedef struct DI_SearchThread DI_SearchThread; -struct DI_SearchThread -{ - Thread thread; - Mutex ring_mutex; - CondVar ring_cv; - U64 ring_size; - U8 *ring_base; - U64 ring_write_pos; - U64 ring_read_pos; -}; - -//////////////////////////////// -//~ rjf: Match Cache State Types +//~ rjf: Match Types typedef struct DI_Match DI_Match; struct DI_Match { - U64 dbgi_idx; - RDI_SectionKind section; + DI_Key key; + RDI_SectionKind section_kind; U32 idx; }; -typedef struct DI_MatchNode DI_MatchNode; -struct DI_MatchNode -{ - DI_MatchNode *next; - DI_Match v; -}; - -typedef struct DI_MatchNameNode DI_MatchNameNode; -struct DI_MatchNameNode -{ - // rjf: synchronously written by usage code - DI_MatchNameNode *next; - DI_MatchNameNode *prev; - DI_MatchNameNode *lru_next; - DI_MatchNameNode *lru_prev; - U64 alloc_gen; - U64 first_gen_touched; - U64 last_gen_touched; - U64 req_params_hash; - U64 req_count; - String8 name; - U64 hash; - - // rjf: atomically written by match work - U64 cmp_count; - U64 cmp_params_hash; - DI_Match primary_match; - // DI_MatchNode *first_alt_match; - // DI_MatchNode *last_alt_match; -}; - -typedef struct DI_MatchNameSlot DI_MatchNameSlot; -struct DI_MatchNameSlot -{ - DI_MatchNameNode *first; - DI_MatchNameNode *last; -}; - -typedef struct DI_MatchStore DI_MatchStore; -struct DI_MatchStore -{ - Arena *arena; - U64 gen; - Arena *gen_arenas[2]; - - // rjf: parameters - Arena *params_arena; - RWMutex params_rw_mutex; - U64 params_hash; - DI_KeyArray params_keys; - - // rjf: match cache - U64 match_name_slots_count; - DI_MatchNameSlot *match_name_slots; - DI_MatchNameNode *first_free_match_name; - DI_Match *first_free_match; - DI_MatchNameNode *first_lru_match_name; - DI_MatchNameNode *last_lru_match_name; - U64 active_match_name_nodes_count; - RWMutex match_rw_mutex; - CondVar match_cv; - - // rjf: user -> match work ring buffer - CondVar u2m_ring_cv; - Mutex u2m_ring_mutex; - U64 u2m_ring_size; - U8 *u2m_ring_base; - U64 u2m_ring_write_pos; - U64 u2m_ring_read_pos; - - // rjf: match -> user work ring buffer - CondVar m2u_ring_cv; - Mutex m2u_ring_mutex; - U64 m2u_ring_size; - U8 *m2u_ring_base; - U64 m2u_ring_write_pos; - U64 m2u_ring_read_pos; -}; - //////////////////////////////// -//~ rjf: Shared State Types +//~ rjf: Shared State typedef struct DI_Shared DI_Shared; struct DI_Shared { Arena *arena; + U64 load_gen; + + // rjf: key -> path cache + U64 key2path_slots_count; + DI_KeySlot *key2path_slots; + StripeArray key2path_stripes; + + // rjf: path -> key cache + U64 path2key_slots_count; + DI_KeySlot *path2key_slots; + StripeArray path2key_stripes; // rjf: debug info cache U64 slots_count; DI_Slot *slots; - U64 stripes_count; - DI_Stripe *stripes; + StripeArray stripes; - // rjf: search cache - U64 search_slots_count; - DI_SearchSlot *search_slots; - U64 search_stripes_count; - DI_SearchStripe *search_stripes; + // rjf: requests + DI_RequestBatch req_batches[2]; // [0] -> high priority, [1] -> low priority - // rjf: user -> parse ring - Mutex u2p_ring_mutex; - CondVar u2p_ring_cv; - U64 u2p_ring_size; - U8 *u2p_ring_base; - U64 u2p_ring_write_pos; - U64 u2p_ring_read_pos; + // rjf: conversion tasks + DI_LoadTask *first_load_task; + DI_LoadTask *last_load_task; + DI_LoadTask *free_load_task; + U64 conversion_process_count; + U64 conversion_thread_count; - // rjf: parse -> user event ring - Mutex p2u_ring_mutex; - CondVar p2u_ring_cv; - U64 p2u_ring_size; - U8 *p2u_ring_base; - U64 p2u_ring_write_pos; - U64 p2u_ring_read_pos; + // rjf: conversion completion receiving thread + U64 conversion_completion_code; + String8 conversion_completion_lock_semaphore_name; + String8 conversion_completion_signal_semaphore_name; + String8 conversion_completion_shared_memory_name; + Semaphore conversion_completion_lock_semaphore; + Semaphore conversion_completion_signal_semaphore; + OS_Handle conversion_completion_shared_memory; + U64 *conversion_completion_shared_memory_base; + Thread conversion_completion_signal_receiver_thread; - // rjf: search threads - U64 search_threads_count; - DI_SearchThread *search_threads; - Thread search_evictor_thread; + // rjf: completion batch + Mutex completion_mutex; + Arena *completion_arena; + DI_LoadCompletion *first_completion; + DI_LoadCompletion *last_completion; }; //////////////////////////////// //~ rjf: Globals global DI_Shared *di_shared = 0; -thread_static DI_TCTX *di_tctx = 0; //////////////////////////////// -//~ rjf: Basic Helpers +//~ rjf: Helpers -internal U64 di_hash_from_seed_string(U64 seed, String8 string, StringMatchFlags match_flags); -internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags); -internal U64 di_hash_from_key(DI_Key *k); internal DI_Key di_key_zero(void); -internal B32 di_key_match(DI_Key *a, DI_Key *b); -internal DI_Key di_key_copy(Arena *arena, DI_Key *src); -internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src); -internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key); +internal B32 di_key_match(DI_Key a, DI_Key b); +internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key key); internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list); -internal DI_KeyArray di_key_array_copy(Arena *arena, DI_KeyArray *src); -internal DI_SearchParams di_search_params_copy(Arena *arena, DI_SearchParams *src); -internal U64 di_hash_from_search_params(DI_SearchParams *params); -internal void di_search_item_chunk_list_concat_in_place(DI_SearchItemChunkList *dst, DI_SearchItemChunkList *to_push); -internal U64 di_search_item_num_from_array_element_idx__linear_search(DI_SearchItemArray *array, U64 element_idx); -internal String8 di_search_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx); //////////////////////////////// //~ rjf: Main Layer Initialization -internal void di_init(void); +internal void di_init(CmdLine *cmdline); //////////////////////////////// -//~ rjf: Scope Functions +//~ rjf: Path * Timestamp Cache Submission & Lookup -internal DI_Scope *di_scope_open(void); -internal void di_scope_close(DI_Scope *scope); -internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Stripe *stripe, DI_Node *node); -internal void di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchStripe *stripe, DI_SearchNode *node); +internal DI_Key di_key_from_path_timestamp(String8 path, U64 min_timestamp); //////////////////////////////// -//~ rjf: Per-Slot Functions +//~ rjf: Debug Info Opening / Closing -internal DI_Node *di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key); +internal void di_open(DI_Key key); +internal void di_close(DI_Key key); //////////////////////////////// -//~ rjf: Per-Stripe Functions +//~ rjf: Debug Info Lookups -internal U64 di_string_bucket_idx_from_string_size(U64 size); -internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); -internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); +internal U64 di_load_gen(void); +internal DI_KeyArray di_push_all_loaded_keys(Arena *arena); +internal RDI_Parsed *di_rdi_from_key(Access *access, DI_Key key, B32 high_priority, U64 endt_us); //////////////////////////////// -//~ rjf: Key Opening/Closing +//~ rjf: Asynchronous Tick -internal void di_open(DI_Key *key); -internal void di_close(DI_Key *key); +internal void di_async_tick(void); //////////////////////////////// -//~ rjf: Debug Info Cache Lookups +//~ rjf: Conversion Completion Signal Receiver Thread -internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, B32 high_priority, U64 endt_us); +internal void di_signal_completion(void); +internal void di_conversion_completion_signal_receiver_thread_entry_point(void *p); //////////////////////////////// -//~ rjf: Search Cache Lookups +//~ rjf: Search Artifact Cache Hooks / Lookups -internal DI_SearchItemArray di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams *params, String8 query, U64 endt_us, B32 *stale_out); +internal AC_Artifact di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal void di_search_artifact_destroy(AC_Artifact artifact); +internal DI_SearchItemArray di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us); //////////////////////////////// -//~ rjf: Asynchronous Parse Work +//~ rjf: Match Artifact Cache Hooks / Lookups -internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us); -internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key); - -internal void di_p2u_push_event(DI_Event *event); -internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us); - -ASYNC_WORK_DEF(di_parse_work); - -//////////////////////////////// -//~ rjf: Search Threads - -internal B32 di_u2s_enqueue_req(U128 key, U64 endt_us); -internal U128 di_u2s_dequeue_req(U64 thread_idx); - -ASYNC_WORK_DEF(di_search_work); -internal int di_qsort_compare_search_items(DI_SearchItem *a, DI_SearchItem *b); -internal void di_search_thread__entry_point(void *p); - -internal void di_search_evictor_thread__entry_point(void *p); - -//////////////////////////////// -//~ rjf: Match Store - -internal DI_MatchStore *di_match_store_alloc(void); -internal void di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys); -internal DI_Match di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us); -ASYNC_WORK_DEF(di_match_work); +internal AC_Artifact di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal DI_Match di_match_from_string(String8 string, U64 index, U64 endt_us); #endif // DBG_INFO_H diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c deleted file mode 100644 index e95d18dd..00000000 --- a/src/dbg_info/dbg_info2.c +++ /dev/null @@ -1,1503 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Helpers - -internal DI2_Key -di2_key_zero(void) -{ - DI2_Key key = {0}; - return key; -} - -internal B32 -di2_key_match(DI2_Key a, DI2_Key b) -{ - B32 result = MemoryMatchStruct(&a, &b); - return result; -} - -internal void -di2_key_list_push(Arena *arena, DI2_KeyList *list, DI2_Key key) -{ - DI2_KeyNode *n = push_array(arena, DI2_KeyNode, 1); - n->v = key; - SLLQueuePush(list->first, list->last, n); - list->count += 1; -} - -internal DI2_KeyArray -di2_key_array_from_list(Arena *arena, DI2_KeyList *list) -{ - DI2_KeyArray array = {0}; - array.count = list->count; - array.v = push_array(arena, DI2_Key, array.count); - U64 idx = 0; - for EachNode(n, DI2_KeyNode, list->first) - { - array.v[idx] = n->v; - idx += 1; - } - return array; -} - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -di2_init(CmdLine *cmdline) -{ - Arena *arena = arena_alloc(); - di2_shared = push_array(arena, DI2_Shared, 1); - di2_shared->arena = arena; - di2_shared->key2path_slots_count = 4096; - di2_shared->key2path_slots = push_array(arena, DI2_KeySlot, di2_shared->key2path_slots_count); - di2_shared->key2path_stripes = stripe_array_alloc(arena); - di2_shared->path2key_slots_count = 4096; - di2_shared->path2key_slots = push_array(arena, DI2_KeySlot, di2_shared->path2key_slots_count); - di2_shared->path2key_stripes = stripe_array_alloc(arena); - di2_shared->slots_count = 4096; - di2_shared->slots = push_array(arena, DI2_Slot, di2_shared->slots_count); - di2_shared->stripes = stripe_array_alloc(arena); - for EachElement(idx, di2_shared->req_batches) - { - di2_shared->req_batches[idx].mutex = mutex_alloc(); - di2_shared->req_batches[idx].arena = arena_alloc(); - } - U64 signal_pid = 0; - String8 signal_pid_string = cmd_line_string(cmdline, str8_lit("signal_pid")); - B32 has_parent = 1; - if(!try_u64_from_str8_c_rules(signal_pid_string, &signal_pid)) - { - has_parent = 0; - signal_pid = os_get_process_info()->pid; - } - U64 signal_code = 0; - String8 signal_code_string = cmd_line_string(cmdline, str8_lit("signal_code")); - try_u64_from_str8_c_rules(signal_code_string, &signal_code); - di2_shared->conversion_completion_code = signal_code; - di2_shared->conversion_completion_lock_semaphore_name = str8f(arena, "conversion_completion_lock_pid_%I64u", signal_pid); - di2_shared->conversion_completion_signal_semaphore_name = str8f(arena, "conversion_completion_signal_pid_%I64u", signal_pid); - di2_shared->conversion_completion_shared_memory_name = str8f(arena, "conversion_completion_shared_memory_pid_%I64u", signal_pid); - if(has_parent) - { - di2_shared->conversion_completion_lock_semaphore = semaphore_open(di2_shared->conversion_completion_lock_semaphore_name); - di2_shared->conversion_completion_signal_semaphore = semaphore_open(di2_shared->conversion_completion_signal_semaphore_name); - di2_shared->conversion_completion_shared_memory = os_shared_memory_open(di2_shared->conversion_completion_shared_memory_name); - } - else - { - di2_shared->conversion_completion_lock_semaphore = semaphore_alloc(1, 1, di2_shared->conversion_completion_lock_semaphore_name); - di2_shared->conversion_completion_signal_semaphore = semaphore_alloc(0, 65536, di2_shared->conversion_completion_signal_semaphore_name); - di2_shared->conversion_completion_shared_memory = os_shared_memory_alloc(KB(4), di2_shared->conversion_completion_shared_memory_name); - di2_shared->conversion_completion_signal_receiver_thread = thread_launch(di2_conversion_completion_signal_receiver_thread_entry_point, 0); - } - di2_shared->conversion_completion_shared_memory_base = (U64 *)os_shared_memory_view_open(di2_shared->conversion_completion_shared_memory, r1u64(0, KB(4))); - di2_shared->completion_mutex = mutex_alloc(); - di2_shared->completion_arena = arena_alloc(); -} - -//////////////////////////////// -//~ rjf: Path * Timestamp Cache Submission & Lookup - -internal DI2_Key -di2_key_from_path_timestamp(String8 path, U64 min_timestamp) -{ - //- rjf: unpack key - U64 hash = u64_hash_from_str8(path); - U64 slot_idx = hash%di2_shared->path2key_slots_count; - DI2_KeySlot *slot = &di2_shared->path2key_slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di2_shared->path2key_stripes, slot_idx); - - //- rjf: look up key, create if needed - DI2_Key key = {0}; - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - // rjf: look up node, with this write mode, to find existing key computation - B32 found = 0; - RWMutexScope(stripe->rw_mutex, write_mode) - { - DI2_KeyPathNode *node = 0; - for(DI2_KeyPathNode *n = slot->first; n != 0; n = n->next) - { - if(str8_match(n->path, path, 0) && min_timestamp <= n->min_timestamp) - { - found = 1; - node = n; - key = node->key; - break; - } - } - if(!found && write_mode) - { - node = stripe->free; - if(node) - { - stripe->free = node->next; - } - else - { - node = push_array(stripe->arena, DI2_KeyPathNode, 1); - } - node->path = str8_copy(stripe->arena, path); - node->min_timestamp = min_timestamp; - node->key = key; - DLLPushBack(slot->first, slot->last, node); - } - } - - // rjf: found the key? abort - if(found) - { - break; - } - - // rjf: didn't find the key on our read lookup? compute the key before entering - // write mode - if(!found && !write_mode) - { - B32 made_key = 0; - - //- rjf: try to make key from file's contents - if(!made_key) - { - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path); - FileProperties props = os_properties_from_file(file); - if(min_timestamp <= props.modified) - { - //- rjf: PDB magic => use GUID for key - if(!made_key) - { - B32 is_pdb = 0; - if(!is_pdb) - { - read_only local_persist char msf_msf20_magic[] = "Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"; - U8 msf20_magic_maybe[sizeof(msf_msf20_magic)] = {0}; - os_file_read(file, r1u64(0, sizeof(msf20_magic_maybe)), msf20_magic_maybe); - if(MemoryMatch(msf20_magic_maybe, msf_msf20_magic, sizeof(msf20_magic_maybe))) - { - is_pdb = 1; - } - } - if(!is_pdb) - { - read_only local_persist char msf_msf70_magic[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"; - U8 msf70_magic_maybe[sizeof(msf_msf70_magic)] = {0}; - os_file_read(file, r1u64(0, sizeof(msf70_magic_maybe)), msf70_magic_maybe); - if(MemoryMatch(msf70_magic_maybe, msf_msf70_magic, sizeof(msf70_magic_maybe))) - { - is_pdb = 1; - } - } - if(is_pdb) - { - // TODO(rjf) - } - } - } - os_file_close(file); - } - - //- rjf: fallback: hash from path/timestamp - if(!made_key) - { - made_key = 1; - U128 hash = u128_hash_from_seed_str8(min_timestamp, path); - MemoryCopy(&key, &hash, Min(sizeof(hash), sizeof(key))); - } - - //- rjf: made key -> store in (key -> path/timestamp) table - if(made_key) - { - U64 key_hash = u64_hash_from_str8(str8_struct(&key)); - U64 key_slot_idx = key_hash%di2_shared->key2path_slots_count; - DI2_KeySlot *key_slot = &di2_shared->key2path_slots[key_slot_idx]; - Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, key_slot_idx); - RWMutexScope(key_stripe->rw_mutex, 1) - { - DI2_KeyPathNode *node = 0; - for EachNode(n, DI2_KeyPathNode, key_slot->first) - { - if(di2_key_match(n->key, key)) - { - node = n; - break; - } - } - if(node == 0) - { - node = key_stripe->free; - if(node != 0) - { - key_stripe->free = node->next; - } - else - { - node = push_array(key_stripe->arena, DI2_KeyPathNode, 1); - } - DLLPushBack(key_slot->first, key_slot->last, node); - node->path = str8_copy(key_stripe->arena, path); - node->min_timestamp = min_timestamp; - node->key = key; - } - } - } - } - } - - return key; -} - -//////////////////////////////// -//~ rjf: Debug Info Opening / Closing - -internal void -di2_open(DI2_Key key) -{ - //- rjf: unpack key - U64 hash = u64_hash_from_str8(str8_struct(&key)); - U64 slot_idx = hash%di2_shared->slots_count; - DI2_Slot *slot = &di2_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); - - //- rjf: bump this key's node's refcount; create if needed - B32 node_is_new = 0; - RWMutexScope(stripe->rw_mutex, 1) - { - DI2_Node *node = 0; - for(DI2_Node *n = slot->first; n != 0; n = n->next) - { - if(di2_key_match(n->key, key)) - { - node = n; - break; - } - } - if(node == 0) - { - node_is_new = 1; - node = stripe->free; - if(node) - { - stripe->free = node->next; - } - else - { - node = push_array_no_zero(stripe->arena, DI2_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->key = key; - node->batch_request_counts[1] = 1; - } - node->refcount += 1; - } - - //- rjf: if new, submit low-priority request to load this key - if(node_is_new) - { - DI2_RequestBatch *batch = &di2_shared->req_batches[1]; - MutexScope(batch->mutex) - { - DI2_RequestNode *n = push_array(batch->arena, DI2_RequestNode, 1); - SLLQueuePush(batch->first, batch->last, n); - n->v.key = key; - batch->count += 1; - } - cond_var_broadcast(async_tick_start_cond_var); - ins_atomic_u32_eval_assign(&async_loop_again, 1); - } -} - -internal void -di2_close(DI2_Key key) -{ - //- rjf: unpack key - U64 hash = u64_hash_from_str8(str8_struct(&key)); - U64 slot_idx = hash%di2_shared->slots_count; - DI2_Slot *slot = &di2_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); - - //- rjf: decrement this key's node's refcount; remove if needed - B32 node_released = 0; - OS_Handle file = {0}; - OS_Handle file_map = {0}; - FileProperties file_props = {0}; - void *file_base = 0; - Arena *arena = 0; - RWMutexScope(stripe->rw_mutex, 1) - { - DI2_Node *node = 0; - for(DI2_Node *n = slot->first; n != 0; n = n->next) - { - if(di2_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) > 0) - { - node = n; - break; - } - } - if(node) - { - node->refcount -= 1; - if(node->refcount == 0) - { - for(;;) - { - if(access_pt_is_expired(&node->access_pt, .time = 0, .update_idxs = 0)) - { - node_released = 1; - DLLRemove(slot->first, slot->last, node); - node->next = stripe->free; - stripe->free = node; - file = node->file; - file_map = node->file_map; - file_props = node->file_props; - file_base = node->file_base; - arena = node->arena; - break; - } - cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64); - } - } - } - } - - //- rjf: release node's resources if needed - if(node_released) - { - os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); - os_file_map_close(file_map); - os_file_close(file); - if(arena != 0) - { - arena_release(arena); - } - } -} - -//////////////////////////////// -//~ rjf: Debug Info Lookups - -internal U64 -di2_load_gen(void) -{ - U64 result = ins_atomic_u64_eval(&di2_shared->load_gen); - return result; -} - -internal DI2_KeyArray -di2_push_all_loaded_keys(Arena *arena) -{ - Temp scratch = scratch_begin(&arena, 1); - DI2_KeyList list = {0}; - { - for EachIndex(slot_idx, di2_shared->key2path_slots_count) - { - DI2_KeySlot *slot = &di2_shared->key2path_slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, slot_idx); - RWMutexScope(stripe->rw_mutex, 0) - { - for(DI2_KeyPathNode *n = slot->first; n != 0; n = n->next) - { - DI2_KeyNode *dst_n = push_array(scratch.arena, DI2_KeyNode, 1); - SLLQueuePush(list.first, list.last, dst_n); - list.count += 1; - dst_n->v = n->key; - } - } - } - } - DI2_KeyArray array = {0}; - array.count = list.count; - array.v = push_array(arena, DI2_Key, array.count); - { - U64 idx = 0; - for EachNode(n, DI2_KeyNode, list.first) - { - array.v[idx] = n->v; - idx += 1; - } - } - scratch_end(scratch); - return array; -} - -internal RDI_Parsed * -di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us) -{ - RDI_Parsed *rdi = &rdi_parsed_nil; - { - U64 hash = u64_hash_from_str8(str8_struct(&key)); - U64 slot_idx = hash%di2_shared->slots_count; - DI2_Slot *slot = &di2_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); - RWMutexScope(stripe->rw_mutex, 0) for(;;) - { - // rjf: try to grab current results - B32 found = 0; - B32 need_hi_request = 0; - B32 grabbed = 0; - for(DI2_Node *n = slot->first; n != 0; n = n->next) - { - if(di2_key_match(n->key, key) && ins_atomic_u64_eval(&n->refcount) > 0) - { - found = 1; - if(high_priority && ins_atomic_u64_eval_cond_assign(&n->batch_request_counts[0], 1, 0) == 0) - { - need_hi_request = 1; - } - if(ins_atomic_u64_eval(&n->completion_count) > 0) - { - grabbed = 1; - rdi = &n->rdi; - access_touch(access, &n->access_pt, stripe->cv); - } - break; - } - } - - // rjf: push high-priority request if needed - if(need_hi_request) - { - DI2_RequestBatch *batch = &di2_shared->req_batches[0]; - MutexScope(batch->mutex) - { - DI2_RequestNode *n = push_array(batch->arena, DI2_RequestNode, 1); - SLLQueuePush(batch->first, batch->last, n); - n->v.key = key; - batch->count += 1; - } - cond_var_broadcast(async_tick_start_cond_var); - ins_atomic_u32_eval_assign(&async_loop_again, 1); - ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1); - } - - // rjf: found current results, or out-of-time? abort - if(grabbed || os_now_microseconds() >= endt_us) - { - break; - } - - // rjf: wait on stripe change - cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 0, endt_us); - } - } - return rdi; -} - -//////////////////////////////// -//~ rjf: Asynchronous Tick - -internal void -di2_async_tick(void) -{ - Temp scratch = scratch_begin(0, 0); - - ////////////////////////////// - //- rjf: do single-lane update: pop requests, update tasks, gather RDI paths to parse wide - // - typedef struct ParseTask ParseTask; - struct ParseTask - { - DI2_Key key; - String8 rdi_path; - }; - ParseTask *parse_tasks = 0; - U64 parse_tasks_count = 0; - if(lane_idx() == 0) - { - typedef struct ParseTaskNode ParseTaskNode; - struct ParseTaskNode - { - ParseTaskNode *next; - ParseTask v; - }; - ParseTaskNode *first_parse_task = 0; - ParseTaskNode *last_parse_task = 0; - - //////////////////////////// - //- rjf: pop all requests, high priority first - // - DI2_RequestNode *first_req = 0; - DI2_RequestNode *last_req = 0; - for EachElement(idx, di2_shared->req_batches) - { - DI2_RequestBatch *b = &di2_shared->req_batches[idx]; - MutexScope(b->mutex) - { - for EachNode(n, DI2_RequestNode, b->first) - { - DI2_RequestNode *n_copy = push_array(scratch.arena, DI2_RequestNode, 1); - MemoryCopyStruct(&n_copy->v, &n->v); - SLLQueuePush(first_req, last_req, n_copy); - } - arena_clear(b->arena); - b->first = b->last = 0; - b->count = 0; - } - } - - //////////////////////////// - //- rjf: gather all completions - // - DI2_LoadCompletion *first_completion = 0; - DI2_LoadCompletion *last_completion = 0; - MutexScope(di2_shared->completion_mutex) - { - for EachNode(c, DI2_LoadCompletion, di2_shared->first_completion) - { - DI2_LoadCompletion *dst_c = push_array(scratch.arena, DI2_LoadCompletion, 1); - SLLQueuePush(first_completion, last_completion, dst_c); - dst_c->code = c->code; - } - arena_clear(di2_shared->completion_arena); - di2_shared->first_completion = di2_shared->last_completion = 0; - } - - //////////////////////////// - //- rjf: generate load tasks for all unique requests - // - for EachNode(n, DI2_RequestNode, first_req) - { - // rjf: unpack request - DI2_Key key = n->v.key; - - // rjf: determine if this request is a duplicate - B32 request_is_duplicate = 1; - { - U64 hash = u64_hash_from_str8(str8_struct(&key)); - U64 slot_idx = hash%di2_shared->slots_count; - DI2_Slot *slot = &di2_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); - RWMutexScope(stripe->rw_mutex, 0) - { - for(DI2_Node *n = slot->first; n != 0; n = n->next) - { - if(di2_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) == 0) - { - request_is_duplicate = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) != 0); - break; - } - } - } - } - - // rjf: if not a duplicate, create new task - if(!request_is_duplicate) - { - DI2_LoadTask *t = di2_shared->free_load_task; - if(t) - { - SLLStackPop(di2_shared->free_load_task); - } - else - { - t = push_array_no_zero(di2_shared->arena, DI2_LoadTask, 1); - } - MemoryZeroStruct(t); - DLLPushBack(di2_shared->first_load_task, di2_shared->last_load_task, t); - t->key = key; - } - } - - //////////////////////////// - //- rjf: update tasks: configure, launch if we can, & retire if we can - // - for(DI2_LoadTask *t = di2_shared->first_load_task, *next = 0; t != 0; t = next) - { - next = t->next; - - //- rjf: unpack key - DI2_Key key = t->key; - U64 key_hash = u64_hash_from_str8(str8_struct(&key)); - U64 key_slot_idx = key_hash%di2_shared->key2path_slots_count; - DI2_KeySlot *key_slot = &di2_shared->key2path_slots[key_slot_idx]; - Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, key_slot_idx); - - //- rjf: get key's O.G. path - String8 og_path = {0}; - U64 og_min_timestamp = 0; - RWMutexScope(key_stripe->rw_mutex, 0) - { - for(DI2_KeyPathNode *n = key_slot->first; n != 0; n = n->next) - { - if(di2_key_match(n->key, key)) - { - og_path = str8_copy(scratch.arena, n->path); - og_min_timestamp = n->min_timestamp; - break; - } - } - } - - //- rjf: analyze O.G. debug info - if(!t->og_analyzed) - { - t->og_analyzed = 1; - OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, og_path); - FileProperties props = os_properties_from_file(file); - t->og_size = props.size; - U64 rdi_magic_maybe = 0; - if(os_file_read_struct(file, 0, &rdi_magic_maybe) == 8 && - rdi_magic_maybe == RDI_MAGIC_CONSTANT) - { - t->og_is_rdi = 1; - } - os_file_close(file); - } - U64 og_size = t->og_size; - B32 og_is_rdi = t->og_is_rdi; - - //- rjf: compute key's RDI path - String8 rdi_path = {0}; - { - if(og_is_rdi) - { - rdi_path = og_path; - } - else - { - rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); - } - } - - //- rjf: determine if RDI is stale - if(!t->rdi_analyzed) - { - t->rdi_analyzed = 1; - OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, rdi_path); - FileProperties props = os_properties_from_file(file); - if(props.modified < og_min_timestamp) - { - t->rdi_is_stale = 1; - } - else - { - t->rdi_is_stale = 1; - RDI_Header header = {0}; - if(os_file_read_struct(file, 0, &header) == sizeof(header)) - { - t->rdi_is_stale = (header.encoding_version != RDI_ENCODING_VERSION); - } - } - os_file_close(file); - } - B32 rdi_is_stale = t->rdi_is_stale; - - //- rjf: calculate thread counts for conversion processes - if(!og_is_rdi && rdi_is_stale && t->thread_count == 0) - { - U64 thread_count = 1; - U64 max_thread_count = os_get_system_info()->logical_processor_count; - { - if(0){} - else if(og_size <= MB(4)) {thread_count = 1;} - else if(og_size <= MB(256)) {thread_count = max_thread_count/4;} - else if(og_size <= MB(512)) {thread_count = max_thread_count/3;} - else if(og_size <= GB(1)) {thread_count = max_thread_count/2;} - else {thread_count = max_thread_count;} - } - thread_count = Max(1, thread_count); - t->thread_count = thread_count; - } - - //- rjf: determine if there are threads available - B32 threads_available = 0; - { - U64 max_threads = os_get_system_info()->logical_processor_count*2; - U64 current_threads = di2_shared->conversion_thread_count; - U64 needed_threads = (current_threads + t->thread_count); - threads_available = (max_threads >= needed_threads); - } - - //- rjf: launch conversion processes - if(threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI2_LoadTaskStatus_Active) - { - B32 should_compress = 0; - OS_ProcessLaunchParams params = {0}; - params.path = os_get_process_info()->binary_path; - params.inherit_env = 1; - params.consoleless = 1; - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "raddbg"); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--bin"); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--quiet"); - if(should_compress) - { - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--compress"); - } - // str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--capture"); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--rdi"); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--out:%S", rdi_path); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--thread_count:%I64u", t->thread_count); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_pid:%I64u", (U64)os_get_process_info()->pid); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_code:%I64u", (U64)t); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "%S", og_path); - ProfMsg("launch creation for %.*s", str8_varg(rdi_path)); - t->process = os_process_launch(¶ms); - t->status = DI2_LoadTaskStatus_Active; - di2_shared->conversion_process_count += 1; - di2_shared->conversion_thread_count += t->thread_count; - } - - //- rjf: if active & process has completed, mark as done - { - U64 exit_code = 0; - if(t->status == DI2_LoadTaskStatus_Active) - { - B32 task_is_done = 0; - for(DI2_LoadCompletion *c = first_completion; c != 0; c = c->next) - { - if(c->code == (U64)t) - { - task_is_done = 1; - break; - } - } - if(!task_is_done) - { - task_is_done = os_process_join(t->process, 0, 0); - } - if(task_is_done) - { - t->status = DI2_LoadTaskStatus_Done; - di2_shared->conversion_process_count -= 1; - di2_shared->conversion_thread_count -= t->thread_count; - } - } - } - - //- rjf: if the RDI for this task is not stale, then we're already done - mark this - // task as done & prepped for storing into the cache - if(!rdi_is_stale) - { - t->status = DI2_LoadTaskStatus_Done; - } - - //- rjf: if the RDI for this task *is* stale, but the O.G. path is actually RDI, - // then we can't actually re-convert to produce a non-stale RDI. in this case, just - // mark as done. - if(rdi_is_stale && og_is_rdi) - { - t->status = DI2_LoadTaskStatus_Done; - } - - //- rjf: if task is done, retire & recycle task; gather path to load - if(t->status == DI2_LoadTaskStatus_Done) - { - DLLRemove(di2_shared->first_load_task, di2_shared->last_load_task, t); - SLLStackPush(di2_shared->free_load_task, t); - ParseTaskNode *n = push_array(scratch.arena, ParseTaskNode, 1); - n->v.key = key; - n->v.rdi_path = rdi_path; - SLLQueuePush(first_parse_task, last_parse_task, n); - parse_tasks_count += 1; - } - } - - //////////////////////////// - //- rjf: join all parse tasks - // - parse_tasks = push_array(scratch.arena, ParseTask, parse_tasks_count); - { - U64 idx = 0; - for EachNode(n, ParseTaskNode, first_parse_task) - { - parse_tasks[idx] = n->v; - idx += 1; - } - } - } - lane_sync_u64(&parse_tasks, 0); - lane_sync_u64(&parse_tasks_count, 0); - lane_sync(); - - ////////////////////////////// - //- rjf: do wide load of all prepped RDIs - // - U64 parse_task_take_counter = 0; - U64 *parse_task_take_counter_ptr = 0; - if(lane_idx() == 0) - { - parse_task_take_counter_ptr = &parse_task_take_counter; - } - lane_sync_u64(&parse_task_take_counter_ptr, 0); - { - for(;;) - { - //- rjf: take next task - U64 parse_task_idx = ins_atomic_u64_inc_eval(parse_task_take_counter_ptr) - 1; - if(parse_task_idx >= parse_tasks_count) - { - break; - } - - //- rjf: unpack task - DI2_Key key = parse_tasks[parse_task_idx].key; - String8 rdi_path = parse_tasks[parse_task_idx].rdi_path; - ProfBegin("parse %.*s", str8_varg(rdi_path)); - - //- rjf: open file - OS_Handle file = {0}; - OS_Handle file_map = {0}; - FileProperties file_props = {0}; - void *file_base = 0; - { - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path); - file_map = os_file_map_open(OS_AccessFlag_Read, file); - file_props = os_properties_from_file(file); - file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); - } - - //- rjf: do initial parse of rdi - RDI_Parsed rdi_parsed_maybe_compressed = rdi_parsed_nil; - { - RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); - (void)parse_status; - } - - //- rjf: decompress & re-parse, if necessary - Arena *rdi_parsed_arena = 0; - RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed; - { - U64 decompressed_size = rdi_decompressed_size_from_parsed(&rdi_parsed_maybe_compressed); - if(decompressed_size > file_props.size) - { - rdi_parsed_arena = arena_alloc(); - U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size); - rdi_decompress_parsed(decompressed_data, decompressed_size, &rdi_parsed_maybe_compressed); - RDI_ParseStatus parse_status = rdi_parse(decompressed_data, decompressed_size, &rdi_parsed); - (void)parse_status; - } - } - - //- rjf: commit parsed info to cache - { - ProfMsg("commit %.*s", str8_varg(rdi_path)); - U64 hash = u64_hash_from_str8(str8_struct(&key)); - U64 slot_idx = hash%di2_shared->slots_count; - DI2_Slot *slot = &di2_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); - RWMutexScope(stripe->rw_mutex, 1) - { - DI2_Node *node = 0; - for(DI2_Node *n = slot->first; n != 0; n = n->next) - { - if(di2_key_match(n->key, key)) - { - node = n; - break; - } - } - if(node) - { - node->file = file; - node->file_map = file_map; - node->file_props = file_props; - node->file_base = file_base; - node->arena = rdi_parsed_arena; - MemoryCopyStruct(&node->rdi, &rdi_parsed); - node->completion_count += 1; - node->working_count -= 1; - ins_atomic_u64_inc_eval(&di2_shared->load_gen); - } - else - { - if(rdi_parsed_arena != 0) - { - arena_release(rdi_parsed_arena); - } - os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); - os_file_map_close(file_map); - os_file_close(file); - } - } - cond_var_broadcast(stripe->cv); - } - - ProfEnd(); - } - } - lane_sync(); - - scratch_end(scratch); -} - -//////////////////////////////// -//~ rjf: Conversion Completion Signal Receiver Thread - -internal void -di2_signal_completion(void) -{ - semaphore_take(di2_shared->conversion_completion_lock_semaphore, max_U64); - di2_shared->conversion_completion_shared_memory_base[0] = di2_shared->conversion_completion_code; - semaphore_drop(di2_shared->conversion_completion_lock_semaphore); - semaphore_drop(di2_shared->conversion_completion_signal_semaphore); -} - -internal void -di2_conversion_completion_signal_receiver_thread_entry_point(void *p) -{ - ThreadNameF("di2_conversion_completion_signal_receiver_thread"); - for(;;) - { - if(semaphore_take(di2_shared->conversion_completion_signal_semaphore, max_U64)) - { - // rjf: get the next retired code - U64 retired_code = 0; - semaphore_take(di2_shared->conversion_completion_lock_semaphore, max_U64); - retired_code = di2_shared->conversion_completion_shared_memory_base[0]; - semaphore_drop(di2_shared->conversion_completion_lock_semaphore); - - // rjf: push completion record - MutexScope(di2_shared->completion_mutex) - { - DI2_LoadCompletion *c = push_array(di2_shared->completion_arena, DI2_LoadCompletion, 1); - SLLQueuePush(di2_shared->first_completion, di2_shared->last_completion, c); - c->code = retired_code; - } - - // rjf: signal async system to resume - ProfMsg("signal conversion completion"); - ins_atomic_u32_eval_assign(&async_loop_again, 1); - ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1); - cond_var_broadcast(async_tick_start_cond_var); - } - } -} - -//////////////////////////////// -//~ rjf: Search Artifact Cache Hooks / Lookups - -internal AC_Artifact -di2_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) -{ - ProfBeginFunction(); - Access *access = access_open(); - Temp scratch = scratch_begin(0, 0); - AC_Artifact artifact = {0}; - { - //- rjf: unpack key - RDI_SectionKind section_kind = RDI_SectionKind_NULL; - String8 query = {0}; - { - U64 key_read_off = 0; - key_read_off += str8_deserial_read_struct(key, key_read_off, §ion_kind); - key_read_off += str8_deserial_read_struct(key, key_read_off, &query.size); - query.str = push_array(scratch.arena, U8, query.size); - key_read_off += str8_deserial_read(key, key_read_off, query.str, query.size, 1); - } - - //- rjf: gather all debug info keys we'll search on - DI2_KeyArray keys = {0}; - ProfScope("gather all debug info keys we'll search on") - { - if(lane_idx() == 0) - { - keys = di2_push_all_loaded_keys(scratch.arena); - } - lane_sync_u64(&keys.v, 0); - lane_sync_u64(&keys.count, 0); - } - - //- rjf: map all debug info keys -> RDIs - RDI_Parsed **rdis = 0; - ProfScope("map all debug info keys -> RDIs") - { - if(lane_idx() == 0) - { - rdis = push_array(scratch.arena, RDI_Parsed *, keys.count); - } - lane_sync_u64(&rdis, 0); - { - Rng1U64 range = lane_range(keys.count); - for EachInRange(idx, range) - { - rdis[idx] = di2_rdi_from_key(access, keys.v[idx], 0, 0); - } - } - } - lane_sync(); - - //- rjf: do wide search on all lanes - Arena *arena = arena_alloc(); - DI2_SearchItemChunkList *lanes_items = 0; - ProfScope("do wide search on all lanes") - { - if(lane_idx() == 0) - { - lanes_items = push_array(scratch.arena, DI2_SearchItemChunkList, lane_count()); - } - lane_sync_u64(&lanes_items, 0); - { - DI2_SearchItemChunkList *lane_items = &lanes_items[lane_idx()]; - for EachIndex(rdi_idx, keys.count) - { - DI2_Key key = keys.v[rdi_idx]; - RDI_Parsed *rdi = rdis[rdi_idx]; - - // rjf: unpack table info - U64 element_count = 0; - void *table_base = rdi_section_raw_table_from_kind(rdi, section_kind, &element_count); - U64 element_size = rdi_section_element_size_table[section_kind]; - - // rjf: determine name string index offset, depending on table kind - U64 element_name_idx_off = 0; - switch(section_kind) - { - default:{}break; - case RDI_SectionKind_Procedures: - { - element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); - }break; - case RDI_SectionKind_GlobalVariables: - { - element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); - }break; - case RDI_SectionKind_ThreadVariables: - { - element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); - }break; - case RDI_SectionKind_UDTs: - { - // NOTE(rjf): name must be determined from self_type_idx - }break; - case RDI_SectionKind_SourceFiles: - { - // NOTE(rjf): name must be determined from file path node chain - }break; - } - - Rng1U64 range = lane_range(element_count); - for EachInRange(idx, range) - { - //- rjf: every so often, check if we need to cancel, and cancel - { - // TODO(rjf) - } - - //- rjf: get element, map to string; if empty, continue to next element - void *element = (U8 *)table_base + element_size*idx; - String8 name = {0}; - switch(section_kind) - { - case RDI_SectionKind_UDTs: - { - RDI_UDT *udt = (RDI_UDT *)element; - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); - name.str = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name.size); - name = str8_copy(arena, name); - }break; - case RDI_SectionKind_SourceFiles: - { - Temp scratch = scratch_begin(&arena, 1); - RDI_SourceFile *file = (RDI_SourceFile *)element; - String8List path_parts = {0}; - for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, file->file_path_node_idx); - fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0); - fpn = rdi_element_from_name_idx(rdi, FilePathNodes, fpn->parent_path_node)) - { - String8 path_part = {0}; - path_part.str = rdi_string_from_idx(rdi, fpn->name_string_idx, &path_part.size); - str8_list_push_front(scratch.arena, &path_parts, path_part); - } - StringJoin join = {0}; - join.sep = str8_lit("/"); - name = str8_list_join(arena, &path_parts, &join); - scratch_end(scratch); - }break; - default: - { - U32 name_idx = *(U32 *)((U8 *)element + element_name_idx_off); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); - name = str8(name_base, name_size); - }break; - } - if(name.size == 0) { continue; } - - //- rjf: fuzzy match against query - FuzzyMatchRangeList matches = fuzzy_match_find(arena, query, name); - - //- rjf: collect - if(matches.count == matches.needle_part_count) - { - DI2_SearchItemChunk *chunk = lane_items->last; - if(chunk == 0 || chunk->count >= chunk->cap) - { - chunk = push_array(scratch.arena, DI2_SearchItemChunk, 1); - chunk->base_idx = lane_items->total_count; - chunk->cap = 1024; - chunk->count = 0; - chunk->v = push_array_no_zero(scratch.arena, DI2_SearchItem, chunk->cap); - SLLQueuePush(lane_items->first, lane_items->last, chunk); - lane_items->chunk_count += 1; - } - chunk->v[chunk->count].idx = idx; - chunk->v[chunk->count].key = key; - chunk->v[chunk->count].match_ranges = matches; - chunk->v[chunk->count].missed_size = (name.size > matches.total_dim) ? (name.size-matches.total_dim) : 0; - chunk->count += 1; - lane_items->total_count += 1; - } - } - } - } - } - lane_sync(); - - //- rjf: join all lane chunk lists - DI2_SearchItemChunkList *all_items = &lanes_items[0]; - if(lane_idx() == 0) ProfScope("join all lane chunk lists") - { - for(U64 lidx = 1; lidx < lane_count(); lidx += 1) - { - DI2_SearchItemChunkList *dst = all_items; - DI2_SearchItemChunkList *to_push = &lanes_items[lidx]; - for EachNode(n, DI2_SearchItemChunk, to_push->first) - { - n->base_idx += dst->total_count; - } - if(dst->first && to_push->first) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - } - else if(dst->first == 0) - { - MemoryCopyStruct(dst, to_push); - } - MemoryZeroStruct(to_push); - } - } - lane_sync(); - - //- rjf: produce sort records - typedef struct SortRecord SortRecord; - struct SortRecord - { - U64 key; - DI2_SearchItem *item; - }; - U64 sort_records_count = all_items->total_count; - SortRecord *sort_records = 0; - SortRecord *sort_records__swap = 0; - ProfScope("produce sort records") - { - if(lane_idx() == 0) - { - sort_records = push_array(scratch.arena, SortRecord, sort_records_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - sort_records__swap = push_array(scratch.arena, SortRecord, sort_records_count); - } - lane_sync_u64(&sort_records, 0); - lane_sync_u64(&sort_records__swap, lane_from_task_idx(1)); - for EachNode(n, DI2_SearchItemChunk, all_items->first) - { - Rng1U64 range = lane_range(n->count); - U64 dst_idx = n->base_idx + range.min; - for EachInRange(n_idx, range) - { - DI2_SearchItem *item = &n->v[n_idx]; - sort_records[dst_idx].item = item; - sort_records[dst_idx].key = (((item->missed_size & 0xffffffffull) << 32) | (u64_hash_from_seed_str8(item->idx, str8_struct(&key)) & 0xffffffffull)); - dst_idx += 1; - } - } - } - lane_sync(); - - //- rjf: sort records - ProfScope("sort records") - { - //- rjf: set up common data - U64 bits_per_digit = 8; - U64 digits_count = 64 / bits_per_digit; - U64 num_possible_values_per_digit = 1 << bits_per_digit; - U32 **lanes_digit_counts = 0; - U32 **lanes_digit_offsets = 0; - if(lane_idx() == 0) - { - lanes_digit_counts = push_array(scratch.arena, U32 *, lane_count()); - lanes_digit_offsets = push_array(scratch.arena, U32 *, lane_count()); - } - lane_sync_u64(&lanes_digit_counts, 0); - lane_sync_u64(&lanes_digit_offsets, 0); - - //- rjf: set up this lane - lanes_digit_counts[lane_idx()] = push_array(scratch.arena, U32, num_possible_values_per_digit); - lanes_digit_offsets[lane_idx()] = push_array(scratch.arena, U32, num_possible_values_per_digit); - SortRecord *src = sort_records; - SortRecord *dst = sort_records__swap; - U64 count = sort_records_count; - - //- rjf: do all per-digit sorts - for EachIndex(digit_idx, digits_count) - { - // rjf: count digit value occurrences per-lane - { - U32 *digit_counts = lanes_digit_counts[lane_idx()]; - MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); - Rng1U64 range = lane_range(count); - for EachInRange(idx, range) - { - SortRecord *r = &src[idx]; - U16 digit_value = (U16)(U8)(r->key >> (digit_idx*bits_per_digit)); - digit_counts[digit_value] += 1; - } - } - lane_sync(); - - // rjf: compute thread * digit value *relative* offset table - { - Rng1U64 range = lane_range(num_possible_values_per_digit); - for EachInRange(value_idx, range) - { - U64 layout_off = 0; - for EachIndex(lane_idx, lane_count()) - { - lanes_digit_offsets[lane_idx][value_idx] = layout_off; - layout_off += lanes_digit_counts[lane_idx][value_idx]; - } - } - } - lane_sync(); - - // rjf: convert relative offsets -> absolute offsets - if(lane_idx() == 0) - { - U64 last_off = 0; - U64 num_of_nonzero_digit = 0; - for EachIndex(value_idx, num_possible_values_per_digit) - { - for EachIndex(lane_idx, lane_count()) - { - lanes_digit_offsets[lane_idx][value_idx] += last_off; - } - last_off = lanes_digit_offsets[lane_count()-1][value_idx] + lanes_digit_counts[lane_count()-1][value_idx]; - } - // NOTE(rjf): required that: (last_off == element_count) - } - lane_sync(); - - // rjf: move - { - U32 *lane_digit_offsets = lanes_digit_offsets[lane_idx()]; - Rng1U64 range = lane_range(count); - for EachInRange(idx, range) - { - SortRecord *src_r = &src[idx]; - U16 digit_value = (U16)(U8)(src_r->key >> (digit_idx*bits_per_digit)); - U64 dst_off = lane_digit_offsets[digit_value]; - lane_digit_offsets[digit_value] += 1; - MemoryCopyStruct(&dst[dst_off], src_r); - } - } - lane_sync(); - - // rjf: swap - { - SortRecord *swap = src; - src = dst; - dst = swap; - } - } - } - lane_sync(); - - //- rjf: produce final array - DI2_SearchItemArray items = {0}; - ProfScope("produce final array") - { - if(lane_idx() == 0) - { - items.count = all_items->total_count; - items.v = push_array(arena, DI2_SearchItem, items.count); - } - lane_sync_u64(&items.count, 0); - lane_sync_u64(&items.v, 0); - Rng1U64 range = lane_range(sort_records_count); - for EachInRange(idx, range) - { - SortRecord *record = &sort_records[idx]; - DI2_SearchItem *dst_item = &items.v[idx]; - MemoryCopyStruct(dst_item, record->item); - } - } - lane_sync(); - - //- rjf: bundle as artifact - artifact.u64[0] = (U64)arena; - artifact.u64[1] = (U64)items.v; - artifact.u64[2] = items.count; - } - scratch_end(scratch); - access_close(access); - ProfEnd(); - return artifact; -} - -internal void -di2_search_artifact_destroy(AC_Artifact artifact) -{ - Arena *arena = (Arena *)artifact.u64[0]; - if(arena != 0) - { - arena_release(arena); - } -} - -internal DI2_SearchItemArray -di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us) -{ - DI2_SearchItemArray result = {0}; - { - Temp scratch = scratch_begin(0, 0); - - // rjf: form key - String8List key_parts = {0}; - str8_list_push(scratch.arena, &key_parts, str8_struct(&target)); - str8_list_push(scratch.arena, &key_parts, str8_struct(&query.size)); - str8_list_push(scratch.arena, &key_parts, query); - String8 key = str8_list_join(scratch.arena, &key_parts, 0); - - // rjf: get artifact - AC_Artifact artifact = ac_artifact_from_key(access, key, di2_search_artifact_create, di2_search_artifact_destroy, endt_us, .gen = di2_load_gen(), .flags = AC_Flag_Wide); - - // rjf: unpack artifact - result.v = (DI2_SearchItem *)artifact.u64[1]; - result.count = artifact.u64[2]; - - scratch_end(scratch); - } - return result; -} - -//////////////////////////////// -//~ rjf: Match Artifact Cache Hooks / Lookups - -internal AC_Artifact -di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - //- rjf: unpack key - U64 index = 0; - String8 name = {0}; - { - U64 key_read_off = 0; - key_read_off += str8_deserial_read_struct(key, key_read_off, &index); - key_read_off += str8_deserial_read_struct(key, key_read_off, &name.size); - name.str = push_array_no_zero(scratch.arena, U8, name.size); - key_read_off += str8_deserial_read(key, key_read_off, name.str, name.size, 1); - } - - //- rjf: get all loaded keys - DI2_KeyArray dbgi_keys = di2_push_all_loaded_keys(scratch.arena); - - //- rjf: wide search across all debug infos - DI2_Match *lane_matches = 0; - if(lane_idx() == 0) - { - lane_matches = push_array(scratch.arena, DI2_Match, lane_count()); - } - lane_sync_u64(&lane_matches, 0); - { - read_only local_persist RDI_NameMapKind name_map_kinds[] = - { - RDI_NameMapKind_GlobalVariables, - RDI_NameMapKind_ThreadVariables, - RDI_NameMapKind_Constants, - RDI_NameMapKind_Procedures, - RDI_NameMapKind_Types, - }; - read_only local_persist RDI_SectionKind name_map_section_kinds[] = - { - RDI_SectionKind_GlobalVariables, - RDI_SectionKind_ThreadVariables, - RDI_SectionKind_Constants, - RDI_SectionKind_Procedures, - RDI_SectionKind_TypeNodes, - }; - Rng1U64 range = lane_range(dbgi_keys.count); - for EachInRange(dbgi_idx, range) - { - Access *access = access_open(); - { - DI2_Key dbgi_key = dbgi_keys.v[dbgi_idx]; - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); - for EachElement(name_map_kind_idx, name_map_kinds) - { - RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, name_map_kinds[name_map_kind_idx]); - RDI_ParsedNameMap parsed_name_map = {0}; - rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); - RDI_NameMapNode *map_node = rdi_name_map_lookup(rdi, &parsed_name_map, name.str, name.size); - U32 num = 0; - U32 *run = rdi_matches_from_map_node(rdi, map_node, &num); - if(num != 0) - { - lane_matches[lane_idx()].key = dbgi_key; - lane_matches[lane_idx()].section_kind = name_map_section_kinds[name_map_kind_idx]; - lane_matches[lane_idx()].idx = run[num-1]; - } - } - } - access_close(access); - } - } - lane_sync(); - - //- rjf: pick match - DI2_Match match = {0}; - for EachIndex(idx, lane_count()) - { - if(lane_matches[idx].idx != 0) - { - match = lane_matches[idx]; - break; - } - } - - //- rjf: package as artifact - AC_Artifact artifact = {0}; - { - StaticAssert(ArrayCount(artifact.u64) >= 4, artifact_size_check); - artifact.u64[0] = match.key.u64[0]; - artifact.u64[1] = match.key.u64[1]; - artifact.u64[2] = match.section_kind; - artifact.u64[3] = match.idx; - } - - lane_sync(); - scratch_end(scratch); - ProfEnd(); - return artifact; -} - -internal DI2_Match -di2_match_from_string(String8 string, U64 index, U64 endt_us) -{ - DI2_Match result = {0}; - Access *access = access_open(); - Temp scratch = scratch_begin(0, 0); - { - String8List key_parts = {0}; - str8_list_push(scratch.arena, &key_parts, str8_struct(&index)); - str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); - str8_list_push(scratch.arena, &key_parts, string); - String8 key = str8_list_join(scratch.arena, &key_parts, 0); - AC_Artifact artifact = ac_artifact_from_key(access, key, di2_match_artifact_create, 0, endt_us, .flags = AC_Flag_Wide, .gen = di2_load_gen()); - result.key.u64[0] = artifact.u64[0]; - result.key.u64[1] = artifact.u64[1]; - result.section_kind = artifact.u64[2]; - result.idx = artifact.u64[3]; - } - scratch_end(scratch); - access_close(access); - return result; -} diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h deleted file mode 100644 index f406d825..00000000 --- a/src/dbg_info/dbg_info2.h +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef DBG_INFO2_H -#define DBG_INFO2_H - -//////////////////////////////// -//~ rjf: Unique Debug Info Key - -typedef struct DI2_Key DI2_Key; -struct DI2_Key -{ - U64 u64[2]; -}; - -typedef struct DI2_KeyNode DI2_KeyNode; -struct DI2_KeyNode -{ - DI2_KeyNode *next; - DI2_Key v; -}; - -typedef struct DI2_KeyList DI2_KeyList; -struct DI2_KeyList -{ - DI2_KeyNode *first; - DI2_KeyNode *last; - U64 count; -}; - -typedef struct DI2_KeyArray DI2_KeyArray; -struct DI2_KeyArray -{ - DI2_Key *v; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Debug Info Path / Timestamp => Key Cache Types - -typedef struct DI2_KeyPathNode DI2_KeyPathNode; -struct DI2_KeyPathNode -{ - DI2_KeyPathNode *next; - DI2_KeyPathNode *prev; - String8 path; - U64 min_timestamp; - DI2_Key key; -}; - -typedef struct DI2_KeySlot DI2_KeySlot; -struct DI2_KeySlot -{ - DI2_KeyPathNode *first; - DI2_KeyPathNode *last; -}; - -//////////////////////////////// -//~ rjf: Debug Info Cache Types - -typedef struct DI2_Node DI2_Node; -struct DI2_Node -{ - // rjf: links - DI2_Node *next; - DI2_Node *prev; - - // rjf: key - DI2_Key key; - - // rjf: value - OS_Handle file; - OS_Handle file_map; - void *file_base; - FileProperties file_props; - Arena *arena; - RDI_Parsed rdi; - - // rjf: metadata - AccessPt access_pt; - U64 refcount; - U64 batch_request_counts[2]; - U64 working_count; - U64 completion_count; -}; - -typedef struct DI2_Slot DI2_Slot; -struct DI2_Slot -{ - DI2_Node *first; - DI2_Node *last; -}; - -//////////////////////////////// -//~ rjf: Requests - -typedef struct DI2_Request DI2_Request; -struct DI2_Request -{ - DI2_Key key; -}; - -typedef struct DI2_RequestNode DI2_RequestNode; -struct DI2_RequestNode -{ - DI2_RequestNode *next; - DI2_Request v; -}; - -typedef struct DI2_RequestBatch DI2_RequestBatch; -struct DI2_RequestBatch -{ - Mutex mutex; - Arena *arena; - DI2_RequestNode *first; - DI2_RequestNode *last; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Load Tasks - -typedef enum DI2_LoadTaskStatus -{ - DI2_LoadTaskStatus_Null, - DI2_LoadTaskStatus_Active, - DI2_LoadTaskStatus_Done, -} -DI2_LoadTaskStatus; - -typedef struct DI2_LoadTask DI2_LoadTask; -struct DI2_LoadTask -{ - DI2_LoadTask *next; - DI2_LoadTask *prev; - - DI2_Key key; - DI2_LoadTaskStatus status; - - B32 og_analyzed; - B32 og_is_rdi; - U64 og_size; - - B32 rdi_analyzed; - B32 rdi_is_stale; - - U64 thread_count; - OS_Handle process; -}; - -typedef struct DI2_LoadCompletion DI2_LoadCompletion; -struct DI2_LoadCompletion -{ - DI2_LoadCompletion *next; - U64 code; -}; - -//////////////////////////////// -//~ rjf: Search Types - -typedef struct DI2_SearchItem DI2_SearchItem; -struct DI2_SearchItem -{ - U64 idx; - DI2_Key key; - U64 missed_size; - FuzzyMatchRangeList match_ranges; -}; - -typedef struct DI2_SearchItemChunk DI2_SearchItemChunk; -struct DI2_SearchItemChunk -{ - DI2_SearchItemChunk *next; - U64 base_idx; - DI2_SearchItem *v; - U64 count; - U64 cap; -}; - -typedef struct DI2_SearchItemChunkList DI2_SearchItemChunkList; -struct DI2_SearchItemChunkList -{ - DI2_SearchItemChunk *first; - DI2_SearchItemChunk *last; - U64 chunk_count; - U64 total_count; -}; - -typedef struct DI2_SearchItemArray DI2_SearchItemArray; -struct DI2_SearchItemArray -{ - DI2_SearchItem *v; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Match Types - -typedef struct DI2_Match DI2_Match; -struct DI2_Match -{ - DI2_Key key; - RDI_SectionKind section_kind; - U32 idx; -}; - -//////////////////////////////// -//~ rjf: Shared State - -typedef struct DI2_Shared DI2_Shared; -struct DI2_Shared -{ - Arena *arena; - U64 load_gen; - - // rjf: key -> path cache - U64 key2path_slots_count; - DI2_KeySlot *key2path_slots; - StripeArray key2path_stripes; - - // rjf: path -> key cache - U64 path2key_slots_count; - DI2_KeySlot *path2key_slots; - StripeArray path2key_stripes; - - // rjf: debug info cache - U64 slots_count; - DI2_Slot *slots; - StripeArray stripes; - - // rjf: requests - DI2_RequestBatch req_batches[2]; // [0] -> high priority, [1] -> low priority - - // rjf: conversion tasks - DI2_LoadTask *first_load_task; - DI2_LoadTask *last_load_task; - DI2_LoadTask *free_load_task; - U64 conversion_process_count; - U64 conversion_thread_count; - - // rjf: conversion completion receiving thread - U64 conversion_completion_code; - String8 conversion_completion_lock_semaphore_name; - String8 conversion_completion_signal_semaphore_name; - String8 conversion_completion_shared_memory_name; - Semaphore conversion_completion_lock_semaphore; - Semaphore conversion_completion_signal_semaphore; - OS_Handle conversion_completion_shared_memory; - U64 *conversion_completion_shared_memory_base; - Thread conversion_completion_signal_receiver_thread; - - // rjf: completion batch - Mutex completion_mutex; - Arena *completion_arena; - DI2_LoadCompletion *first_completion; - DI2_LoadCompletion *last_completion; -}; - -//////////////////////////////// -//~ rjf: Globals - -global DI2_Shared *di2_shared = 0; - -//////////////////////////////// -//~ rjf: Helpers - -internal DI2_Key di2_key_zero(void); -internal B32 di2_key_match(DI2_Key a, DI2_Key b); -internal void di2_key_list_push(Arena *arena, DI2_KeyList *list, DI2_Key key); -internal DI2_KeyArray di2_key_array_from_list(Arena *arena, DI2_KeyList *list); - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void di2_init(CmdLine *cmdline); - -//////////////////////////////// -//~ rjf: Path * Timestamp Cache Submission & Lookup - -internal DI2_Key di2_key_from_path_timestamp(String8 path, U64 min_timestamp); - -//////////////////////////////// -//~ rjf: Debug Info Opening / Closing - -internal void di2_open(DI2_Key key); -internal void di2_close(DI2_Key key); - -//////////////////////////////// -//~ rjf: Debug Info Lookups - -internal U64 di2_load_gen(void); -internal DI2_KeyArray di2_push_all_loaded_keys(Arena *arena); -internal RDI_Parsed *di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us); - -//////////////////////////////// -//~ rjf: Asynchronous Tick - -internal void di2_async_tick(void); - -//////////////////////////////// -//~ rjf: Conversion Completion Signal Receiver Thread - -internal void di2_signal_completion(void); -internal void di2_conversion_completion_signal_receiver_thread_entry_point(void *p); - -//////////////////////////////// -//~ rjf: Search Artifact Cache Hooks / Lookups - -internal AC_Artifact di2_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); -internal void di2_search_artifact_destroy(AC_Artifact artifact); -internal DI2_SearchItemArray di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us); - -//////////////////////////////// -//~ rjf: Match Artifact Cache Hooks / Lookups - -internal AC_Artifact di2_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); -internal DI2_Match di2_match_from_string(String8 string, U64 index, U64 endt_us); - -#endif // DBG_INFO2_H diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index b740448a..126fd52c 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -185,7 +185,7 @@ dasm_params_match(DASM_Params *a, DASM_Params *b) a->style_flags == b->style_flags && a->syntax == b->syntax && a->base_vaddr == b->base_vaddr && - di2_key_match(a->dbgi_key, b->dbgi_key)); + di_key_match(a->dbgi_key, b->dbgi_key)); return result; } @@ -285,9 +285,9 @@ dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) //- rjf: get dbg info B32 stale = 0; RDI_Parsed *rdi = &rdi_parsed_nil; - if(!di2_key_match(params.dbgi_key, di2_key_zero())) + if(!di_key_match(params.dbgi_key, di_key_zero())) { - rdi = di2_rdi_from_key(access, params.dbgi_key, 0, 0); + rdi = di_rdi_from_key(access, params.dbgi_key, 0, 0); stale = (stale || (rdi == &rdi_parsed_nil)); } diff --git a/src/disasm/disasm.h b/src/disasm/disasm.h index 9b5c9b54..0001693c 100644 --- a/src/disasm/disasm.h +++ b/src/disasm/disasm.h @@ -97,7 +97,7 @@ struct DASM_Params DASM_StyleFlags style_flags; DASM_Syntax syntax; U64 base_vaddr; - DI2_Key dbgi_key; + DI_Key dbgi_key; }; //////////////////////////////// diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 2f5131e9..164b5849 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -1871,7 +1871,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I Access *access = access_open(); // rjf: find match - DI2_Match match = di2_match_from_string(string, 0, 0); + DI_Match match = di_match_from_string(string, 0, 0); if(match.idx == 0) { String8List namespaceified_strings = {0}; @@ -1900,7 +1900,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } for(String8Node *n = namespaceified_strings.first; n != 0; n = n->next) { - match = di2_match_from_string(n->string, 0, 0); + match = di_match_from_string(n->string, 0, 0); if(match.idx != 0) { break; @@ -1909,7 +1909,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } // rjf: match -> RDI - RDI_Parsed *rdi = di2_rdi_from_key(access, match.key, 0, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, match.key, 0, 0); // rjf: find module from dbgi key U32 dbgi_idx = 0; diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index 9feaad41..269b41be 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -585,11 +585,11 @@ e_leaf_type_key_from_name(String8 name) E_TypeKey key = e_leaf_builtin_type_key_from_name(name); if(!e_type_key_match(e_type_key_zero(), key)) { - DI2_Match match = di2_match_from_string(name, 0, 0); + DI_Match match = di_match_from_string(name, 0, 0); if(match.section_kind == RDI_SectionKind_TypeNodes) { Access *access = access_open(); - RDI_Parsed *rdi = di2_rdi_from_key(access, match.key, 0, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, match.key, 0, 0); for EachIndex(idx, e_base_ctx->modules_count) { E_Module *module = &e_base_ctx->modules[idx]; diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 199f0699..140275af 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -520,7 +520,7 @@ Rng1U64 rd_reg_slot_range_table[47] = {OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(C_Key)}, {OffsetOf(RD_Regs, lang_kind), OffsetOf(RD_Regs, lang_kind) + sizeof(TXT_LangKind)}, {OffsetOf(RD_Regs, lines), OffsetOf(RD_Regs, lines) + sizeof(D_LineList)}, -{OffsetOf(RD_Regs, dbgi_key), OffsetOf(RD_Regs, dbgi_key) + sizeof(DI2_Key)}, +{OffsetOf(RD_Regs, dbgi_key), OffsetOf(RD_Regs, dbgi_key) + sizeof(DI_Key)}, {OffsetOf(RD_Regs, vaddr), OffsetOf(RD_Regs, vaddr) + sizeof(U64)}, {OffsetOf(RD_Regs, voff), OffsetOf(RD_Regs, voff) + sizeof(U64)}, {OffsetOf(RD_Regs, vaddr_range), OffsetOf(RD_Regs, vaddr_range) + sizeof(Rng1U64)}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index fd98a78b..14e419f0 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -466,7 +466,7 @@ TxtPt mark; C_Key text_key; TXT_LangKind lang_kind; D_LineList lines; -DI2_Key dbgi_key; +DI_Key dbgi_key; U64 vaddr; U64 voff; Rng1U64 vaddr_range; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index f340f64c..2e24874c 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -736,7 +736,7 @@ RD_RegTable: {C_Key text_key TextKey } {TXT_LangKind lang_kind LangKind } {D_LineList lines Lines } - {DI2_Key dbgi_key DbgiKey } + {DI_Key dbgi_key DbgiKey } {U64 vaddr Vaddr } {U64 voff Voff } {Rng1U64 vaddr_range VaddrRange } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 4147365d..05683584 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -3273,11 +3273,11 @@ rd_view_ui(Rng2F32 rect) U64 vaddr = eval.value.u64; CTRL_Entity *process = rd_ctrl_entity_from_eval_space(eval.space); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 voff = ctrl_voff_from_vaddr(module, vaddr); { Access *access = access_open(); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); String8 name = {0}; if(name.size == 0) { @@ -3360,11 +3360,11 @@ rd_view_ui(Rng2F32 rect) U64 vaddr = eval.value.u64; CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 voff = ctrl_voff_from_vaddr(module, vaddr); { Access *access = access_open(); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 1, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0); if(name.size == 0) { RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); @@ -5298,7 +5298,7 @@ rd_view_ui(Rng2F32 rect) { U64 vaddr = cell->eval.value.u64; CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 voff = ctrl_voff_from_vaddr(module, vaddr); D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, voff); String8 file_path = {0}; @@ -6444,8 +6444,8 @@ rd_window_frame(void) { Access *access = access_open(); CTRL_Entity *dbg_info_entity = ctrl_entity_child_from_kind(ctrl_entity, CTRL_EntityKind_DebugInfoPath); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(ctrl_entity); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(ctrl_entity); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); if(rdi->raw_data_size != 0) { ui_labelf("Symbols successfully loaded from %S", dbg_info_entity->string); @@ -10311,7 +10311,7 @@ rd_code_color_slot_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 // rjf: try to map using asynchronous matching system if(!mapped && kind == TXT_TokenKind_Identifier) { - DI2_Match match = di2_match_from_string(string, 0, 0); + DI_Match match = di_match_from_string(string, 0, 0); RDI_SectionKind section_kind = match.section_kind; mapped = 1; switch(section_kind) @@ -11872,15 +11872,15 @@ rd_frame(void) E_Module *eval_modules_primary = &eval_modules[0]; eval_modules_primary->rdi = &rdi_parsed_nil; eval_modules_primary->vaddr_range = r1u64(0, max_U64); - DI2_Key primary_dbgi_key = {0}; + DI_Key primary_dbgi_key = {0}; ProfScope("produce all eval modules") { for EachIndex(eval_module_idx, all_modules.count) { CTRL_Entity *m = all_modules.v[eval_module_idx]; - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(m); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(m); eval_modules[eval_module_idx].arch = m->arch; - eval_modules[eval_module_idx].rdi = di2_rdi_from_key(rd_state->frame_access, dbgi_key, 0, 0); + eval_modules[eval_module_idx].rdi = di_rdi_from_key(rd_state->frame_access, dbgi_key, 0, 0); eval_modules[eval_module_idx].vaddr_range = m->vaddr_range; eval_modules[eval_module_idx].space = rd_eval_space_from_ctrl_entity(ctrl_entity_ancestor_from_kind(m, CTRL_EntityKind_Process), RD_EvalSpaceKind_CtrlEntity); if(module == m) @@ -14678,8 +14678,8 @@ rd_frame(void) U64 rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_index); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, rip_voff); D_Line line = {0}; @@ -14695,7 +14695,7 @@ rd_frame(void) } } B32 missing_rip = (rip_vaddr == 0); - B32 dbgi_missing = (di2_key_match(di2_key_zero(), dbgi_key)); + B32 dbgi_missing = (di_key_match(di_key_zero(), dbgi_key)); B32 dbgi_pending = !dbgi_missing && rdi == &rdi_parsed_nil; B32 has_line_info = (line.voff_range.max != 0); B32 has_module = (module != &ctrl_entity_nil); @@ -14759,16 +14759,16 @@ rd_frame(void) // rjf: try to resolve name as a symbol U64 voff = 0; - DI2_Key voff_dbgi_key = {0}; + DI_Key voff_dbgi_key = {0}; if(!name_resolved) { - DI2_Match match = di2_match_from_string(name, 0, 0); + DI_Match match = di_match_from_string(name, 0, 0); if(match.section_kind == RDI_SectionKind_Procedures) { Access *access = access_open(); { name_resolved = 1; - RDI_Parsed *rdi = di2_rdi_from_key(access, match.key, 0, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, match.key, 0, 0); RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, match.idx); voff = rdi_first_voff_from_procedure(rdi, procedure); voff_dbgi_key = match.key; diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 23df8995..e2d8930e 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1634,7 +1634,7 @@ typedef struct RD_DebugInfoTableLookupAccel RD_DebugInfoTableLookupAccel; struct RD_DebugInfoTableLookupAccel { RDI_SectionKind section; - DI2_SearchItemArray items; + DI_SearchItemArray items; }; E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) @@ -1662,12 +1662,12 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) U64 endt_us = rd_state->frame_eval_memread_endt_us; U128 fuzzy_search_key = {d_hash_from_string(str8_struct(&rd_regs()->view)), (U64)section}; accel->section = section; - accel->items = di2_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us); + accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us); RD_ViewState *vs = rd_view_state_from_cfg(rd_cfg_from_id(rd_regs()->view)); if(accel->items.count == 0) { String8 last_query = str8(vs->last_successful_query_buffer, vs->last_successful_query_string_size); - accel->items = di2_search_item_array_from_target_query(rd_state->frame_access, section, last_query, endt_us); + accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, last_query, endt_us); } else { @@ -1691,8 +1691,8 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table) Access *access = access_open(); // rjf: unpack row - DI2_SearchItem *item = &accel->items.v[idx_range.min + idx]; - RDI_Parsed *rdi = di2_rdi_from_key(access, item->key, 0, 0); + DI_SearchItem *item = &accel->items.v[idx_range.min + idx]; + RDI_Parsed *rdi = di_rdi_from_key(access, item->key, 0, 0); // rjf: get item's string String8 item_string = {0}; diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 2dc89e6c..a59ab36f 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -219,7 +219,6 @@ #include "base/base_inc.h" #include "linker/hash_table.h" #include "os/os_inc.h" -#include "async/async.h" #include "artifact_cache/artifact_cache.h" #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" @@ -248,7 +247,7 @@ #include "radbin/radbin.h" #include "regs/regs.h" #include "regs/rdi/regs_rdi.h" -#include "dbg_info/dbg_info2.h" +#include "dbg_info/dbg_info.h" #include "disasm/disasm.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" @@ -266,7 +265,6 @@ #include "base/base_inc.c" #include "linker/hash_table.c" #include "os/os_inc.c" -#include "async/async.c" #include "artifact_cache/artifact_cache.c" #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" @@ -295,7 +293,7 @@ #include "radbin/radbin.c" #include "regs/regs.c" #include "regs/rdi/regs_rdi.c" -#include "dbg_info/dbg_info2.c" +#include "dbg_info/dbg_info.c" #include "disasm/disasm.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" @@ -749,7 +747,7 @@ entry_point(CmdLine *cmd_line) case ExecMode_BinaryUtility: { rb_entry_point(cmd_line); - di2_signal_completion(); + di_signal_completion(); }break; //- rjf: help message box diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 2054e97e..4d80c187 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -20,7 +20,7 @@ rd_code_view_init(RD_CodeViewState *cv) } internal RD_CodeViewBuildResult -rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags flags, Rng2F32 rect, String8 text_data, TXT_TextInfo *text_info, DASM_LineArray *dasm_lines, Rng1U64 dasm_vaddr_range, DI2_Key dasm_dbgi_key) +rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags flags, Rng2F32 rect, String8 text_data, TXT_TextInfo *text_info, DASM_LineArray *dasm_lines, Rng1U64 dasm_vaddr_range, DI_Key dasm_dbgi_key) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -289,7 +289,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla U64 last_inst_on_unwound_rip_vaddr = rip_vaddr - !!unwind_count; CTRL_Entity *module = ctrl_module_from_process_vaddr(process, last_inst_on_unwound_rip_vaddr); U64 rip_voff = ctrl_voff_from_vaddr(module, last_inst_on_unwound_rip_vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, rip_voff); for(D_LineNode *n = lines.first; n != 0; n = n->next) { @@ -341,7 +341,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla { String8 file_path = rd_regs()->file_path; CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); D_LineListArray lines_array = d_lines_array_from_dbgi_key_file_path_line_range(scratch.arena, dbgi_key, file_path, visible_line_num_range); if(lines_array.count != 0) { @@ -423,7 +423,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla if(dasm_lines) { CTRL_Entity *module = ctrl_module_from_process_vaddr(process, dasm_vaddr_range.min); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) { U64 vaddr = dasm_vaddr_range.min + dasm_line_array_code_off_from_idx(dasm_lines, line_num-1); @@ -437,7 +437,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: add dasm dbgi key to relevant dbgis if(dasm_lines != 0) { - di2_key_list_push(scratch.arena, &code_slice_params.relevant_dbgi_keys, dasm_dbgi_key); + di_key_list_push(scratch.arena, &code_slice_params.relevant_dbgi_keys, dasm_dbgi_key); } } @@ -813,9 +813,9 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // RD_CodeViewBuildResult result = {0}; { - for(DI2_KeyNode *n = code_slice_params.relevant_dbgi_keys.first; n != 0; n = n->next) + for(DI_KeyNode *n = code_slice_params.relevant_dbgi_keys.first; n != 0; n = n->next) { - di2_key_list_push(arena, &result.dbgi_keys, n->v); + di_key_list_push(arena, &result.dbgi_keys, n->v); } } @@ -2147,7 +2147,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) ////////////////////////////// //- rjf: build code contents // - DI2_KeyList dbgi_keys = {0}; + DI_KeyList dbgi_keys = {0}; if(!file_is_missing) { RD_CodeViewBuildFlags flags = RD_CodeViewBuildFlag_All; @@ -2155,7 +2155,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) { flags &= ~RD_CodeViewBuildFlag_Margins; } - RD_CodeViewBuildResult result = rd_code_view_build(scratch.arena, cv, flags, code_area_rect, data, &info, 0, r1u64(0, 0), di2_key_zero()); + RD_CodeViewBuildResult result = rd_code_view_build(scratch.arena, cv, flags, code_area_rect, data, &info, 0, r1u64(0, 0), di_key_zero()); dbgi_keys = result.dbgi_keys; } @@ -2165,7 +2165,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) if(rd_regs()->file_path.size != 0) { CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); rd_regs()->lines = d_lines_from_dbgi_key_file_path_line_num(rd_frame_arena(), dbgi_key, rd_regs()->file_path, rd_regs()->cursor.line); } @@ -2178,9 +2178,9 @@ RD_VIEW_UI_FUNCTION_DEF(text) U64 file_timestamp = os_properties_from_file_path(rd_regs()->file_path).modified; if(file_timestamp != 0) { - for(DI2_KeyNode *n = dbgi_keys.first; n != 0; n = n->next) + for(DI_KeyNode *n = dbgi_keys.first; n != 0; n = n->next) { - DI2_Key key = n->v; + DI_Key key = n->v; // TODO(rjf): @dbgi2 #if 0 if(key.min_timestamp < file_timestamp && key.min_timestamp != 0 && key.path.size != 0) @@ -2358,7 +2358,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) Arch arch = rd_arch_from_eval(eval); CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(space); CTRL_Entity *dasm_module = &ctrl_entity_nil; - DI2_Key dbgi_key = {0}; + DI_Key dbgi_key = {0}; U64 base_vaddr = 0; switch(space_entity->kind) { @@ -2958,8 +2958,8 @@ RD_VIEW_UI_FUNCTION_DEF(memory) U64 f_rip_vaddr = regs_rip_from_arch_block(selected_thread->arch, f->regs); CTRL_Entity *module = ctrl_module_from_process_vaddr(selected_process, f_rip_vaddr); U64 f_rip_voff = ctrl_voff_from_vaddr(module, f_rip_vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, f_rip_voff); String8 procedure_name = {0}; procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size); @@ -3071,8 +3071,8 @@ RD_VIEW_UI_FUNCTION_DEF(memory) if(module != &ctrl_entity_nil) { U64 voff = ctrl_voff_from_vaddr(module, vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); RDI_Scope *root_scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx); if(procedure->root_scope_idx != 0) @@ -3128,8 +3128,8 @@ RD_VIEW_UI_FUNCTION_DEF(memory) if(module != &ctrl_entity_nil) { U64 voff = ctrl_voff_from_vaddr(module, vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); RDI_GlobalVariable *gvar = rdi_global_variable_from_voff(rdi, voff); if(gvar->voff != 0) { diff --git a/src/raddbg/raddbg_views.h b/src/raddbg/raddbg_views.h index 9ac7da52..f13b2ecc 100644 --- a/src/raddbg/raddbg_views.h +++ b/src/raddbg/raddbg_views.h @@ -67,7 +67,7 @@ struct RD_CodeViewState typedef struct RD_CodeViewBuildResult RD_CodeViewBuildResult; struct RD_CodeViewBuildResult { - DI2_KeyList dbgi_keys; + DI_KeyList dbgi_keys; }; //////////////////////////////// @@ -199,7 +199,7 @@ struct RD_WatchViewState //~ rjf: Code View Functions internal void rd_code_view_init(RD_CodeViewState *cv); -internal RD_CodeViewBuildResult rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags flags, Rng2F32 rect, String8 text_data, TXT_TextInfo *text_info, DASM_LineArray *dasm_lines, Rng1U64 dasm_vaddr_range, DI2_Key dasm_dbgi_key); +internal RD_CodeViewBuildResult rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags flags, Rng2F32 rect, String8 text_data, TXT_TextInfo *text_info, DASM_LineArray *dasm_lines, Rng1U64 dasm_vaddr_range, DI_Key dasm_dbgi_key); //////////////////////////////// //~ rjf: Watch View Functions diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index ac5d94cf..e61c9d4c 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -563,8 +563,8 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); String8 name = {0}; { - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); if(rdi != &rdi_parsed_nil) { RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, rip_voff); @@ -597,8 +597,8 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e if(entity->kind == CTRL_EntityKind_Module && include_extras) { Access *access = access_open(); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(entity); - RDI_Parsed *rdi = di2_rdi_from_key(access, dbgi_key, 0, 0); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(entity); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); if(rdi->raw_data_size == 0) { dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); @@ -1417,7 +1417,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe U64 thread_rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, thread_rip_vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color @@ -1488,7 +1488,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe D_Line *line = 0; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - if(di2_key_match(n->v.dbgi_key, dbgi_key)) + if(di_key_match(n->v.dbgi_key, dbgi_key)) { line = &n->v; break; @@ -1573,7 +1573,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe U64 thread_rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, thread_rip_vaddr); - DI2_Key dbgi_key = ctrl_dbgi_key_from_module(module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color @@ -1642,7 +1642,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe D_Line *line = 0; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - if(di2_key_match(n->v.dbgi_key, dbgi_key)) + if(di_key_match(n->v.dbgi_key, dbgi_key)) { line = &n->v; break; @@ -2796,7 +2796,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe for(D_LineNode *n = lines->first; n != 0; n = n->next) { if((n->v.pt.line == line_num || params->line_vaddrs[line_idx] != 0) && - ((di2_key_match(n->v.dbgi_key, hover_regs->dbgi_key) && + ((di_key_match(n->v.dbgi_key, hover_regs->dbgi_key) && n->v.voff_range.min <= hover_voff_range.min && hover_voff_range.min < n->v.voff_range.max) || (params->line_vaddrs[line_idx] == hover_regs->vaddr_range.min && hover_regs->vaddr_range.min != 0))) { diff --git a/src/raddbg/raddbg_widgets.h b/src/raddbg/raddbg_widgets.h index ce426e18..88678f99 100644 --- a/src/raddbg/raddbg_widgets.h +++ b/src/raddbg/raddbg_widgets.h @@ -104,7 +104,7 @@ struct RD_CodeSliceParams RD_CfgList *line_pins; U64 *line_vaddrs; D_LineList *line_infos; - DI2_KeyList relevant_dbgi_keys; + DI_KeyList relevant_dbgi_keys; TXT_TextInfo *text_info; String8 text_data; diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 7729b4e1..cd79bb71 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -17,7 +17,7 @@ #include "artifact_cache/artifact_cache.h" #include "file_stream/file_stream.h" #include "rdi/rdi_local.h" -#include "dbg_info/dbg_info2.h" +#include "dbg_info/dbg_info.h" //- rjf: [c] #include "base/base_inc.c" @@ -26,7 +26,7 @@ #include "artifact_cache/artifact_cache.c" #include "file_stream/file_stream.c" #include "rdi/rdi_local.c" -#include "dbg_info/dbg_info2.c" +#include "dbg_info/dbg_info.c" //////////////////////////////// //~ rjf: Entry Point @@ -40,12 +40,12 @@ entry_point(CmdLine *cmdline) // #include "fn_debug_infos.inc" }; - DI2_Key keys[ArrayCount(pdb_paths)] = {0}; + DI_Key keys[ArrayCount(pdb_paths)] = {0}; for EachElement(idx, pdb_paths) { String8 path = str8_cstring(pdb_paths[idx]); - keys[idx] = di2_key_from_path_timestamp(path, 0); - di2_open(keys[idx]); + keys[idx] = di_key_from_path_timestamp(path, 0); + di_open(keys[idx]); } for(;;) @@ -55,7 +55,7 @@ entry_point(CmdLine *cmdline) U64 num_rdis_loaded = 0; for EachElement(idx, pdb_paths) { - RDI_Parsed *rdi = di2_rdi_from_key(access, keys[idx], 1, 0); + RDI_Parsed *rdi = di_rdi_from_key(access, keys[idx], 1, 0); if(rdi == &rdi_parsed_nil) { got_all_rdis = 0; @@ -65,19 +65,19 @@ entry_point(CmdLine *cmdline) num_rdis_loaded += 1; } } - printf("\rloaded [%I64u/%I64u], %I64u active threads, %I64u active processes", num_rdis_loaded, ArrayCount(pdb_paths), di2_shared->conversion_thread_count, di2_shared->conversion_process_count); + printf("\rloaded [%I64u/%I64u], %I64u active threads, %I64u active processes", num_rdis_loaded, ArrayCount(pdb_paths), di_shared->conversion_thread_count, di_shared->conversion_process_count); access_close(access); if(got_all_rdis) { Access *access = access_open(); String8 search_query = str8_lit("rd_"); - DI2_SearchItemArray items = di2_search_item_array_from_target_query(access, RDI_SectionKind_Procedures, search_query, max_U64); + DI_SearchItemArray items = di_search_item_array_from_target_query(access, RDI_SectionKind_Procedures, search_query, max_U64); printf("\n"); printf("fuzzy searched for %.*s, found %I64u items\n", str8_varg(search_query), items.count); access_close(access); String8 match_query = str8_lit("rd_frame"); - DI2_Match match = di2_match_from_string(match_query, 0, max_U64); + DI_Match match = di_match_from_string(match_query, 0, max_U64); printf("searched for %.*s, found at %i in [%I64x:%I64x]\n", str8_varg(match_query), match.idx, match.key.u64[0], match.key.u64[1]); break; From 32c4da878ffdf331aae5484cedda215165b91f7a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 11:53:53 -0700 Subject: [PATCH 020/133] fix radbin build --- src/radbin/radbin_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/radbin/radbin_main.c b/src/radbin/radbin_main.c index f72180de..e1abc2fc 100644 --- a/src/radbin/radbin_main.c +++ b/src/radbin/radbin_main.c @@ -14,7 +14,6 @@ #include "base/base_inc.h" #include "linker/hash_table.h" #include "os/os_inc.h" -#include "async/async.h" #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" #include "coff/coff_inc.h" @@ -39,7 +38,6 @@ #include "base/base_inc.c" #include "linker/hash_table.c" #include "os/os_inc.c" -#include "async/async.c" #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" #include "coff/coff_inc.c" From 871daf3f228c2afc63b77568d17e37240ad11675 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 12:08:31 -0700 Subject: [PATCH 021/133] only push unique hashes to key history in content layer; fix staleness detection in search --- src/content/content.c | 16 ++++++++++++---- src/dbg_info/dbg_info.c | 4 ++-- src/dbg_info/dbg_info.h | 2 +- src/raddbg/raddbg_eval.c | 7 ++++--- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/content/content.c b/src/content/content.c index 1136f1af..86062fea 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -276,12 +276,20 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) // rjf: push hash into key's history if(key_node) { - if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) + U128 last_hash = {0}; + if(key_node->hash_history_gen >= 1) { - key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; + last_hash = key_node->hash_history[(key_node->hash_history_gen-1)%ArrayCount(key_node->hash_history)]; + } + if(!u128_match(last_hash, hash)) + { + if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) + { + key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; + } + key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; + key_node->hash_history_gen += 1; } - key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; - key_node->hash_history_gen += 1; } // rjf: key is new -> add this key to the associated root diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index e6a42707..9f5f9c39 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -1352,7 +1352,7 @@ di_search_artifact_destroy(AC_Artifact artifact) } internal DI_SearchItemArray -di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us) +di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us, B32 *stale_out) { DI_SearchItemArray result = {0}; { @@ -1366,7 +1366,7 @@ di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, S String8 key = str8_list_join(scratch.arena, &key_parts, 0); // rjf: get artifact - AC_Artifact artifact = ac_artifact_from_key(access, key, di_search_artifact_create, di_search_artifact_destroy, endt_us, .gen = di_load_gen(), .flags = AC_Flag_Wide); + AC_Artifact artifact = ac_artifact_from_key(access, key, di_search_artifact_create, di_search_artifact_destroy, endt_us, .gen = di_load_gen(), .flags = AC_Flag_Wide, .stale_out = stale_out); // rjf: unpack artifact result.v = (DI_SearchItem *)artifact.u64[1]; diff --git a/src/dbg_info/dbg_info.h b/src/dbg_info/dbg_info.h index 49ea1341..5af13b45 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -308,7 +308,7 @@ internal void di_conversion_completion_signal_receiver_thread_entry_point(void * internal AC_Artifact di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void di_search_artifact_destroy(AC_Artifact artifact); -internal DI_SearchItemArray di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us); +internal DI_SearchItemArray di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us, B32 *stale_out); //////////////////////////////// //~ rjf: Match Artifact Cache Hooks / Lookups diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index e2d8930e..4de6e60d 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1661,13 +1661,14 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) { U64 endt_us = rd_state->frame_eval_memread_endt_us; U128 fuzzy_search_key = {d_hash_from_string(str8_struct(&rd_regs()->view)), (U64)section}; + B32 stale = 0; accel->section = section; - accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us); + accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us, &stale); RD_ViewState *vs = rd_view_state_from_cfg(rd_cfg_from_id(rd_regs()->view)); - if(accel->items.count == 0) + if(stale) { String8 last_query = str8(vs->last_successful_query_buffer, vs->last_successful_query_string_size); - accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, last_query, endt_us); + accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, last_query, endt_us, 0); } else { From b88c45d7379a5eea2cd6a65abe1a22440fd2dea6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 12:44:42 -0700 Subject: [PATCH 022/133] dbg info conversion events --- src/dbg_info/dbg_info.c | 43 +++++++++++++++++++++++++++++++++++++++ src/dbg_info/dbg_info.h | 44 ++++++++++++++++++++++++++++++++++++++++ src/raddbg/raddbg_core.c | 4 +--- 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 9f5f9c39..a259646e 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -96,6 +96,8 @@ di_init(CmdLine *cmdline) di_shared->conversion_completion_shared_memory_base = (U64 *)os_shared_memory_view_open(di_shared->conversion_completion_shared_memory, r1u64(0, KB(4))); di_shared->completion_mutex = mutex_alloc(); di_shared->completion_arena = arena_alloc(); + di_shared->event_mutex = mutex_alloc(); + di_shared->event_arena = arena_alloc(); } //////////////////////////////// @@ -486,6 +488,29 @@ di_rdi_from_key(Access *access, DI_Key key, B32 high_priority, U64 endt_us) return rdi; } +//////////////////////////////// +//~ rjf: Events + +internal DI_EventList +di_get_events(Arena *arena) +{ + DI_EventList dst = {0}; + MutexScope(di_shared->event_mutex) + { + for EachNode(src_n, DI_EventNode, di_shared->events.first) + { + DI_EventNode *dst_n = push_array(arena, DI_EventNode, 1); + MemoryCopyStruct(&dst_n->v, &src_n->v); + dst_n->v.string = str8_copy(arena, dst_n->v.string); + SLLQueuePush(dst.first, dst.last, dst_n); + dst.count += 1; + } + MemoryZeroStruct(&di_shared->events); + arena_clear(di_shared->event_arena); + } + return dst; +} + //////////////////////////////// //~ rjf: Asynchronous Tick @@ -738,6 +763,16 @@ di_async_tick(void) t->status = DI_LoadTaskStatus_Active; di_shared->conversion_process_count += 1; di_shared->conversion_thread_count += t->thread_count; + + // rjf: send event + MutexScope(di_shared->event_mutex) + { + DI_EventNode *n = push_array(di_shared->event_arena, DI_EventNode, 1); + SLLQueuePush(di_shared->events.first, di_shared->events.last, n); + di_shared->events.count += 1; + n->v.kind = DI_EventKind_ConversionStarted; + n->v.string = str8_copy(di_shared->event_arena, rdi_path); + } } //- rjf: if active & process has completed, mark as done @@ -785,6 +820,14 @@ di_async_tick(void) //- rjf: if task is done, retire & recycle task; gather path to load if(t->status == DI_LoadTaskStatus_Done) { + if(!os_handle_match(t->process, os_handle_zero())) MutexScope(di_shared->event_mutex) + { + DI_EventNode *n = push_array(di_shared->event_arena, DI_EventNode, 1); + SLLQueuePush(di_shared->events.first, di_shared->events.last, n); + di_shared->events.count += 1; + n->v.kind = DI_EventKind_ConversionEnded; + n->v.string = str8_copy(di_shared->event_arena, rdi_path); + } DLLRemove(di_shared->first_load_task, di_shared->last_load_task, t); SLLStackPush(di_shared->free_load_task, t); ParseTaskNode *n = push_array(scratch.arena, ParseTaskNode, 1); diff --git a/src/dbg_info/dbg_info.h b/src/dbg_info/dbg_info.h index 5af13b45..5e2dbbb3 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -204,6 +204,40 @@ struct DI_Match U32 idx; }; +//////////////////////////////// +//~ rjf: Events + +typedef enum DI_EventKind +{ + DI_EventKind_Null, + DI_EventKind_ConversionStarted, + DI_EventKind_ConversionEnded, + DI_EventKind_COUNT +} +DI_EventKind; + +typedef struct DI_Event DI_Event; +struct DI_Event +{ + DI_EventKind kind; + String8 string; +}; + +typedef struct DI_EventNode DI_EventNode; +struct DI_EventNode +{ + DI_EventNode *next; + DI_Event v; +}; + +typedef struct DI_EventList DI_EventList; +struct DI_EventList +{ + DI_EventNode *first; + DI_EventNode *last; + U64 count; +}; + //////////////////////////////// //~ rjf: Shared State @@ -254,6 +288,11 @@ struct DI_Shared Arena *completion_arena; DI_LoadCompletion *first_completion; DI_LoadCompletion *last_completion; + + // rjf: events + Mutex event_mutex; + Arena *event_arena; + DI_EventList events; }; //////////////////////////////// @@ -292,6 +331,11 @@ internal U64 di_load_gen(void); internal DI_KeyArray di_push_all_loaded_keys(Arena *arena); internal RDI_Parsed *di_rdi_from_key(Access *access, DI_Key key, B32 high_priority, U64 endt_us); +//////////////////////////////// +//~ rjf: Events + +internal DI_EventList di_get_events(Arena *arena); + //////////////////////////////// //~ rjf: Asynchronous Tick diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 05683584..57911805 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -11399,10 +11399,9 @@ rd_frame(void) ////////////////////////////// //- rjf: sync with di parsers // -#if 0 // TODO(rjf): @dbgi2 ProfScope("sync with di parsers") { - DI_EventList events = di_p2u_pop_events(scratch.arena, 0); + DI_EventList events = di_get_events(scratch.arena); for(DI_EventNode *n = events.first; n != 0; n = n->next) { DI_Event *event = &n->v; @@ -11430,7 +11429,6 @@ rd_frame(void) } } } -#endif ////////////////////////////// //- rjf: animate all views From 56b57925467a12f89fb9206ebec9b628c7170ddf Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 13:40:45 -0700 Subject: [PATCH 023/133] rdi checksum kinds, rdim checksums, pull parsed checksum kinds/values from cv, fill out rdim checksums (still haven't put into rdi itself yet) --- src/codeview/codeview_parse.c | 36 ++++++++++----- src/codeview/codeview_parse.h | 16 ++++--- src/lib_rdi/rdi.h | 17 +++++++ src/lib_rdi_make/rdi_make.h | 2 + src/rdi/rdi.mdesk | 23 ++++++++++ src/rdi_from_pdb/rdi_from_pdb.c | 80 +++++++++++++++++++++++++-------- src/rdi_from_pdb/rdi_from_pdb.h | 33 +++++++++++--- 7 files changed, 166 insertions(+), 41 deletions(-) diff --git a/src/codeview/codeview_parse.c b/src/codeview/codeview_parse.c index e7f3da9c..bab4371f 100644 --- a/src/codeview/codeview_parse.c +++ b/src/codeview/codeview_parse.c @@ -1460,14 +1460,18 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec U32 line_count_unclamped = file->num_lines; U32 block_size = file->block_size; - // file_name from file_off + // file_name / checksum from file_off String8 file_name = {0}; + CV_C13ChecksumKind checksum_kind = CV_C13ChecksumKind_Null; + String8 checksum_value = {0}; if(file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off); U32 name_off = checksum->name_off; - file_name = str8_cstring_capped((char*)(strtbl.str + name_off), - (char*)(strtbl.str + strtbl.size)); + file_name = str8_cstring_capped((char*)(strtbl.str + name_off), (char*)(strtbl.str + strtbl.size)); + checksum_kind = checksum->kind; + checksum_value = str8_skip(c13_data, file_chksms->off + file_off + sizeof(*checksum)); + checksum_value.size = Min(checksum->len, checksum_value.size); } // array layouts @@ -1503,13 +1507,15 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec // emit parsed lines CV_C13LinesParsedNode *lines_parsed_node = push_array(arena, CV_C13LinesParsedNode, 1); CV_C13LinesParsed *lines_parsed = &lines_parsed_node->v; - lines_parsed->sec_idx = sec_idx; - lines_parsed->file_off = file_off; + lines_parsed->sec_idx = sec_idx; + lines_parsed->file_off = file_off; lines_parsed->secrel_base_off = secrel_off; - lines_parsed->file_name = file_name; - lines_parsed->voffs = voffs; - lines_parsed->line_nums = line_nums; - lines_parsed->line_count = line_count; + lines_parsed->file_name = file_name; + lines_parsed->checksum_kind = checksum_kind; + lines_parsed->checksum = checksum_value; + lines_parsed->voffs = voffs; + lines_parsed->line_nums = line_nums; + lines_parsed->line_count = line_count; SLLQueuePush(node->lines_first, node->lines_last, lines_parsed_node); // rjf: advance @@ -1539,12 +1545,16 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec // rjf: file_off -> file_name String8 file_name = {0}; + CV_C13ChecksumKind checksum_kind = CV_C13ChecksumKind_Null; + String8 checksum_value = {0}; if(hdr->file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off); U32 name_off = checksum->name_off; - file_name = str8_cstring_capped((char*)(strtbl.str + name_off), - (char*)(strtbl.str + strtbl.size)); + file_name = str8_cstring_capped((char*)(strtbl.str + name_off), (char*)(strtbl.str + strtbl.size)); + checksum_kind = checksum->kind; + checksum_value = str8_skip(c13_data, file_chksms->off + hdr->file_off + sizeof(*checksum)); + checksum_value.size = Min(checksum->len, checksum_value.size); } // rjf: parse extra files @@ -1564,8 +1574,10 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec CV_C13InlineeLinesParsedNode *n = push_array(arena, CV_C13InlineeLinesParsedNode, 1); SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n); n->v.inlinee = hdr->inlinee; - n->v.file_name = file_name; n->v.file_off = hdr->file_off; + n->v.file_name = file_name; + n->v.checksum_kind = checksum_kind; + n->v.checksum = checksum_value; n->v.first_source_ln = hdr->first_source_ln; n->v.extra_file_count = extra_file_count; n->v.extra_files = extra_files; diff --git a/src/codeview/codeview_parse.h b/src/codeview/codeview_parse.h index d77e2913..111d1288 100644 --- a/src/codeview/codeview_parse.h +++ b/src/codeview/codeview_parse.h @@ -150,6 +150,8 @@ struct CV_C13LinesParsed // parsed info String8 file_name; + CV_C13ChecksumKind checksum_kind; + String8 checksum; U64 *voffs; // [line_count + 1] U32 *line_nums; // [line_count] U16 *col_nums; // [2*line_count] @@ -166,12 +168,14 @@ struct CV_C13LinesParsedNode typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed; struct CV_C13InlineeLinesParsed { - CV_ItemId inlinee; - U32 file_off; - String8 file_name; - U32 first_source_ln; - U32 extra_file_count; - U32 *extra_files; + CV_ItemId inlinee; + U32 file_off; + String8 file_name; + CV_C13ChecksumKind checksum_kind; + String8 checksum; + U32 first_source_ln; + U32 extra_file_count; + U32 *extra_files; }; typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode; diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index 20394e53..ef581cb2 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -305,6 +305,16 @@ RDI_BinarySectionFlag_Write = 1<<1, RDI_BinarySectionFlag_Execute = 1<<2, } RDI_BinarySectionFlagsEnum; +typedef RDI_U16 RDI_ChecksumKind; +typedef enum RDI_ChecksumKindEnum +{ +RDI_ChecksumKind_Null = 0, +RDI_ChecksumKind_MD5 = 1, +RDI_ChecksumKind_SHA1 = 2, +RDI_ChecksumKind_SHA256 = 3, +RDI_ChecksumKind_Timestamp = 4, +} RDI_ChecksumKindEnum; + typedef RDI_U32 RDI_Language; typedef enum RDI_LanguageEnum { @@ -790,6 +800,13 @@ X(RDI_U64, voff_opl)\ X(RDI_U64, foff_first)\ X(RDI_U64, foff_opl)\ +#define RDI_ChecksumKind_XList \ +X(Null)\ +X(MD5)\ +X(SHA1)\ +X(SHA256)\ +X(Timestamp)\ + #define RDI_FilePathNode_XList \ X(RDI_U32, name_string_idx)\ X(RDI_U32, parent_path_node)\ diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 5e872a64..934a3a76 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -540,6 +540,8 @@ struct RDIM_SrcFile RDIM_SrcFileLineMapFragment *first_line_map_fragment; RDIM_SrcFileLineMapFragment *last_line_map_fragment; RDI_U64 total_line_count; + RDI_ChecksumKind checksum_kind; + RDIM_String8 checksum; }; typedef struct RDIM_SrcFileChunkNode RDIM_SrcFileChunkNode; diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 8abb24e8..7f570eee 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -534,6 +534,29 @@ RDI_BinarySectionMemberTable: @expand(RDI_BinarySectionMemberTable a) `$(a.type) $(a.name)` } +//////////////////////////////// +//~ rjf: Checksum Type Tables + +@table(name value) +RDI_ChecksumKindTable: +{ + {Null 0} + {MD5 1} + {SHA1 2} + {SHA256 3} + {Timestamp 4} +} + +@enum(RDI_U16) RDI_ChecksumKind: +{ + @expand(RDI_ChecksumKindTable a) `$(a.name .. =>10) = $(a.value)` +} + +@xlist RDI_ChecksumKind_XList: +{ + @expand(RDI_ChecksumKindTable a) `$(a.name)`; +} + //////////////////////////////// //~ rjf: File Path Tree Info Type Tables diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 37b84abf..ca15f48a 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -264,6 +264,20 @@ p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type) return result; } +internal RDI_ChecksumKind +p2r_rdi_from_cv_c13_checksum_kind(CV_C13ChecksumKind k) +{ + RDI_ChecksumKind result = RDI_ChecksumKind_Null; + switch((CV_C13ChecksumKindEnum)k) + { + case CV_C13ChecksumKind_Null: {result = RDI_ChecksumKind_Null;}break; + case CV_C13ChecksumKind_MD5: {result = RDI_ChecksumKind_MD5;}break; + case CV_C13ChecksumKind_SHA1: {result = RDI_ChecksumKind_SHA1;}break; + case CV_C13ChecksumKind_SHA256:{result = RDI_ChecksumKind_SHA256;}break; + } + return result; +} + //////////////////////////////// //~ rjf: Location Info Building Helpers @@ -774,7 +788,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: prep outputs ProfScope("prep outputs") if(lane_idx() == 0) { - p2r_shared->unit_file_paths = push_array(arena, String8Array, comp_units->count); + p2r_shared->unit_file_stubs = push_array(arena, P2R_SrcFileStubArray, comp_units->count); p2r_shared->unit_file_paths_hashes = push_array(arena, U64Array, comp_units->count); p2r_shared->sym_lane_take_counter = 0; } @@ -819,8 +833,10 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - //- rjf: find all inline site symbols & gather filenames - String8List src_file_paths = {0}; + //- rjf: find all inline site symbols & gather file stubs + P2R_SrcFileStubNode *first_src_file_stub = 0; + P2R_SrcFileStubNode *last_src_file_stub = 0; + U64 src_file_stub_count = 0; U64 base_voff = 0; for(CV_RecRange *rec_range = rec_ranges_first; rec_range < rec_ranges_opl; @@ -917,11 +933,16 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) if(last_file_off != max_U32 && last_file_off != curr_file_off) { String8 seq_file_name = {0}; + CV_C13ChecksumKind checksum_kind = CV_C13ChecksumKind_Null; + String8 checksum_value = {0}; if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { CV_C13Checksum *checksum = (CV_C13Checksum *)(c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; + U32 name_off = checksum->name_off; seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); + checksum_kind = checksum->kind; + checksum_value = str8_skip(c13->data, file_chksms->off + last_file_off + sizeof(*checksum)); + checksum_value.size = Min(checksum->len, checksum_value.size); } // rjf: file name -> normalized file path @@ -958,7 +979,12 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) hit_path_node = push_array(scratch.arena, String8Node, 1); SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); hit_path_node->string = file_path_normalized; - str8_list_push(arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); + P2R_SrcFileStubNode *stub_n = push_array(arena, P2R_SrcFileStubNode, 1); + SLLQueuePush(first_src_file_stub, last_src_file_stub, stub_n); + src_file_stub_count += 1; + stub_n->v.file_path = str8_copy(arena, file_path_normalized); + stub_n->v.checksum_kind = checksum_kind; + stub_n->v.checksum = str8_copy(arena, checksum_value); } line_count = 0; } @@ -1026,22 +1052,36 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) hit_path_node = push_array(scratch.arena, String8Node, 1); SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); hit_path_node->string = file_path_sanitized; - str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_sanitized)); + P2R_SrcFileStubNode *stub_n = push_array(arena, P2R_SrcFileStubNode, 1); + SLLQueuePush(first_src_file_stub, last_src_file_stub, stub_n); + src_file_stub_count += 1; + stub_n->v.file_path = str8_copy(arena, file_path_sanitized); + stub_n->v.checksum_kind = lines_n->v.checksum_kind; + stub_n->v.checksum = str8_copy(arena, lines_n->v.checksum); } } } } //- rjf: merge into array for this unit - p2r_shared->unit_file_paths[unit_idx] = str8_array_from_list(arena, &src_file_paths); + p2r_shared->unit_file_stubs[unit_idx].count = src_file_stub_count; + p2r_shared->unit_file_stubs[unit_idx].v = push_array_no_zero(arena, P2R_SrcFileStub, p2r_shared->unit_file_stubs[unit_idx].count); + { + U64 idx = 0; + for EachNode(n, P2R_SrcFileStubNode, first_src_file_stub) + { + p2r_shared->unit_file_stubs[unit_idx].v[idx] = n->v; + idx += 1; + } + } //- rjf: hash this unit's file paths U64Array hashes = {0}; - hashes.count = p2r_shared->unit_file_paths[unit_idx].count; + hashes.count = p2r_shared->unit_file_stubs[unit_idx].count; hashes.v = push_array(arena, U64, hashes.count); - for EachIndex(idx, p2r_shared->unit_file_paths[unit_idx].count) + for EachIndex(idx, p2r_shared->unit_file_stubs[unit_idx].count) { - hashes.v[idx] = rdi_hash(p2r_shared->unit_file_paths[unit_idx].v[idx].str, p2r_shared->unit_file_paths[unit_idx].v[idx].size); + hashes.v[idx] = rdi_hash(p2r_shared->unit_file_stubs[unit_idx].v[idx].file_path.str, p2r_shared->unit_file_stubs[unit_idx].v[idx].file_path.size); } p2r_shared->unit_file_paths_hashes[unit_idx] = hashes; } @@ -1049,7 +1089,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } lane_sync(); - String8Array *unit_file_paths = p2r_shared->unit_file_paths; + P2R_SrcFileStubArray *unit_file_stubs = p2r_shared->unit_file_stubs; U64Array *unit_file_paths_hashes = p2r_shared->unit_file_paths_hashes; ////////////////////////////////////////////////////////////// @@ -1065,7 +1105,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) p2r_shared->total_path_count = 0; for EachIndex(idx, comp_units->count) { - p2r_shared->total_path_count += unit_file_paths[idx].count; + p2r_shared->total_path_count += unit_file_stubs[idx].count; } p2r_shared->src_file_map.slots_count = p2r_shared->total_path_count + p2r_shared->total_path_count/2 + 1; p2r_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r_shared->src_file_map.slots_count); @@ -1077,12 +1117,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { for EachIndex(idx, comp_units->count) { - String8Array paths = unit_file_paths[idx]; + P2R_SrcFileStubArray stubs = unit_file_stubs[idx]; U64Array hashes = unit_file_paths_hashes[idx]; - for EachIndex(path_idx, paths.count) + for EachIndex(stub_idx, stubs.count) { - String8 file_path_sanitized = paths.v[path_idx]; - U64 file_path_sanitized_hash = hashes.v[path_idx]; + String8 file_path_sanitized = stubs.v[stub_idx].file_path; + CV_C13ChecksumKind c13_checksum_kind = stubs.v[stub_idx].checksum_kind; + String8 checksum = stubs.v[stub_idx].checksum; + U64 file_path_sanitized_hash = hashes.v[stub_idx]; U64 src_file_slot = file_path_sanitized_hash%p2r_shared->src_file_map.slots_count; P2R_SrcFileNode *src_file_node = 0; for(P2R_SrcFileNode *n = p2r_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) @@ -1098,7 +1140,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) src_file_node = push_array(arena, P2R_SrcFileNode, 1); SLLStackPush(p2r_shared->src_file_map.slots[src_file_slot], src_file_node); src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r_shared->all_src_files__sequenceless, p2r_shared->total_path_count); - src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); + src_file_node->src_file->path = str8_copy(arena, file_path_sanitized); + src_file_node->src_file->checksum_kind = p2r_rdi_from_cv_c13_checksum_kind(c13_checksum_kind); + src_file_node->src_file->checksum = str8_copy(arena, checksum); } } } @@ -1369,7 +1413,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; + U32 name_off = checksum->name_off; seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); } diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index bb16e8ee..64939815 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -42,6 +42,28 @@ struct P2R_LinkNameMap //- rjf: normalized file path -> source file map +typedef struct P2R_SrcFileStub P2R_SrcFileStub; +struct P2R_SrcFileStub +{ + String8 file_path; + CV_C13ChecksumKind checksum_kind; + String8 checksum; +}; + +typedef struct P2R_SrcFileStubArray P2R_SrcFileStubArray; +struct P2R_SrcFileStubArray +{ + P2R_SrcFileStub *v; + U64 count; +}; + +typedef struct P2R_SrcFileStubNode P2R_SrcFileStubNode; +struct P2R_SrcFileStubNode +{ + P2R_SrcFileStubNode *next; + P2R_SrcFileStub v; +}; + typedef struct P2R_SrcFileNode P2R_SrcFileNode; struct P2R_SrcFileNode { @@ -109,7 +131,7 @@ struct P2R_Shared U64 sym_lane_take_counter; - String8Array *unit_file_paths; + P2R_SrcFileStubArray *unit_file_stubs; U64Array *unit_file_paths_hashes; U64 total_path_count; @@ -175,10 +197,11 @@ internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_f //////////////////////////////// //~ rjf: CodeView => RDI Canonical Conversions -internal RDI_Arch p2r_rdi_arch_from_cv_arch(CV_Arch arch); -internal RDI_RegCode p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code); -internal RDI_Language p2r_rdi_language_from_cv_language(CV_Language language); -internal RDI_TypeKind p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type); +internal RDI_Arch p2r_rdi_arch_from_cv_arch(CV_Arch arch); +internal RDI_RegCode p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code); +internal RDI_Language p2r_rdi_language_from_cv_language(CV_Language language); +internal RDI_TypeKind p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type); +internal RDI_ChecksumKind p2r_rdi_from_cv_c13_checksum_kind(CV_C13ChecksumKind k); //////////////////////////////// //~ rjf: Location Info Building Helpers From 403d05cc8b8358fad1126bf607453e746ce080ec Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 14:17:21 -0700 Subject: [PATCH 024/133] first pass at checksum baking --- src/lib_rdi/rdi.c | 4 +- src/lib_rdi/rdi.h | 20 +++++-- src/lib_rdi_make/rdi_make.c | 11 ++-- src/lib_rdi_make/rdi_make.h | 14 ++++- src/rdi/rdi.mdesk | 12 ++-- src/rdi_make/rdi_make_local.c | 106 +++++++++++++++++++++++++++++++++- src/rdi_make/rdi_make_local.h | 9 +++ 7 files changed, 153 insertions(+), 23 deletions(-) diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index 7f2e6515..69e1b10a 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -10,7 +10,7 @@ #ifndef RDI_C #define RDI_C -RDI_U16 rdi_section_element_size_table[40] = +RDI_U16 rdi_section_element_size_table[42] = { sizeof(RDI_U8), sizeof(RDI_TopLevelInfo), @@ -48,6 +48,8 @@ sizeof(RDI_LocationBlock), sizeof(RDI_U8), sizeof(RDI_U8), sizeof(RDI_U32), +sizeof(RDI_U8), +sizeof(RDI_U32), sizeof(RDI_NameMap), sizeof(RDI_NameMapBucket), sizeof(RDI_NameMapNode), diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index ef581cb2..37a77e9d 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -52,7 +52,7 @@ typedef int64_t RDI_S64; // "raddbg\0\0" #define RDI_MAGIC_CONSTANT 0x0000676264646172 -#define RDI_ENCODING_VERSION 13 +#define RDI_ENCODING_VERSION 14 //////////////////////////////////////////////////////////////// //~ Format Types & Functions @@ -96,10 +96,12 @@ RDI_SectionKind_LocationBlocks = 0x0020, RDI_SectionKind_LocationData = 0x0021, RDI_SectionKind_ConstantValueData = 0x0022, RDI_SectionKind_ConstantValueTable = 0x0023, -RDI_SectionKind_NameMaps = 0x0024, -RDI_SectionKind_NameMapBuckets = 0x0025, -RDI_SectionKind_NameMapNodes = 0x0026, -RDI_SectionKind_COUNT = 0x0027, +RDI_SectionKind_ChecksumData = 0x0024, +RDI_SectionKind_ChecksumTable = 0x0025, +RDI_SectionKind_NameMaps = 0x0026, +RDI_SectionKind_NameMapBuckets = 0x0027, +RDI_SectionKind_NameMapNodes = 0x0028, +RDI_SectionKind_COUNT = 0x0029, } RDI_SectionKindEnum; typedef RDI_U32 RDI_SectionEncoding; @@ -588,6 +590,8 @@ X(LocationBlocks, location_blocks, RDI_LocationBlock)\ X(LocationData, location_data, RDI_U8)\ X(ConstantValueData, constant_value_data, RDI_U8)\ X(ConstantValueTable, constant_value_table, RDI_U32)\ +X(ChecksumData, checksum_data, RDI_U8)\ +X(ChecksumTable, checksum_table, RDI_U32)\ X(NameMaps, name_maps, RDI_NameMap)\ X(NameMapBuckets, name_map_buckets, RDI_NameMapBucket)\ X(NameMapNodes, name_map_nodes, RDI_NameMapNode)\ @@ -1169,6 +1173,7 @@ typedef struct RDI_U32_LocationBlocks { RDI_U32 v; } RDI_U32_Locati typedef struct RDI_U32_LocationData { RDI_U32 v; } RDI_U32_LocationData; typedef struct RDI_U32_ConstantValueData { RDI_U32 v; } RDI_U32_ConstantValueData; typedef struct RDI_U32_ConstantValueTable { RDI_U32 v; } RDI_U32_ConstantValueTable; +typedef struct RDI_U32_ChecksumTable { RDI_U32 v; } RDI_U32_ChecksumTable; typedef struct RDI_U32_NameMaps { RDI_U32 v; } RDI_U32_NameMaps; typedef struct RDI_U32_NameMapBuckets { RDI_U32 v; } RDI_U32_NameMapBuckets; typedef struct RDI_U32_NameMapNodes { RDI_U32 v; } RDI_U32_NameMapNodes; @@ -1205,6 +1210,7 @@ typedef RDI_U32_Table RDI_U32_LocationBlocks; typedef RDI_U32_Table RDI_U32_LocationData; typedef RDI_U32_Table RDI_U32_ConstantValueData; typedef RDI_U32_Table RDI_U32_ConstantValueTable; +typedef RDI_U32_Table RDI_U32_ChecksumTable; typedef RDI_U32_Table RDI_U32_NameMaps; typedef RDI_U32_Table RDI_U32_NameMapBuckets; typedef RDI_U32_Table RDI_U32_NameMapNodes; @@ -1572,6 +1578,8 @@ typedef RDI_LocationBlock RDI_SectionElementType_LocationBlocks; typedef RDI_U8 RDI_SectionElementType_LocationData; typedef RDI_U8 RDI_SectionElementType_ConstantValueData; typedef RDI_U32 RDI_SectionElementType_ConstantValueTable; +typedef RDI_U8 RDI_SectionElementType_ChecksumData; +typedef RDI_U32 RDI_SectionElementType_ChecksumTable; typedef RDI_NameMap RDI_SectionElementType_NameMaps; typedef RDI_NameMapBucket RDI_SectionElementType_NameMapBuckets; typedef RDI_NameMapNode RDI_SectionElementType_NameMapNodes; @@ -1584,7 +1592,7 @@ RDI_PROC RDI_EvalConversionKind rdi_eval_conversion_kind_from_typegroups(RDI_Eva RDI_PROC RDI_S32 rdi_eval_op_typegroup_are_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group); RDI_PROC RDI_U8 *rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RDI_U64 *size_out); -extern RDI_U16 rdi_section_element_size_table[40]; +extern RDI_U16 rdi_section_element_size_table[42]; extern RDI_U16 rdi_eval_op_ctrlbits_table[52]; #endif // RDI_H diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 2b4ceacd..bfec01cb 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -2022,15 +2022,12 @@ rdim_serialized_section_bundle_from_bake_results(RDIM_BakeResults *results) bundle.sections[RDI_SectionKind_ScopeVMap] = rdim_serialized_section_make_unpacked_array(results->scope_vmap.vmap.vmap, results->scope_vmap.vmap.count); bundle.sections[RDI_SectionKind_InlineSites] = rdim_serialized_section_make_unpacked_array(results->inline_sites.inline_sites, results->inline_sites.inline_sites_count); bundle.sections[RDI_SectionKind_Locals] = rdim_serialized_section_make_unpacked_array(results->scopes.locals, results->scopes.locals_count); - bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks.str, results->location_blocks.size); - bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->location_data.str, results->location_data.size); - if(results->location_blocks.size == 0) - { - bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks2.location_blocks, results->location_blocks2.location_blocks_count); - bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->locations.location_data, results->locations.location_data_size); - } + bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks.location_blocks, results->location_blocks.location_blocks_count); + bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->locations.location_data, results->locations.location_data_size); bundle.sections[RDI_SectionKind_ConstantValueData] = rdim_serialized_section_make_unpacked_array(results->constants.constant_value_data, results->constants.constant_value_data_size); bundle.sections[RDI_SectionKind_ConstantValueTable] = rdim_serialized_section_make_unpacked_array(results->constants.constant_values, results->constants.constant_values_count); + bundle.sections[RDI_SectionKind_ChecksumData] = rdim_serialized_section_make_unpacked_array(results->checksums.data, results->checksums.data_size); + bundle.sections[RDI_SectionKind_ChecksumTable] = rdim_serialized_section_make_unpacked_array(results->checksums.offs, results->checksums.offs_count); bundle.sections[RDI_SectionKind_NameMaps] = rdim_serialized_section_make_unpacked_array(results->top_level_name_maps.name_maps, results->top_level_name_maps.name_maps_count); bundle.sections[RDI_SectionKind_NameMapBuckets] = rdim_serialized_section_make_unpacked_array(results->name_maps.buckets, results->name_maps.buckets_count); bundle.sections[RDI_SectionKind_NameMapNodes] = rdim_serialized_section_make_unpacked_array(results->name_maps.nodes, results->name_maps.nodes_count); diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 934a3a76..9f6eb541 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1312,6 +1312,15 @@ struct RDIM_SrcFileBakeResult RDI_U64 source_line_map_voffs_count; }; +typedef struct RDIM_ChecksumBakeResult RDIM_ChecksumBakeResult; +struct RDIM_ChecksumBakeResult +{ + RDI_U32 *offs; + RDI_U64 offs_count; + RDI_U8 *data; + RDI_U64 data_size; +}; + typedef struct RDIM_LineTableBakeResult RDIM_LineTableBakeResult; struct RDIM_LineTableBakeResult { @@ -1466,6 +1475,7 @@ struct RDIM_BakeResults RDIM_UnitBakeResult units; RDIM_UnitVMapBakeResult unit_vmap; RDIM_SrcFileBakeResult src_files; + RDIM_ChecksumBakeResult checksums; RDIM_LineTableBakeResult line_tables; RDIM_TypeNodeBakeResult type_nodes; RDIM_UDTBakeResult udts; @@ -1483,9 +1493,7 @@ struct RDIM_BakeResults RDIM_StringBakeResult strings; RDIM_IndexRunBakeResult idx_runs; RDIM_LocationBakeResult locations; - RDIM_LocationBlockBakeResult location_blocks2; - RDIM_String8 location_blocks; - RDIM_String8 location_data; + RDIM_LocationBlockBakeResult location_blocks; }; //////////////////////////////// diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 7f570eee..7e8a8bc5 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -62,7 +62,7 @@ ""; "// \"raddbg\\0\\0\""; "#define RDI_MAGIC_CONSTANT 0x0000676264646172"; - "#define RDI_ENCODING_VERSION 13"; + "#define RDI_ENCODING_VERSION 14"; ""; "////////////////////////////////////////////////////////////////"; "//~ Format Types & Functions"; @@ -156,10 +156,12 @@ RDI_SectionTable: {LocationData location_data RDI_U8 0x0021 U32 ""} {ConstantValueData constant_value_data RDI_U8 0x0022 U32 ""} {ConstantValueTable constant_value_table RDI_U32 0x0023 U32 ""} - {NameMaps name_maps RDI_NameMap 0x0024 U32 ""} - {NameMapBuckets name_map_buckets RDI_NameMapBucket 0x0025 U32 ""} - {NameMapNodes name_map_nodes RDI_NameMapNode 0x0026 U32 ""} - {COUNT count RDI_U8 0x0027 - ""} + {ChecksumData checksum_data RDI_U8 0x0024 - ""} + {ChecksumTable checksum_table RDI_U32 0x0025 U32 ""} + {NameMaps name_maps RDI_NameMap 0x0026 U32 ""} + {NameMapBuckets name_map_buckets RDI_NameMapBucket 0x0027 U32 ""} + {NameMapNodes name_map_nodes RDI_NameMapNode 0x0028 U32 ""} + {COUNT count RDI_U8 0x0029 - ""} } @table(name value) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index e886f697..e6481551 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -1920,6 +1920,109 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } } + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute lane checksum layouts + // + ProfScope("compute lane checksum layouts") + { + // rjf: allocate + if(lane_idx() == 0) + { + rdim_shared->lane_chunk_src_file_checksum_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_checksum_sizes = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_checksum_off_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_checksum_data_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + } + lane_sync(); + + // rjf: compute counts / sizes of all checksum data + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; + for EachInRange(n_idx, range) + { + if(n->v[n_idx].checksum_kind != RDI_ChecksumKind_Null && n->v[n_idx].checksum.size != 0) + { + rdim_shared->lane_chunk_src_file_checksum_counts[slot_idx] += 1; + rdim_shared->lane_chunk_src_file_checksum_sizes[slot_idx] += n->v[n_idx].checksum.size; + } + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: lay out per-lane-chunk offsets + if(lane_idx() == 0) + { + U64 off_off = 0; + U64 data_off = 0; + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; + rdim_shared->lane_chunk_src_file_checksum_off_offs[slot_idx] = off_off; + rdim_shared->lane_chunk_src_file_checksum_data_offs[slot_idx] = data_off; + off_off += rdim_shared->lane_chunk_src_file_checksum_counts[slot_idx]; + data_off += rdim_shared->lane_chunk_src_file_checksum_sizes[slot_idx]; + } + chunk_idx += 1; + } + rdim_shared->total_checksum_count = off_off; + rdim_shared->total_checksum_size = data_off; + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake checksums + // + ProfScope("bake checksums") + { + // rjf: allocate + if(lane_idx() == 0) + { + rdim_shared->baked_checksums.offs_count = rdim_shared->total_checksum_count+1; + rdim_shared->baked_checksums.offs = push_array(arena, U32, rdim_shared->baked_checksums.offs_count); + rdim_shared->baked_checksums.data_size = rdim_shared->total_checksum_size; + rdim_shared->baked_checksums.data = push_array(arena, U8, rdim_shared->baked_checksums.data_size); + } + lane_sync(); + + // rjf: fill + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; + U64 dst_off_off = rdim_shared->lane_chunk_src_file_checksum_off_offs[slot_idx]; + U64 dst_data_off = rdim_shared->lane_chunk_src_file_checksum_data_offs[slot_idx]; + for EachInRange(n_idx, range) + { + if(n->v[n_idx].checksum_kind != RDI_ChecksumKind_Null && n->v[n_idx].checksum.size != 0) + { + rdim_shared->baked_checksums.offs[dst_off_off] = (U32)dst_data_off; + MemoryCopy(&rdim_shared->baked_checksums.data[dst_data_off], n->v[n_idx].checksum.str, n->v[n_idx].checksum.size); + dst_off_off += 1; + dst_data_off += n->v[n_idx].checksum.size; + } + } + chunk_idx += 1; + } + if(lane_idx() == 0) + { + rdim_shared->baked_checksums.offs[rdim_shared->baked_checksums.offs_count-1] = rdim_shared->baked_checksums.data_size; + } + } + } + lane_sync(); + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute lane UDT member/enum-val layouts // @@ -2849,6 +2952,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) result.units = rdim_shared->baked_units; result.unit_vmap = rdim_shared->baked_unit_vmap; result.src_files = rdim_shared->baked_src_files; + result.checksums = rdim_shared->baked_checksums; result.line_tables = rdim_shared->baked_line_tables; result.type_nodes = rdim_shared->baked_type_nodes; result.udts = rdim_shared->baked_udts; @@ -2866,7 +2970,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) result.strings = rdim_shared->baked_strings; result.idx_runs = rdim_shared->baked_idx_runs; result.locations = rdim_shared->baked_locations; - result.location_blocks2 = rdim_shared->baked_location_blocks; + result.location_blocks = rdim_shared->baked_location_blocks; } return result; diff --git a/src/rdi_make/rdi_make_local.h b/src/rdi_make/rdi_make_local.h index 9dfea4e2..e6ad029c 100644 --- a/src/rdi_make/rdi_make_local.h +++ b/src/rdi_make/rdi_make_local.h @@ -136,6 +136,15 @@ struct RDIM_Shared RDIM_SrcFileBakeResult baked_src_files; + RDI_U64 *lane_chunk_src_file_checksum_counts; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_checksum_sizes; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_checksum_off_offs; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_checksum_data_offs; // [lane_count * src_file_chunk_count] + U64 total_checksum_count; + U64 total_checksum_size; + + RDIM_ChecksumBakeResult baked_checksums; + RDI_U64 *member_chunk_lane_counts; // [lane_count * udt_chunk_count] RDI_U64 *member_chunk_lane_offs; // [lane_count * udt_chunk_count] RDI_U64 *enum_val_chunk_lane_counts; // [lane_count * udt_chunk_count] From c1e32b93a7a75d68e33cbcb405e9a57952f25c39 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 15:43:01 -0700 Subject: [PATCH 025/133] switch from variable size checksum data sections to just making well-defined fixed size ones for all of the concrete cases --- src/lib_rdi/rdi.c | 8 ++-- src/lib_rdi/rdi.h | 66 +++++++++++++++++-------- src/lib_rdi_make/rdi_make.c | 5 +- src/lib_rdi_make/rdi_make.h | 12 +++-- src/rdi/rdi.mdesk | 43 +++++++++++------ src/rdi_from_pdb/rdi_from_pdb.c | 4 +- src/rdi_make/rdi_make_local.c | 85 +++++++++++++++++++-------------- src/rdi_make/rdi_make_local.h | 9 ++-- 8 files changed, 145 insertions(+), 87 deletions(-) diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index 69e1b10a..444f43d4 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -10,7 +10,7 @@ #ifndef RDI_C #define RDI_C -RDI_U16 rdi_section_element_size_table[42] = +RDI_U16 rdi_section_element_size_table[44] = { sizeof(RDI_U8), sizeof(RDI_TopLevelInfo), @@ -48,8 +48,10 @@ sizeof(RDI_LocationBlock), sizeof(RDI_U8), sizeof(RDI_U8), sizeof(RDI_U32), -sizeof(RDI_U8), -sizeof(RDI_U32), +sizeof(RDI_MD5), +sizeof(RDI_SHA1), +sizeof(RDI_SHA256), +sizeof(RDI_U64), sizeof(RDI_NameMap), sizeof(RDI_NameMapBucket), sizeof(RDI_NameMapNode), diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index 37a77e9d..d782fb31 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -40,6 +40,18 @@ typedef int32_t RDI_S32; typedef int64_t RDI_S64; #endif +//////////////////////////////////////////////////////////////// +//~ Checksum Types + +typedef union RDI_MD5 RDI_MD5; +union RDI_MD5 {RDI_U8 u8[16]; RDI_U64 u64[2];}; + +typedef union RDI_SHA1 RDI_SHA1; +union RDI_SHA1 {RDI_U8 u8[20];}; + +typedef union RDI_SHA256 RDI_SHA256; +union RDI_SHA256 {RDI_U8 u8[32]; RDI_U64 u64[4];}; + //////////////////////////////////////////////////////////////// //~ Overridable Enabling/Disabling Of Table Index Typechecking @@ -52,7 +64,7 @@ typedef int64_t RDI_S64; // "raddbg\0\0" #define RDI_MAGIC_CONSTANT 0x0000676264646172 -#define RDI_ENCODING_VERSION 14 +#define RDI_ENCODING_VERSION 15 //////////////////////////////////////////////////////////////// //~ Format Types & Functions @@ -96,12 +108,14 @@ RDI_SectionKind_LocationBlocks = 0x0020, RDI_SectionKind_LocationData = 0x0021, RDI_SectionKind_ConstantValueData = 0x0022, RDI_SectionKind_ConstantValueTable = 0x0023, -RDI_SectionKind_ChecksumData = 0x0024, -RDI_SectionKind_ChecksumTable = 0x0025, -RDI_SectionKind_NameMaps = 0x0026, -RDI_SectionKind_NameMapBuckets = 0x0027, -RDI_SectionKind_NameMapNodes = 0x0028, -RDI_SectionKind_COUNT = 0x0029, +RDI_SectionKind_MD5Checksums = 0x0024, +RDI_SectionKind_SHA1Checksums = 0x0025, +RDI_SectionKind_SHA256Checksums = 0x0026, +RDI_SectionKind_Timestamps = 0x0027, +RDI_SectionKind_NameMaps = 0x0028, +RDI_SectionKind_NameMapBuckets = 0x0029, +RDI_SectionKind_NameMapNodes = 0x002A, +RDI_SectionKind_COUNT = 0x002B, } RDI_SectionKindEnum; typedef RDI_U32 RDI_SectionEncoding; @@ -310,11 +324,12 @@ RDI_BinarySectionFlag_Execute = 1<<2, typedef RDI_U16 RDI_ChecksumKind; typedef enum RDI_ChecksumKindEnum { -RDI_ChecksumKind_Null = 0, +RDI_ChecksumKind_NULL = 0, RDI_ChecksumKind_MD5 = 1, RDI_ChecksumKind_SHA1 = 2, RDI_ChecksumKind_SHA256 = 3, RDI_ChecksumKind_Timestamp = 4, +RDI_ChecksumKind_COUNT = 5, } RDI_ChecksumKindEnum; typedef RDI_U32 RDI_Language; @@ -590,8 +605,10 @@ X(LocationBlocks, location_blocks, RDI_LocationBlock)\ X(LocationData, location_data, RDI_U8)\ X(ConstantValueData, constant_value_data, RDI_U8)\ X(ConstantValueTable, constant_value_table, RDI_U32)\ -X(ChecksumData, checksum_data, RDI_U8)\ -X(ChecksumTable, checksum_table, RDI_U32)\ +X(MD5Checksums, md5_checksums, RDI_MD5)\ +X(SHA1Checksums, sha1_checksums, RDI_SHA1)\ +X(SHA256Checksums, sha256_checksums, RDI_SHA256)\ +X(Timestamps, timestamps, RDI_U64)\ X(NameMaps, name_maps, RDI_NameMap)\ X(NameMapBuckets, name_map_buckets, RDI_NameMapBucket)\ X(NameMapNodes, name_map_nodes, RDI_NameMapNode)\ @@ -805,11 +822,12 @@ X(RDI_U64, foff_first)\ X(RDI_U64, foff_opl)\ #define RDI_ChecksumKind_XList \ -X(Null)\ -X(MD5)\ -X(SHA1)\ -X(SHA256)\ -X(Timestamp)\ +X(NULL, NULL)\ +X(MD5, MD5Checksums)\ +X(SHA1, SHA1Checksums)\ +X(SHA256, SHA256Checksums)\ +X(Timestamp, Timestamps)\ +X(COUNT, NULL)\ #define RDI_FilePathNode_XList \ X(RDI_U32, name_string_idx)\ @@ -1173,7 +1191,10 @@ typedef struct RDI_U32_LocationBlocks { RDI_U32 v; } RDI_U32_Locati typedef struct RDI_U32_LocationData { RDI_U32 v; } RDI_U32_LocationData; typedef struct RDI_U32_ConstantValueData { RDI_U32 v; } RDI_U32_ConstantValueData; typedef struct RDI_U32_ConstantValueTable { RDI_U32 v; } RDI_U32_ConstantValueTable; -typedef struct RDI_U32_ChecksumTable { RDI_U32 v; } RDI_U32_ChecksumTable; +typedef struct RDI_U32_MD5Checksums { RDI_U32 v; } RDI_U32_MD5Checksums; +typedef struct RDI_U32_SHA1Checksums { RDI_U32 v; } RDI_U32_SHA1Checksums; +typedef struct RDI_U32_SHA256Checksums { RDI_U32 v; } RDI_U32_SHA256Checksums; +typedef struct RDI_U32_Timestamps { RDI_U32 v; } RDI_U32_Timestamps; typedef struct RDI_U32_NameMaps { RDI_U32 v; } RDI_U32_NameMaps; typedef struct RDI_U32_NameMapBuckets { RDI_U32 v; } RDI_U32_NameMapBuckets; typedef struct RDI_U32_NameMapNodes { RDI_U32 v; } RDI_U32_NameMapNodes; @@ -1210,7 +1231,10 @@ typedef RDI_U32_Table RDI_U32_LocationBlocks; typedef RDI_U32_Table RDI_U32_LocationData; typedef RDI_U32_Table RDI_U32_ConstantValueData; typedef RDI_U32_Table RDI_U32_ConstantValueTable; -typedef RDI_U32_Table RDI_U32_ChecksumTable; +typedef RDI_U32_Table RDI_U32_MD5Checksums; +typedef RDI_U32_Table RDI_U32_SHA1Checksums; +typedef RDI_U32_Table RDI_U32_SHA256Checksums; +typedef RDI_U32_Table RDI_U32_Timestamps; typedef RDI_U32_Table RDI_U32_NameMaps; typedef RDI_U32_Table RDI_U32_NameMapBuckets; typedef RDI_U32_Table RDI_U32_NameMapNodes; @@ -1578,8 +1602,10 @@ typedef RDI_LocationBlock RDI_SectionElementType_LocationBlocks; typedef RDI_U8 RDI_SectionElementType_LocationData; typedef RDI_U8 RDI_SectionElementType_ConstantValueData; typedef RDI_U32 RDI_SectionElementType_ConstantValueTable; -typedef RDI_U8 RDI_SectionElementType_ChecksumData; -typedef RDI_U32 RDI_SectionElementType_ChecksumTable; +typedef RDI_MD5 RDI_SectionElementType_MD5Checksums; +typedef RDI_SHA1 RDI_SectionElementType_SHA1Checksums; +typedef RDI_SHA256 RDI_SectionElementType_SHA256Checksums; +typedef RDI_U64 RDI_SectionElementType_Timestamps; typedef RDI_NameMap RDI_SectionElementType_NameMaps; typedef RDI_NameMapBucket RDI_SectionElementType_NameMapBuckets; typedef RDI_NameMapNode RDI_SectionElementType_NameMapNodes; @@ -1592,7 +1618,7 @@ RDI_PROC RDI_EvalConversionKind rdi_eval_conversion_kind_from_typegroups(RDI_Eva RDI_PROC RDI_S32 rdi_eval_op_typegroup_are_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group); RDI_PROC RDI_U8 *rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RDI_U64 *size_out); -extern RDI_U16 rdi_section_element_size_table[42]; +extern RDI_U16 rdi_section_element_size_table[44]; extern RDI_U16 rdi_eval_op_ctrlbits_table[52]; #endif // RDI_H diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index bfec01cb..25fc7f63 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -2026,8 +2026,9 @@ rdim_serialized_section_bundle_from_bake_results(RDIM_BakeResults *results) bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->locations.location_data, results->locations.location_data_size); bundle.sections[RDI_SectionKind_ConstantValueData] = rdim_serialized_section_make_unpacked_array(results->constants.constant_value_data, results->constants.constant_value_data_size); bundle.sections[RDI_SectionKind_ConstantValueTable] = rdim_serialized_section_make_unpacked_array(results->constants.constant_values, results->constants.constant_values_count); - bundle.sections[RDI_SectionKind_ChecksumData] = rdim_serialized_section_make_unpacked_array(results->checksums.data, results->checksums.data_size); - bundle.sections[RDI_SectionKind_ChecksumTable] = rdim_serialized_section_make_unpacked_array(results->checksums.offs, results->checksums.offs_count); + bundle.sections[RDI_SectionKind_MD5Checksums] = rdim_serialized_section_make_unpacked_array(results->checksums.md5s, results->checksums.md5s_count); + bundle.sections[RDI_SectionKind_SHA1Checksums] = rdim_serialized_section_make_unpacked_array(results->checksums.sha1s, results->checksums.sha1s_count); + bundle.sections[RDI_SectionKind_SHA256Checksums] = rdim_serialized_section_make_unpacked_array(results->checksums.sha256s, results->checksums.sha256s_count); bundle.sections[RDI_SectionKind_NameMaps] = rdim_serialized_section_make_unpacked_array(results->top_level_name_maps.name_maps, results->top_level_name_maps.name_maps_count); bundle.sections[RDI_SectionKind_NameMapBuckets] = rdim_serialized_section_make_unpacked_array(results->name_maps.buckets, results->name_maps.buckets_count); bundle.sections[RDI_SectionKind_NameMapNodes] = rdim_serialized_section_make_unpacked_array(results->name_maps.nodes, results->name_maps.nodes_count); diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 9f6eb541..cab8df40 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1315,10 +1315,14 @@ struct RDIM_SrcFileBakeResult typedef struct RDIM_ChecksumBakeResult RDIM_ChecksumBakeResult; struct RDIM_ChecksumBakeResult { - RDI_U32 *offs; - RDI_U64 offs_count; - RDI_U8 *data; - RDI_U64 data_size; + RDI_MD5 *md5s; + RDI_U64 md5s_count; + RDI_SHA1 *sha1s; + RDI_U64 sha1s_count; + RDI_SHA256 *sha256s; + RDI_U64 sha256s_count; + RDI_U64 *timestamps; + RDI_U64 timestamps_count; }; typedef struct RDIM_LineTableBakeResult RDIM_LineTableBakeResult; diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 7e8a8bc5..a4a219b2 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -51,6 +51,18 @@ "#endif"; ""; "////////////////////////////////////////////////////////////////"; + "//~ Checksum Types"; + ""; + "typedef union RDI_MD5 RDI_MD5;"; + "union RDI_MD5 {RDI_U8 u8[16]; RDI_U64 u64[2];};"; + ""; + "typedef union RDI_SHA1 RDI_SHA1;"; + "union RDI_SHA1 {RDI_U8 u8[20];};"; + ""; + "typedef union RDI_SHA256 RDI_SHA256;"; + "union RDI_SHA256 {RDI_U8 u8[32]; RDI_U64 u64[4];};"; + ""; + "////////////////////////////////////////////////////////////////"; "//~ Overridable Enabling/Disabling Of Table Index Typechecking"; ""; "#if !defined(RDI_DISABLE_TABLE_INDEX_TYPECHECKING)"; @@ -62,7 +74,7 @@ ""; "// \"raddbg\\0\\0\""; "#define RDI_MAGIC_CONSTANT 0x0000676264646172"; - "#define RDI_ENCODING_VERSION 14"; + "#define RDI_ENCODING_VERSION 15"; ""; "////////////////////////////////////////////////////////////////"; "//~ Format Types & Functions"; @@ -156,12 +168,14 @@ RDI_SectionTable: {LocationData location_data RDI_U8 0x0021 U32 ""} {ConstantValueData constant_value_data RDI_U8 0x0022 U32 ""} {ConstantValueTable constant_value_table RDI_U32 0x0023 U32 ""} - {ChecksumData checksum_data RDI_U8 0x0024 - ""} - {ChecksumTable checksum_table RDI_U32 0x0025 U32 ""} - {NameMaps name_maps RDI_NameMap 0x0026 U32 ""} - {NameMapBuckets name_map_buckets RDI_NameMapBucket 0x0027 U32 ""} - {NameMapNodes name_map_nodes RDI_NameMapNode 0x0028 U32 ""} - {COUNT count RDI_U8 0x0029 - ""} + {MD5Checksums md5_checksums RDI_MD5 0x0024 U32 ""} + {SHA1Checksums sha1_checksums RDI_SHA1 0x0025 U32 ""} + {SHA256Checksums sha256_checksums RDI_SHA256 0x0026 U32 ""} + {Timestamps timestamps RDI_U64 0x0027 U32 ""} + {NameMaps name_maps RDI_NameMap 0x0028 U32 ""} + {NameMapBuckets name_map_buckets RDI_NameMapBucket 0x0029 U32 ""} + {NameMapNodes name_map_nodes RDI_NameMapNode 0x002A U32 ""} + {COUNT count RDI_U8 0x002B - ""} } @table(name value) @@ -539,14 +553,15 @@ RDI_BinarySectionMemberTable: //////////////////////////////// //~ rjf: Checksum Type Tables -@table(name value) +@table(name value section) RDI_ChecksumKindTable: { - {Null 0} - {MD5 1} - {SHA1 2} - {SHA256 3} - {Timestamp 4} + {NULL 0 NULL } + {MD5 1 MD5Checksums } + {SHA1 2 SHA1Checksums } + {SHA256 3 SHA256Checksums} + {Timestamp 4 Timestamps } + {COUNT 5 NULL } } @enum(RDI_U16) RDI_ChecksumKind: @@ -556,7 +571,7 @@ RDI_ChecksumKindTable: @xlist RDI_ChecksumKind_XList: { - @expand(RDI_ChecksumKindTable a) `$(a.name)`; + @expand(RDI_ChecksumKindTable a) `$(a.name), $(a.section)`; } //////////////////////////////// diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index ca15f48a..ac59bb6f 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -267,10 +267,10 @@ p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type) internal RDI_ChecksumKind p2r_rdi_from_cv_c13_checksum_kind(CV_C13ChecksumKind k) { - RDI_ChecksumKind result = RDI_ChecksumKind_Null; + RDI_ChecksumKind result = RDI_ChecksumKind_NULL; switch((CV_C13ChecksumKindEnum)k) { - case CV_C13ChecksumKind_Null: {result = RDI_ChecksumKind_Null;}break; + case CV_C13ChecksumKind_Null: {result = RDI_ChecksumKind_NULL;}break; case CV_C13ChecksumKind_MD5: {result = RDI_ChecksumKind_MD5;}break; case CV_C13ChecksumKind_SHA1: {result = RDI_ChecksumKind_SHA1;}break; case CV_C13ChecksumKind_SHA256:{result = RDI_ChecksumKind_SHA256;}break; diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index e6481551..f03b7614 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -1928,14 +1928,15 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) // rjf: allocate if(lane_idx() == 0) { - rdim_shared->lane_chunk_src_file_checksum_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim_shared->lane_chunk_src_file_checksum_sizes = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim_shared->lane_chunk_src_file_checksum_off_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim_shared->lane_chunk_src_file_checksum_data_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + for EachEnumVal(RDI_ChecksumKind, k) + { + rdim_shared->lane_chunk_src_file_checksum_counts[k] = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_checksum_offs[k] = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + } } lane_sync(); - // rjf: compute counts / sizes of all checksum data + // rjf: compute counts of all checksums { U64 chunk_idx = 0; for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) @@ -1944,10 +1945,9 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; for EachInRange(n_idx, range) { - if(n->v[n_idx].checksum_kind != RDI_ChecksumKind_Null && n->v[n_idx].checksum.size != 0) + if(RDI_ChecksumKind_NULL < n->v[n_idx].checksum_kind && n->v[n_idx].checksum_kind < RDI_ChecksumKind_COUNT && n->v[n_idx].checksum.size != 0) { - rdim_shared->lane_chunk_src_file_checksum_counts[slot_idx] += 1; - rdim_shared->lane_chunk_src_file_checksum_sizes[slot_idx] += n->v[n_idx].checksum.size; + rdim_shared->lane_chunk_src_file_checksum_counts[n->v[n_idx].checksum_kind][slot_idx] += 1; } } chunk_idx += 1; @@ -1958,23 +1958,22 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) // rjf: lay out per-lane-chunk offsets if(lane_idx() == 0) { - U64 off_off = 0; - U64 data_off = 0; - U64 chunk_idx = 0; - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + for EachEnumVal(RDI_ChecksumKind, k) { - for EachIndex(l_idx, lane_count()) + U64 off = 0; + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { - U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; - rdim_shared->lane_chunk_src_file_checksum_off_offs[slot_idx] = off_off; - rdim_shared->lane_chunk_src_file_checksum_data_offs[slot_idx] = data_off; - off_off += rdim_shared->lane_chunk_src_file_checksum_counts[slot_idx]; - data_off += rdim_shared->lane_chunk_src_file_checksum_sizes[slot_idx]; + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; + rdim_shared->lane_chunk_src_file_checksum_offs[k][slot_idx] = off; + off += rdim_shared->lane_chunk_src_file_checksum_counts[k][slot_idx]; + } + chunk_idx += 1; } - chunk_idx += 1; + rdim_shared->total_checksum_counts[k] = off; } - rdim_shared->total_checksum_count = off_off; - rdim_shared->total_checksum_size = data_off; } } lane_sync(); @@ -1987,10 +1986,14 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) // rjf: allocate if(lane_idx() == 0) { - rdim_shared->baked_checksums.offs_count = rdim_shared->total_checksum_count+1; - rdim_shared->baked_checksums.offs = push_array(arena, U32, rdim_shared->baked_checksums.offs_count); - rdim_shared->baked_checksums.data_size = rdim_shared->total_checksum_size; - rdim_shared->baked_checksums.data = push_array(arena, U8, rdim_shared->baked_checksums.data_size); + rdim_shared->baked_checksums.md5s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_MD5]; + rdim_shared->baked_checksums.sha1s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_SHA1]; + rdim_shared->baked_checksums.sha256s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_SHA256]; + rdim_shared->baked_checksums.timestamps_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_Timestamp]; + rdim_shared->baked_checksums.md5s = push_array(arena, RDI_MD5, rdim_shared->baked_checksums.md5s_count); + rdim_shared->baked_checksums.sha1s = push_array(arena, RDI_SHA1, rdim_shared->baked_checksums.sha1s_count); + rdim_shared->baked_checksums.sha256s = push_array(arena, RDI_SHA256, rdim_shared->baked_checksums.sha256s_count); + rdim_shared->baked_checksums.timestamps = push_array(arena, RDI_U64, rdim_shared->baked_checksums.timestamps_count); } lane_sync(); @@ -2001,24 +2004,34 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { Rng1U64 range = lane_range(n->count); U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; - U64 dst_off_off = rdim_shared->lane_chunk_src_file_checksum_off_offs[slot_idx]; - U64 dst_data_off = rdim_shared->lane_chunk_src_file_checksum_data_offs[slot_idx]; + U64 dst_offs[RDI_ChecksumKind_COUNT] = {0}; + for EachEnumVal(RDI_ChecksumKind, k) + { + dst_offs[k] = rdim_shared->lane_chunk_src_file_checksum_offs[k][slot_idx]; + } for EachInRange(n_idx, range) { - if(n->v[n_idx].checksum_kind != RDI_ChecksumKind_Null && n->v[n_idx].checksum.size != 0) + RDI_ChecksumKind k = n->v[n_idx].checksum_kind; + String8 val = n->v[n_idx].checksum; + if(RDI_ChecksumKind_NULL < k && k < RDI_ChecksumKind_COUNT && val.size != 0) { - rdim_shared->baked_checksums.offs[dst_off_off] = (U32)dst_data_off; - MemoryCopy(&rdim_shared->baked_checksums.data[dst_data_off], n->v[n_idx].checksum.str, n->v[n_idx].checksum.size); - dst_off_off += 1; - dst_data_off += n->v[n_idx].checksum.size; + switch((RDI_ChecksumKindEnum)k) + { + case RDI_ChecksumKind_NULL: + case RDI_ChecksumKind_COUNT: + {}break; +#define Case(name, table_name) case RDI_ChecksumKind_##name:{MemoryCopy(&rdim_shared->baked_checksums.table_name[dst_offs[k]], val.str, Min(val.size, sizeof(rdim_shared->baked_checksums.table_name[0])));}break + Case(MD5, md5s); + Case(SHA1, sha1s); + Case(SHA256, sha256s); + Case(Timestamp, timestamps); +#undef Case + } + dst_offs[k] += 1; } } chunk_idx += 1; } - if(lane_idx() == 0) - { - rdim_shared->baked_checksums.offs[rdim_shared->baked_checksums.offs_count-1] = rdim_shared->baked_checksums.data_size; - } } } lane_sync(); diff --git a/src/rdi_make/rdi_make_local.h b/src/rdi_make/rdi_make_local.h index e6ad029c..bd4a0878 100644 --- a/src/rdi_make/rdi_make_local.h +++ b/src/rdi_make/rdi_make_local.h @@ -136,12 +136,9 @@ struct RDIM_Shared RDIM_SrcFileBakeResult baked_src_files; - RDI_U64 *lane_chunk_src_file_checksum_counts; // [lane_count * src_file_chunk_count] - RDI_U64 *lane_chunk_src_file_checksum_sizes; // [lane_count * src_file_chunk_count] - RDI_U64 *lane_chunk_src_file_checksum_off_offs; // [lane_count * src_file_chunk_count] - RDI_U64 *lane_chunk_src_file_checksum_data_offs; // [lane_count * src_file_chunk_count] - U64 total_checksum_count; - U64 total_checksum_size; + RDI_U64 *lane_chunk_src_file_checksum_counts[RDI_ChecksumKind_COUNT]; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_checksum_offs[RDI_ChecksumKind_COUNT]; // [lane_count * src_file_chunk_count] + U64 total_checksum_counts[RDI_ChecksumKind_COUNT]; RDIM_ChecksumBakeResult baked_checksums; From 2d672d232f60e6fd22da01601fed69e43669af8c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 16:12:53 -0700 Subject: [PATCH 026/133] checksum baking & rdi changes; checksum dumping --- src/lib_rdi/rdi.c | 17 ++++++ src/lib_rdi/rdi.h | 8 ++- src/rdi/rdi.mdesk | 28 +++++++-- src/rdi/rdi_local.c | 28 ++++++++- src/rdi_make/rdi_make_local.c | 103 +++++++++++++--------------------- src/rdi_make/rdi_make_local.h | 9 ++- 6 files changed, 117 insertions(+), 76 deletions(-) diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index 444f43d4..dc297153 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -321,4 +321,21 @@ rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RD return rdi_eval_conversion_kind_message_string_table[kind].str; } +RDI_PROC RDI_SectionKind +rdi_section_kind_from_checksum_kind(RDI_ChecksumKind kind) +{ +RDI_SectionKind result = 0; +switch(kind) +{ +default:{}break; +case RDI_ChecksumKind_NULL:{result = RDI_SectionKind_NULL;}break; +case RDI_ChecksumKind_MD5:{result = RDI_SectionKind_MD5Checksums;}break; +case RDI_ChecksumKind_SHA1:{result = RDI_SectionKind_SHA1Checksums;}break; +case RDI_ChecksumKind_SHA256:{result = RDI_SectionKind_SHA256Checksums;}break; +case RDI_ChecksumKind_Timestamp:{result = RDI_SectionKind_Timestamps;}break; +case RDI_ChecksumKind_COUNT:{result = RDI_SectionKind_NULL;}break; +} +return result; +} + #endif // RDI_C diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index d782fb31..4d052bce 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -64,7 +64,7 @@ union RDI_SHA256 {RDI_U8 u8[32]; RDI_U64 u64[4];}; // "raddbg\0\0" #define RDI_MAGIC_CONSTANT 0x0000676264646172 -#define RDI_ENCODING_VERSION 15 +#define RDI_ENCODING_VERSION 16 //////////////////////////////////////////////////////////////// //~ Format Types & Functions @@ -321,7 +321,7 @@ RDI_BinarySectionFlag_Write = 1<<1, RDI_BinarySectionFlag_Execute = 1<<2, } RDI_BinarySectionFlagsEnum; -typedef RDI_U16 RDI_ChecksumKind; +typedef RDI_U32 RDI_ChecksumKind; typedef enum RDI_ChecksumKindEnum { RDI_ChecksumKind_NULL = 0, @@ -840,6 +840,8 @@ X(RDI_U32, source_file_idx)\ X(RDI_U32, file_path_node_idx)\ X(RDI_U32, normal_full_path_string_idx)\ X(RDI_U32, source_line_map_idx)\ +X(RDI_ChecksumKind, checksum_kind)\ +X(RDI_U32, checksum_idx)\ #define RDI_Unit_XList \ X(RDI_U32, unit_name_string_idx)\ @@ -1309,6 +1311,8 @@ struct RDI_SourceFile RDI_U32 file_path_node_idx; RDI_U32 normal_full_path_string_idx; RDI_U32 source_line_map_idx; +RDI_ChecksumKind checksum_kind; +RDI_U32 checksum_idx; }; typedef struct RDI_Unit RDI_Unit; diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index a4a219b2..d106d98d 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -74,7 +74,7 @@ ""; "// \"raddbg\\0\\0\""; "#define RDI_MAGIC_CONSTANT 0x0000676264646172"; - "#define RDI_ENCODING_VERSION 15"; + "#define RDI_ENCODING_VERSION 16"; ""; "////////////////////////////////////////////////////////////////"; "//~ Format Types & Functions"; @@ -564,7 +564,7 @@ RDI_ChecksumKindTable: {COUNT 5 NULL } } -@enum(RDI_U16) RDI_ChecksumKind: +@enum(RDI_U32) RDI_ChecksumKind: { @expand(RDI_ChecksumKindTable a) `$(a.name .. =>10) = $(a.value)` } @@ -590,13 +590,15 @@ RDI_FilePathNodeMemberTable: @table(name type desc) RDI_SourceFileMemberTable: { - {file_path_node_idx RDI_U32 ""} - {normal_full_path_string_idx RDI_U32 ""} + {file_path_node_idx RDI_U32 ""} + {normal_full_path_string_idx RDI_U32 ""} // usage of line map to go from a line number to an array of voffs // (line_map_nums * line_number) -> (nil | index) // (line_map_data * index) -> (range) // (line_map_voff_data * range) -> (array(voff)) - {source_line_map_idx RDI_U32 ""} + {source_line_map_idx RDI_U32 ""} + {checksum_kind RDI_ChecksumKind ""} + {checksum_idx RDI_U32 ""} } @xlist RDI_FilePathNode_XList: @@ -1648,3 +1650,19 @@ rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RD return rdi_eval_conversion_kind_message_string_table[kind].str; } ``` + +@gen(functions) @c_file +{ + `RDI_PROC RDI_SectionKind`; + `rdi_section_kind_from_checksum_kind(RDI_ChecksumKind kind)`; + `{`; + `RDI_SectionKind result = 0;`; + `switch(kind)`; + `{`; + `default:{}break;`; + @expand(RDI_ChecksumKindTable a) `case RDI_ChecksumKind_$(a.name):{result = RDI_SectionKind_$(a.section);}break;`, + `}`; + `return result;`; + `}`; + ``; +} diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index 8473578c..0d91e869 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -671,13 +671,39 @@ lane_sync(); if(flags & RDI_DumpSubsetFlag_##name) ProfScope(#name) { U64 count = 0; RDI_SourceFile *v = rdi_table_from_name(rdi, SourceFiles, &count); + U64 checksums_count[RDI_ChecksumKind_COUNT] = {0}; + RDI_U8 *checksums_data[RDI_ChecksumKind_COUNT] = {0}; + RDI_U64 checksums_element_sizes[RDI_ChecksumKind_COUNT] = {0}; + for EachEnumVal(RDI_ChecksumKind, k) + { + RDI_SectionKind section_kind = rdi_section_kind_from_checksum_kind(k); + checksums_data[k] = rdi_section_raw_table_from_kind(rdi, section_kind, &checksums_count[k]); + checksums_element_sizes[k] = rdi_section_element_size_table[section_kind]; + } Rng1U64 range = lane_range(count); for EachInRange(idx, range) { RDI_SourceFile *source_file = &v[idx]; - dumpf("\n { file_path_node_idx: %4u, source_line_map: %4u, path: %-192S } // source_file[%I64u]", + RDI_ChecksumKind checksum_kind = source_file->checksum_kind; + RDI_U32 checksum_idx = source_file->checksum_idx; + String8 checksum_kind_name = {0}; + switch(checksum_kind) + { + default:{checksum_kind_name = str8_lit("Null");}break; +#define X(name, s) case RDI_ChecksumKind_##name:{checksum_kind_name = str8_lit(#name);}break; + RDI_ChecksumKind_XList +#undef X + } + String8 checksum_value = str8(checksums_data[checksum_kind] + checksums_element_sizes[checksum_kind]*checksum_idx, checksums_element_sizes[checksum_kind]); + String8List checksum_vals = numeric_str8_list_from_data(arena, 16, checksum_value, 1); + StringJoin join = {0}; + join.sep = str8_lit(", "); + String8 checksum_val_string = str8_list_join(arena, &checksum_vals, &join); + dumpf("\n { file_path_node_idx: %4u, source_line_map: %4u, checksum_kind: %10S, checksum_value: %192S, path: %-192S } // source_file[%I64u]", source_file->file_path_node_idx, source_file->source_line_map_idx, + checksum_kind_name, + checksum_val_string, push_str8f(arena, "'%S'", str8_from_rdi_string_idx(rdi, source_file->normal_full_path_string_idx)), idx); } diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index f03b7614..70ccc333 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -1785,6 +1785,11 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) rdim_shared->lane_chunk_src_file_num_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); rdim_shared->lane_chunk_src_file_voff_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); rdim_shared->lane_chunk_src_file_map_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + for EachEnumVal(RDI_ChecksumKind, k) + { + rdim_shared->lane_chunk_src_file_checksum_counts[k] = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_checksum_offs[k] = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + } } lane_sync(); @@ -1801,6 +1806,12 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) rdim_shared->lane_chunk_src_file_num_counts[slot_idx] += map->line_count; rdim_shared->lane_chunk_src_file_voff_counts[slot_idx] += map->voff_range_count; rdim_shared->lane_chunk_src_file_map_counts[slot_idx] += !!map->line_count; + RDI_ChecksumKind k = n->v[idx].checksum_kind; + String8 val = n->v[idx].checksum; + if(RDI_ChecksumKind_NULL < k && k < RDI_ChecksumKind_COUNT && val.size != 0) + { + rdim_shared->lane_chunk_src_file_checksum_counts[k][slot_idx] += 1; + } } chunk_idx += 1; } @@ -1814,6 +1825,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) U64 num_layout_off = 0; U64 voff_layout_off = 0; U64 map_layout_off = 1; + U64 checksum_layout_offs[RDI_ChecksumKind_COUNT] = {0}; for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { for EachIndex(l_idx, lane_count()) @@ -1825,11 +1837,20 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) num_layout_off += rdim_shared->lane_chunk_src_file_num_counts[slot_idx]; voff_layout_off += rdim_shared->lane_chunk_src_file_voff_counts[slot_idx]; map_layout_off += rdim_shared->lane_chunk_src_file_map_counts[slot_idx]; + for EachEnumVal(RDI_ChecksumKind, k) + { + rdim_shared->lane_chunk_src_file_checksum_offs[k][slot_idx] = checksum_layout_offs[k]; + checksum_layout_offs[k] += rdim_shared->lane_chunk_src_file_checksum_counts[k][slot_idx]; + } } chunk_idx += 1; } rdim_shared->total_src_map_line_count = num_layout_off; rdim_shared->total_src_map_voff_count = voff_layout_off; + for EachEnumVal(RDI_ChecksumKind, k) + { + rdim_shared->total_checksum_counts[k] = checksum_layout_offs[k]; + } } } lane_sync(); @@ -1865,6 +1886,11 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) U64 dst_map_off = rdim_shared->lane_chunk_src_file_map_offs[slot_idx]; U64 dst_voff_off = rdim_shared->lane_chunk_src_file_voff_offs[slot_idx]; U64 dst_rng_off = dst_num_off + dst_map_off; + U64 dst_checksums_off[RDI_ChecksumKind_COUNT] = {0}; + for EachEnumVal(RDI_ChecksumKind, k) + { + dst_checksums_off[k] = 1 + rdim_shared->lane_chunk_src_file_checksum_offs[k][slot_idx]; + } for EachInRange(idx, range) { RDIM_BakeSrcLineMap *map = &rdim_shared->bake_src_line_maps[n->base_idx + idx]; @@ -1879,11 +1905,20 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: fill file info Temp scratch = scratch_begin(&arena, 1); String8 normalized_path = rdim_lower_from_str8(scratch.arena, src->path); + B32 has_checksum = (RDI_ChecksumKind_NULL < src->checksum_kind && src->checksum_kind < RDI_ChecksumKind_COUNT && src->checksum.size != 0); dst->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src->path); dst->normal_full_path_string_idx = rdim_bake_idx_from_string(bake_strings, normalized_path); dst->source_line_map_idx = src->total_line_count ? dst_map_off : 0; + dst->checksum_kind = src->checksum_kind; + dst->checksum_idx = has_checksum ? dst_checksums_off[dst->checksum_kind] : 0; scratch_end(scratch); + //- rjf: advance checksum offset for this kind + if(has_checksum) + { + dst_checksums_off[dst->checksum_kind] += 1; + } + //- rjf: fill map info if(src->total_line_count != 0) { @@ -1920,64 +1955,6 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } } - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage compute lane checksum layouts - // - ProfScope("compute lane checksum layouts") - { - // rjf: allocate - if(lane_idx() == 0) - { - for EachEnumVal(RDI_ChecksumKind, k) - { - rdim_shared->lane_chunk_src_file_checksum_counts[k] = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim_shared->lane_chunk_src_file_checksum_offs[k] = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - } - } - lane_sync(); - - // rjf: compute counts of all checksums - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) - { - Rng1U64 range = lane_range(n->count); - U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; - for EachInRange(n_idx, range) - { - if(RDI_ChecksumKind_NULL < n->v[n_idx].checksum_kind && n->v[n_idx].checksum_kind < RDI_ChecksumKind_COUNT && n->v[n_idx].checksum.size != 0) - { - rdim_shared->lane_chunk_src_file_checksum_counts[n->v[n_idx].checksum_kind][slot_idx] += 1; - } - } - chunk_idx += 1; - } - } - lane_sync(); - - // rjf: lay out per-lane-chunk offsets - if(lane_idx() == 0) - { - for EachEnumVal(RDI_ChecksumKind, k) - { - U64 off = 0; - U64 chunk_idx = 0; - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) - { - for EachIndex(l_idx, lane_count()) - { - U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; - rdim_shared->lane_chunk_src_file_checksum_offs[k][slot_idx] = off; - off += rdim_shared->lane_chunk_src_file_checksum_counts[k][slot_idx]; - } - chunk_idx += 1; - } - rdim_shared->total_checksum_counts[k] = off; - } - } - } - lane_sync(); - ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake checksums // @@ -1986,10 +1963,10 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) // rjf: allocate if(lane_idx() == 0) { - rdim_shared->baked_checksums.md5s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_MD5]; - rdim_shared->baked_checksums.sha1s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_SHA1]; - rdim_shared->baked_checksums.sha256s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_SHA256]; - rdim_shared->baked_checksums.timestamps_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_Timestamp]; + rdim_shared->baked_checksums.md5s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_MD5] + 1; + rdim_shared->baked_checksums.sha1s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_SHA1] + 1; + rdim_shared->baked_checksums.sha256s_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_SHA256] + 1; + rdim_shared->baked_checksums.timestamps_count = rdim_shared->total_checksum_counts[RDI_ChecksumKind_Timestamp] + 1; rdim_shared->baked_checksums.md5s = push_array(arena, RDI_MD5, rdim_shared->baked_checksums.md5s_count); rdim_shared->baked_checksums.sha1s = push_array(arena, RDI_SHA1, rdim_shared->baked_checksums.sha1s_count); rdim_shared->baked_checksums.sha256s = push_array(arena, RDI_SHA256, rdim_shared->baked_checksums.sha256s_count); @@ -2007,7 +1984,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) U64 dst_offs[RDI_ChecksumKind_COUNT] = {0}; for EachEnumVal(RDI_ChecksumKind, k) { - dst_offs[k] = rdim_shared->lane_chunk_src_file_checksum_offs[k][slot_idx]; + dst_offs[k] = 1 + rdim_shared->lane_chunk_src_file_checksum_offs[k][slot_idx]; } for EachInRange(n_idx, range) { diff --git a/src/rdi_make/rdi_make_local.h b/src/rdi_make/rdi_make_local.h index bd4a0878..b6134a4e 100644 --- a/src/rdi_make/rdi_make_local.h +++ b/src/rdi_make/rdi_make_local.h @@ -131,17 +131,16 @@ struct RDIM_Shared RDI_U64 *lane_chunk_src_file_num_offs; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_voff_offs; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_map_offs; // [lane_count * src_file_chunk_count] - RDI_U64 total_src_map_line_count; - RDI_U64 total_src_map_voff_count; - - RDIM_SrcFileBakeResult baked_src_files; - RDI_U64 *lane_chunk_src_file_checksum_counts[RDI_ChecksumKind_COUNT]; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_checksum_offs[RDI_ChecksumKind_COUNT]; // [lane_count * src_file_chunk_count] U64 total_checksum_counts[RDI_ChecksumKind_COUNT]; + RDI_U64 total_src_map_line_count; + RDI_U64 total_src_map_voff_count; RDIM_ChecksumBakeResult baked_checksums; + RDIM_SrcFileBakeResult baked_src_files; + RDI_U64 *member_chunk_lane_counts; // [lane_count * udt_chunk_count] RDI_U64 *member_chunk_lane_offs; // [lane_count * udt_chunk_count] RDI_U64 *enum_val_chunk_lane_counts; // [lane_count * udt_chunk_count] From 104e72999c5993d241670887b91217aec13cbcf3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 16:20:34 -0700 Subject: [PATCH 027/133] base layer hashing algorithms, fill out md5 --- src/base/base_hash.c | 36 ++++++++++++++++++++++++++++++++++++ src/base/base_hash.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/base/base_inc.c | 1 + src/base/base_inc.h | 1 + 4 files changed, 82 insertions(+) create mode 100644 src/base/base_hash.c create mode 100644 src/base/base_hash.h diff --git a/src/base/base_hash.c b/src/base/base_hash.c new file mode 100644 index 00000000..664b4710 --- /dev/null +++ b/src/base/base_hash.c @@ -0,0 +1,36 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Hash Functions + +#if !defined(MD5_API) +# define MD5_API static +# include "third_party/md5/md5.c" +# include "third_party/md5/md5.h" +#endif + +internal MD5 +md5_from_data(String8 data) +{ + MD5_CTX ctx = {0}; + MD5_Init(&ctx); + MD5_Update(&ctx, (void*)data.str, data.size); + MD5 result = {0}; + MD5_Final(result.u8, &ctx); + return result; +} + +internal SHA1 +sha1_from_data(String8 data) +{ + SHA1 result = {0}; + return result; +} + +internal SHA256 +sha256_from_data(String8 data) +{ + SHA256 result = {0}; + return result; +} diff --git a/src/base/base_hash.h b/src/base/base_hash.h new file mode 100644 index 00000000..55149541 --- /dev/null +++ b/src/base/base_hash.h @@ -0,0 +1,44 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_HASH_H +#define BASE_HASH_H + +//////////////////////////////// +//~ rjf: Hash Result Types + +typedef union MD5 MD5; +union MD5 +{ + U8 u8[16]; + U16 u16[8]; + U32 u32[4]; + U64 u64[2]; + U128 u128; +}; + +typedef union SHA1 SHA1; +union SHA1 +{ + U8 u8[20]; +}; + +typedef union SHA256 SHA256; +union SHA256 +{ + U8 u8[32]; + U16 u16[16]; + U32 u32[8]; + U64 u64[4]; + U128 u128[2]; + U256 u256; +}; + +//////////////////////////////// +//~ rjf: Hash Functions + +internal MD5 md5_from_data(String8 data); +internal SHA1 sha1_from_data(String8 data); +internal SHA256 sha256_from_data(String8 data); + +#endif // BASE_HASH_H diff --git a/src/base/base_inc.c b/src/base/base_inc.c index 7e9462f5..84444597 100644 --- a/src/base/base_inc.c +++ b/src/base/base_inc.c @@ -12,6 +12,7 @@ #include "base_arena.c" #include "base_math.c" #include "base_strings.c" +#include "base_hash.c" #include "base_threads.c" #include "base_thread_context.c" #include "base_command_line.c" diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 4bf367da..1647d03a 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -14,6 +14,7 @@ #include "base_arena.h" #include "base_math.h" #include "base_strings.h" +#include "base_hash.h" #include "base_threads.h" #include "base_thread_context.h" #include "base_command_line.h" From ee759dbac75379cd2b514a06344727b30d6cebd1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 17:07:16 -0700 Subject: [PATCH 028/133] sha1/sha256 --- src/base/base_hash.c | 19 +- src/base/base_hash.h | 6 +- src/third_party/tomcrypt_hash/tomcrypt_hash.h | 567 ++++++++++++++++++ 3 files changed, 590 insertions(+), 2 deletions(-) create mode 100644 src/third_party/tomcrypt_hash/tomcrypt_hash.h diff --git a/src/base/base_hash.c b/src/base/base_hash.c index 664b4710..6799d6b2 100644 --- a/src/base/base_hash.c +++ b/src/base/base_hash.c @@ -2,7 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: Hash Functions +//~ rjf: MD5 #if !defined(MD5_API) # define MD5_API static @@ -21,10 +21,21 @@ md5_from_data(String8 data) return result; } +//////////////////////////////// +//~ rjf: SHA1 + +#include "third_party/tomcrypt_hash/tomcrypt_hash.h" + internal SHA1 sha1_from_data(String8 data) { SHA1 result = {0}; + { + SHA1State state = {0}; + sha1_init(&state); + sha1_process(&state, data.str, data.size); + sha1_done(&state, result.u8); + } return result; } @@ -32,5 +43,11 @@ internal SHA256 sha256_from_data(String8 data) { SHA256 result = {0}; + { + SHA256State state = {0}; + sha256_init(&state); + sha256_process(&state, data.str, data.size); + sha256_done(&state, result.u8); + } return result; } diff --git a/src/base/base_hash.h b/src/base/base_hash.h index 55149541..fc83487a 100644 --- a/src/base/base_hash.h +++ b/src/base/base_hash.h @@ -35,9 +35,13 @@ union SHA256 }; //////////////////////////////// -//~ rjf: Hash Functions +//~ rjf: MD5 internal MD5 md5_from_data(String8 data); + +//////////////////////////////// +//~ rjf: SHA + internal SHA1 sha1_from_data(String8 data); internal SHA256 sha256_from_data(String8 data); diff --git a/src/third_party/tomcrypt_hash/tomcrypt_hash.h b/src/third_party/tomcrypt_hash/tomcrypt_hash.h new file mode 100644 index 00000000..07770f01 --- /dev/null +++ b/src/third_party/tomcrypt_hash/tomcrypt_hash.h @@ -0,0 +1,567 @@ +// This is a collection of code originally sourced from LibTomCrypt, located at +// https://github.com/libtom/libtomcrypt, released under the following license: +// +// --- +// +// The LibTom license +// +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to +// +// --- +// +// The code has been narrowed down and slightly modified, to include only the +// things that the RAD Debugger project needs, and to work with the project's +// build structure cleanly. + +#ifndef TOMCRYPT_HASH_H +#define TOMCRYPT_HASH_H + +//////////////////////////////// +//~ rjf: Common Helpers + +#define CRYPT_OK 1 + +#define LOAD32H(x, y) \ +do { x = ((U32)((y)[0] & 255)<<24) | \ +((U32)((y)[1] & 255)<<16) | \ +((U32)((y)[2] & 255)<<8) | \ +((U32)((y)[3] & 255)); } while(0) + +#define STORE32H(x, y) \ +do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ +(y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0) + +#define STORE64H(x, y) \ +do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ +(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ +(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ +(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0) + +#define LTC_TMPVAR__(n, l) n ## l +#define LTC_TMPVAR_(n, l) LTC_TMPVAR__(n, l) +#define LTC_TMPVAR(n) LTC_TMPVAR_(LTC_ ## n ## _, __LINE__) + +#define ROL(x, y) ( (((U32)(x)<<(U32)((y)&31)) | (((U32)(x)&0xFFFFFFFFUL)>>(U32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) +#define ROR(x, y) ( ((((U32)(x)&0xFFFFFFFFUL)>>(U32)((y)&31)) | ((U32)(x)<<(U32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) +#define ROLc(x, y) ( (((U32)(x)<<(U32)((y)&31)) | (((U32)(x)&0xFFFFFFFFUL)>>(U32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) +#define RORc(x, y) ( ((((U32)(x)&0xFFFFFFFFUL)>>(U32)((y)&31)) | ((U32)(x)<<(U32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) + +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) + +//////////////////////////////// +//~ rjf: SHA256 + +typedef struct SHA256State SHA256State; +struct SHA256State +{ + U64 length; + U32 state[8], curlen; + U8 buf[64]; +}; + +/* Various logical functions */ +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x),(n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +/* compress 512-bits */ +static int s_sha256_compress(SHA256State *state, const unsigned char *buf) +{ + U32 S[8], W[64], t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = state->state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], buf + (4*i)); + } + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + } + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i,ki) \ +t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ +t1 = Sigma0(a) + Maj(a, b, c); \ +d += t0; \ +h = t0 + t1; + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); +#undef RND + + /* feedback */ + for (i = 0; i < 8; i++) { + state->state[i] = state->state[i] + S[i]; + } + return CRYPT_OK; +} + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int sha256_init(SHA256State *state) +{ + state->curlen = 0; + state->length = 0; + state->state[0] = 0x6A09E667UL; + state->state[1] = 0xBB67AE85UL; + state->state[2] = 0x3C6EF372UL; + state->state[3] = 0xA54FF53AUL; + state->state[4] = 0x510E527FUL; + state->state[5] = 0x9B05688CUL; + state->state[6] = 0x1F83D9ABUL; + state->state[7] = 0x5BE0CD19UL; + return CRYPT_OK; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ + +int sha256_process(SHA256State *state, const unsigned char *in, unsigned long inlen) +{ + unsigned long n; + int err; + int block_size = 64; + if(state->curlen > sizeof(state->buf)) + { + return 0; // CRYPT_INVALID_ARG + } + if(((state->length + inlen * 8) < state->length) || ((inlen * 8) < inlen)) + { + return 0; // CRYPT_HASH_OVERFLOW + } + while(inlen > 0) + { + if(state->curlen == 0 && inlen >= block_size) + { + if ((err = s_sha256_compress(state, in)) != CRYPT_OK) + { + return err; + } + state->length += block_size * 8; + in += block_size; + inlen -= block_size; + } else { + n = MIN(inlen, (block_size - state->curlen)); + MemoryCopy(state->buf + state->curlen, in, (size_t)n); + state->curlen += n; + in += n; + inlen -= n; + if(state->curlen == block_size) + { + if((err = s_sha256_compress(state, state->buf)) != CRYPT_OK) + { + return err; + } + state->length += 8*block_size; + state->curlen = 0; + } + } + } + return CRYPT_OK; +} + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful +*/ +int sha256_done(SHA256State *state, unsigned char *out) +{ + int i; + + if (state->curlen >= sizeof(state->buf)) { + return 0; // CRYPT_INVALID_ARG + } + + + /* increase the length of the message */ + state->length += state->curlen * 8; + + /* append the '1' bit */ + state->buf[state->curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (state->curlen > 56) { + while (state->curlen < 64) { + state->buf[state->curlen++] = (unsigned char)0; + } + s_sha256_compress(state, state->buf); + state->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (state->curlen < 56) { + state->buf[state->curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(state->length, state->buf+56); + s_sha256_compress(state, state->buf); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE32H(state->state[i], out+(4*i)); + } + return CRYPT_OK; +} + +#undef Ch +#undef Maj +#undef S +#undef R +#undef Sigma0 +#undef Sigma1 +#undef Gamma0 +#undef Gamma1 + +//////////////////////////////// +//~ rjf: SHA1 + +typedef struct SHA1State SHA1State; +struct SHA1State +{ + U64 length; + U32 state[5], curlen; + unsigned char buf[64]; +}; + +#define F0(x,y,z) (z ^ (x & (y ^ z))) +#define F1(x,y,z) (x ^ y ^ z) +#define F2(x,y,z) ((x & y) | (z & (x | y))) +#define F3(x,y,z) (x ^ y ^ z) + +static int s_sha1_compress(SHA1State *state, const unsigned char *buf) +{ + U32 a,b,c,d,e,W[80],i; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], buf + (4*i)); + } + + /* copy state */ + a = state->state[0]; + b = state->state[1]; + c = state->state[2]; + d = state->state[3]; + e = state->state[4]; + + /* expand it */ + for (i = 16; i < 80; i++) { + W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); + } + + /* compress */ + /* round one */ +#define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30); +#define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30); +#define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30); +#define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30); + +#ifdef LTC_SMALL_CODE + + for (i = 0; i < 20; ) { + FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 40; ) { + FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 60; ) { + FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 80; ) { + FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + +#else + + for (i = 0; i < 20; ) { + FF0(a,b,c,d,e,i++); + FF0(e,a,b,c,d,i++); + FF0(d,e,a,b,c,i++); + FF0(c,d,e,a,b,i++); + FF0(b,c,d,e,a,i++); + } + + /* round two */ + for (; i < 40; ) { + FF1(a,b,c,d,e,i++); + FF1(e,a,b,c,d,i++); + FF1(d,e,a,b,c,i++); + FF1(c,d,e,a,b,i++); + FF1(b,c,d,e,a,i++); + } + + /* round three */ + for (; i < 60; ) { + FF2(a,b,c,d,e,i++); + FF2(e,a,b,c,d,i++); + FF2(d,e,a,b,c,i++); + FF2(c,d,e,a,b,i++); + FF2(b,c,d,e,a,i++); + } + + /* round four */ + for (; i < 80; ) { + FF3(a,b,c,d,e,i++); + FF3(e,a,b,c,d,i++); + FF3(d,e,a,b,c,i++); + FF3(c,d,e,a,b,i++); + FF3(b,c,d,e,a,i++); + } +#endif + +#undef FF0 +#undef FF1 +#undef FF2 +#undef FF3 + + /* store */ + state->state[0] = state->state[0] + a; + state->state[1] = state->state[1] + b; + state->state[2] = state->state[2] + c; + state->state[3] = state->state[3] + d; + state->state[4] = state->state[4] + e; + + return CRYPT_OK; +} + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int sha1_init(SHA1State *state) +{ + state->state[0] = 0x67452301UL; + state->state[1] = 0xefcdab89UL; + state->state[2] = 0x98badcfeUL; + state->state[3] = 0x10325476UL; + state->state[4] = 0xc3d2e1f0UL; + state->curlen = 0; + state->length = 0; + return CRYPT_OK; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ +// HASH_PROCESS(sha1_process, s_sha1_compress, sha1, 64) +int sha1_process(SHA1State *state, const unsigned char *in, unsigned long inlen) +{ + unsigned long n; + int err; + int block_size = 64; + if(state->curlen > sizeof(state->buf)) + { + return 0; // CRYPT_INVALID_ARG + } + if(((state->length + inlen * 8) < state->length) || ((inlen * 8) < inlen)) + { + return 0; // CRYPT_HASH_OVERFLOW + } + while(inlen > 0) + { + if(state->curlen == 0 && inlen >= block_size) + { + if ((err = s_sha1_compress(state, in)) != CRYPT_OK) + { + return err; + } + state->length += block_size * 8; + in += block_size; + inlen -= block_size; + } else { + n = MIN(inlen, (block_size - state->curlen)); + MemoryCopy(state->buf + state->curlen, in, (size_t)n); + state->curlen += n; + in += n; + inlen -= n; + if(state->curlen == block_size) + { + if((err = s_sha1_compress(state, state->buf)) != CRYPT_OK) + { + return err; + } + state->length += 8*block_size; + state->curlen = 0; + } + } + } + return CRYPT_OK; +} + + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (20 bytes) + @return CRYPT_OK if successful +*/ +int sha1_done(SHA1State *state, unsigned char *out) +{ + int i; + + if (state->curlen >= sizeof(state->buf)) { + return 0; // CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + state->length += state->curlen * 8; + + /* append the '1' bit */ + state->buf[state->curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (state->curlen > 56) { + while (state->curlen < 64) { + state->buf[state->curlen++] = (unsigned char)0; + } + s_sha1_compress(state, state->buf); + state->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (state->curlen < 56) { + state->buf[state->curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(state->length, state->buf+56); + s_sha1_compress(state, state->buf); + + /* copy output */ + for (i = 0; i < 5; i++) { + STORE32H(state->state[i], out+(4*i)); + } + return CRYPT_OK; +} + +#undef F0 +#undef F1 +#undef F2 +#undef F3 +#undef FF0 +#undef FF1 +#undef FF2 +#undef FF3 + +#endif // TOMCRYPT_HASH_H From 569481c7799161a68498aee35ac443aebcbef3d4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 17:29:59 -0700 Subject: [PATCH 029/133] plug in debugger-side checksum computation & comparison --- src/raddbg/raddbg_views.c | 170 +++++++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 3 deletions(-) diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 4d80c187..92f20e13 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2010,6 +2010,90 @@ RD_VIEW_UI_FUNCTION_DEF(null) {} //////////////////////////////// //~ rjf: text @view_hook_impl +internal AC_Artifact +rd_md5_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) +{ + AC_Artifact result = {0}; + { + Access *access = access_open(); + U128 hash = {0}; + str8_deserial_read_struct(key, 0, &hash); + String8 data = c_data_from_hash(access, hash); + MD5 md5 = md5_from_data(data); + StaticAssert(sizeof(result) >= sizeof(md5), artifact_size_check); + MemoryCopy(&result, &md5, Min(sizeof(result), sizeof(md5))); + access_close(access); + } + return result; +} + +internal AC_Artifact +rd_sha1_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) +{ + AC_Artifact result = {0}; + { + Access *access = access_open(); + U128 hash = {0}; + str8_deserial_read_struct(key, 0, &hash); + String8 data = c_data_from_hash(access, hash); + SHA1 sha1 = sha1_from_data(data); + StaticAssert(sizeof(result) >= sizeof(sha1), artifact_size_check); + MemoryCopy(&result, &sha1, Min(sizeof(result), sizeof(sha1))); + access_close(access); + } + return result; +} + +internal AC_Artifact +rd_sha256_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) +{ + AC_Artifact result = {0}; + { + Access *access = access_open(); + U128 hash = {0}; + str8_deserial_read_struct(key, 0, &hash); + String8 data = c_data_from_hash(access, hash); + SHA1 sha256 = sha1_from_data(data); + StaticAssert(sizeof(result) >= sizeof(sha256), artifact_size_check); + MemoryCopy(&result, &sha256, Min(sizeof(result), sizeof(sha256))); + access_close(access); + } + return result; +} + +internal MD5 +rd_md5_from_hash(U128 hash) +{ + Access *access = access_open(); + AC_Artifact artifact = ac_artifact_from_key(access, str8_struct(&hash), rd_md5_artifact_create, 0, 0); + MD5 md5 = {0}; + MemoryCopy(&md5, &artifact, Min(sizeof(md5), sizeof(artifact))); + access_close(access); + return md5; +} + +internal SHA1 +rd_sha1_from_hash(U128 hash) +{ + Access *access = access_open(); + AC_Artifact artifact = ac_artifact_from_key(access, str8_struct(&hash), rd_sha1_artifact_create, 0, 0); + SHA1 sha1 = {0}; + MemoryCopy(&sha1, &artifact, Min(sizeof(sha1), sizeof(artifact))); + access_close(access); + return sha1; +} + +internal SHA256 +rd_sha256_from_hash(U128 hash) +{ + Access *access = access_open(); + AC_Artifact artifact = ac_artifact_from_key(access, str8_struct(&hash), rd_sha256_artifact_create, 0, 0); + SHA256 sha256 = {0}; + MemoryCopy(&sha256, &artifact, Min(sizeof(sha256), sizeof(artifact))); + access_close(access); + return sha256; +} + EV_EXPAND_RULE_INFO_FUNCTION_DEF(text) { EV_ExpandInfo info = {0}; @@ -2175,23 +2259,103 @@ RD_VIEW_UI_FUNCTION_DEF(text) B32 file_is_out_of_date = 0; String8 out_of_date_dbgi_name = {0}; { + Temp scratch = scratch_begin(0, 0); + + // rjf: gather file overrides + String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, rd_regs()->file_path); + + // rjf: determine checksum in relevant debug infos + RDI_ChecksumKind checksum_kind = RDI_ChecksumKind_NULL; + String8 checksum_expected = {0}; + for(DI_KeyNode *n = dbgi_keys.first; n != 0 && checksum_kind == RDI_ChecksumKind_NULL; n = n->next) + { + Access *access = access_open(); + + // rjf: unpack RDI + DI_Key key = n->v; + RDI_Parsed *rdi = di_rdi_from_key(access, key, 0, 0); + + // rjf: file_path_normalized * rdi -> src_id + for EachNode(override_n, String8Node, overrides.first) + { + String8 file_path = override_n->string; + String8 file_path_normalized = lower_from_str8(scratch.arena, path_normalized_from_string(scratch.arena, file_path)); + B32 good_src_id = 0; + U32 src_id = 0; + if(rdi != &rdi_parsed_nil) + { + RDI_NameMap *mapptr = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_NormalSourcePaths); + RDI_ParsedNameMap map = {0}; + rdi_parsed_from_name_map(rdi, mapptr, &map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, file_path_normalized.str, file_path_normalized.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); + if(id_count > 0) + { + U32 src_id = ids[0]; + RDI_SourceFile *src = rdi_element_from_name_idx(rdi, SourceFiles, src_id); + checksum_kind = src->checksum_kind; + RDI_SectionKind checksum_section_kind = rdi_section_kind_from_checksum_kind(checksum_kind); + U64 checksum_size = rdi_section_element_size_table[checksum_section_kind]; + U8 *checksum_data = rdi_section_raw_element_from_kind_idx(rdi, checksum_section_kind, src->checksum_idx); + checksum_expected = str8_copy(scratch.arena, str8(checksum_data, checksum_size)); + break; + } + } + } + } + + access_close(access); + } + + // rjf: if we got a checksum, compute it locally - check if they match. + switch(checksum_kind) + { + default:{}break; + case RDI_ChecksumKind_MD5: + { + MD5 md5 = rd_md5_from_hash(hash); + String8 md5_string = str8_struct(&md5); + file_is_out_of_date = !str8_match(md5_string, checksum_expected, 0); + }break; + case RDI_ChecksumKind_SHA1: + { + SHA1 sha1 = rd_sha1_from_hash(hash); + String8 sha1_string = str8_struct(&sha1); + file_is_out_of_date = !str8_match(sha1_string, checksum_expected, 0); + }break; + case RDI_ChecksumKind_SHA256: + { + SHA256 sha256 = rd_sha256_from_hash(hash); + String8 sha256_string = str8_struct(&sha256); + file_is_out_of_date = !str8_match(sha256_string, checksum_expected, 0); + }break; + } + + // TODO(rjf): turn this back on once done... + file_is_out_of_date = 0; + + scratch_end(scratch); + + // TODO(rjf): @dbgi2 +#if 0 U64 file_timestamp = os_properties_from_file_path(rd_regs()->file_path).modified; if(file_timestamp != 0) { for(DI_KeyNode *n = dbgi_keys.first; n != 0; n = n->next) { DI_Key key = n->v; - // TODO(rjf): @dbgi2 -#if 0 if(key.min_timestamp < file_timestamp && key.min_timestamp != 0 && key.path.size != 0) { file_is_out_of_date = 1; out_of_date_dbgi_name = str8_skip_last_slash(key.path); break; } -#endif } } +#endif } ////////////////////////////// From da74b8595ce5d09c713be0facb107298ad77d1ec Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 30 Sep 2025 16:28:18 -0700 Subject: [PATCH 030/133] add operand count for expression opcodes --- src/dwarf/dwarf.c | 15 ++ src/dwarf/dwarf.h | 358 +++++++++++++++++++++++----------------------- 2 files changed, 195 insertions(+), 178 deletions(-) diff --git a/src/dwarf/dwarf.c b/src/dwarf/dwarf.c index 47a555e2..5e8eb10d 100644 --- a/src/dwarf/dwarf.c +++ b/src/dwarf/dwarf.c @@ -386,6 +386,21 @@ dw_pick_default_lower_bound(DW_Language lang) return lower_bound; } +internal U64 +dw_operand_count_from_expr_op(DW_ExprOp op) +{ + switch (op) { +#define X(_N, _ID, _OPER_COUNT) case _ID: return _OPER_COUNT; + DW_Expr_V3_XList(X) + DW_Expr_V4_XList(X) + DW_Expr_V5_XList(X) + DW_Expr_GNU_XList(X) +#undef X + default: { NotImplemented; } break; + } + return 0; +} + //////////////////////////////// //~ rjf: String <=> Enum diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index afc167a3..85c8f4c3 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -1392,193 +1392,193 @@ enum // Expression Opcodes #define DW_Expr_V3_XList(X) \ -X(Null, 0x00) \ -X(Addr, 0x03) \ -X(Deref, 0x06) \ -X(Const1U, 0x08) \ -X(Const1S, 0x09) \ -X(Const2U, 0x0a) \ -X(Const2S, 0x0b) \ -X(Const4U, 0x0c) \ -X(Const4S, 0x0d) \ -X(Const8U, 0x0e) \ -X(Const8S, 0x0f) \ -X(ConstU, 0x10) \ -X(ConstS, 0x11) \ -X(Dup, 0x12) \ -X(Drop, 0x13) \ -X(Over, 0x14) \ -X(Pick, 0x15) \ -X(Swap, 0x16) \ -X(Rot, 0x17) \ -X(XDeref, 0x18) \ -X(Abs, 0x19) \ -X(And, 0x1a) \ -X(Div, 0x1b) \ -X(Minus, 0x1c) \ -X(Mod, 0x1d) \ -X(Mul, 0x1e) \ -X(Neg, 0x1f) \ -X(Not, 0x20) \ -X(Or, 0x21) \ -X(Plus, 0x22) \ -X(PlusUConst, 0x23) \ -X(Shl, 0x24) \ -X(Shr, 0x25) \ -X(Shra, 0x26) \ -X(Xor, 0x27) \ -X(Skip, 0x2f) \ -X(Bra, 0x28) \ -X(Eq, 0x29) \ -X(Ge, 0x2a) \ -X(Gt, 0x2b) \ -X(Le, 0x2c) \ -X(Lt, 0x2d) \ -X(Ne, 0x2e) \ -X(Lit0, 0x30) \ -X(Lit1, 0x31) \ -X(Lit2, 0x32) \ -X(Lit3, 0x33) \ -X(Lit4, 0x34) \ -X(Lit5, 0x35) \ -X(Lit6, 0x36) \ -X(Lit7, 0x37) \ -X(Lit8, 0x38) \ -X(Lit9, 0x39) \ -X(Lit10, 0x3a) \ -X(Lit11, 0x3b) \ -X(Lit12, 0x3c) \ -X(Lit13, 0x3d) \ -X(Lit14, 0x3e) \ -X(Lit15, 0x3f) \ -X(Lit16, 0x40) \ -X(Lit17, 0x41) \ -X(Lit18, 0x42) \ -X(Lit19, 0x43) \ -X(Lit20, 0x44) \ -X(Lit21, 0x45) \ -X(Lit22, 0x46) \ -X(Lit23, 0x47) \ -X(Lit24, 0x48) \ -X(Lit25, 0x49) \ -X(Lit26, 0x4a) \ -X(Lit27, 0x4b) \ -X(Lit28, 0x4c) \ -X(Lit29, 0x4d) \ -X(Lit30, 0x4e) \ -X(Lit31, 0x4f) \ -X(Reg0, 0x50) \ -X(Reg1, 0x51) \ -X(Reg2, 0x52) \ -X(Reg3, 0x53) \ -X(Reg4, 0x54) \ -X(Reg5, 0x55) \ -X(Reg6, 0x56) \ -X(Reg7, 0x57) \ -X(Reg8, 0x58) \ -X(Reg9, 0x59) \ -X(Reg10, 0x5a) \ -X(Reg11, 0x5b) \ -X(Reg12, 0x5c) \ -X(Reg13, 0x5d) \ -X(Reg14, 0x5e) \ -X(Reg15, 0x5f) \ -X(Reg16, 0x60) \ -X(Reg17, 0x61) \ -X(Reg18, 0x62) \ -X(Reg19, 0x63) \ -X(Reg20, 0x64) \ -X(Reg21, 0x65) \ -X(Reg22, 0x66) \ -X(Reg23, 0x67) \ -X(Reg24, 0x68) \ -X(Reg25, 0x69) \ -X(Reg26, 0x6a) \ -X(Reg27, 0x6b) \ -X(Reg28, 0x6c) \ -X(Reg29, 0x6d) \ -X(Reg30, 0x6e) \ -X(Reg31, 0x6f) \ -X(BReg0, 0x70) \ -X(BReg1, 0x71) \ -X(BReg2, 0x72) \ -X(BReg3, 0x73) \ -X(BReg4, 0x74) \ -X(BReg5, 0x75) \ -X(BReg6, 0x76) \ -X(BReg7, 0x77) \ -X(BReg8, 0x78) \ -X(BReg9, 0x79) \ -X(BReg10, 0x7a) \ -X(BReg11, 0x7b) \ -X(BReg12, 0x7c) \ -X(BReg13, 0x7d) \ -X(BReg14, 0x7e) \ -X(BReg15, 0x7f) \ -X(BReg16, 0x80) \ -X(BReg17, 0x81) \ -X(BReg18, 0x82) \ -X(BReg19, 0x83) \ -X(BReg20, 0x84) \ -X(BReg21, 0x85) \ -X(BReg22, 0x86) \ -X(BReg23, 0x87) \ -X(BReg24, 0x88) \ -X(BReg25, 0x89) \ -X(BReg26, 0x8a) \ -X(BReg27, 0x8b) \ -X(BReg28, 0x8c) \ -X(BReg29, 0x8d) \ -X(BReg30, 0x8e) \ -X(BReg31, 0x8f) \ -X(RegX, 0x90) \ -X(FBReg, 0x91) \ -X(BRegX, 0x92) \ -X(Piece, 0x93) \ -X(DerefSize, 0x94) \ -X(XDerefSize, 0x95) \ -X(Nop, 0x96) \ -X(PushObjectAddress, 0x97) \ -X(Call2, 0x98) \ -X(Call4, 0x99) \ -X(CallRef, 0x9a) \ -X(FormTlsAddress, 0x9b) \ -X(CallFrameCfa, 0x9c) \ -X(BitPiece, 0x9d) +X(Null, 0x00, 0) \ +X(Addr, 0x03, 1) \ +X(Deref, 0x06, 0) \ +X(Const1U, 0x08, 1) \ +X(Const1S, 0x09, 1) \ +X(Const2U, 0x0a, 1) \ +X(Const2S, 0x0b, 1) \ +X(Const4U, 0x0c, 1) \ +X(Const4S, 0x0d, 1) \ +X(Const8U, 0x0e, 1) \ +X(Const8S, 0x0f, 1) \ +X(ConstU, 0x10, 1) \ +X(ConstS, 0x11, 1) \ +X(Dup, 0x12, 0) \ +X(Drop, 0x13, 0) \ +X(Over, 0x14, 0) \ +X(Pick, 0x15, 1) \ +X(Swap, 0x16, 0) \ +X(Rot, 0x17, 0) \ +X(XDeref, 0x18, 0) \ +X(Abs, 0x19, 0) \ +X(And, 0x1a, 0) \ +X(Div, 0x1b, 0) \ +X(Minus, 0x1c, 0) \ +X(Mod, 0x1d, 0) \ +X(Mul, 0x1e, 0) \ +X(Neg, 0x1f, 0) \ +X(Not, 0x20, 0) \ +X(Or, 0x21, 0) \ +X(Plus, 0x22, 0) \ +X(PlusUConst, 0x23, 1) \ +X(Shl, 0x24, 0) \ +X(Shr, 0x25, 0) \ +X(Shra, 0x26, 0) \ +X(Xor, 0x27, 0) \ +X(Bra, 0x28, 1) \ +X(Eq, 0x29, 0) \ +X(Ge, 0x2a, 0) \ +X(Gt, 0x2b, 0) \ +X(Le, 0x2c, 0) \ +X(Lt, 0x2d, 0) \ +X(Ne, 0x2e, 0) \ +X(Skip, 0x2f, 1) \ +X(Lit0, 0x30, 0) \ +X(Lit1, 0x31, 0) \ +X(Lit2, 0x32, 0) \ +X(Lit3, 0x33, 0) \ +X(Lit4, 0x34, 0) \ +X(Lit5, 0x35, 0) \ +X(Lit6, 0x36, 0) \ +X(Lit7, 0x37, 0) \ +X(Lit8, 0x38, 0) \ +X(Lit9, 0x39, 0) \ +X(Lit10, 0x3a, 0) \ +X(Lit11, 0x3b, 0) \ +X(Lit12, 0x3c, 0) \ +X(Lit13, 0x3d, 0) \ +X(Lit14, 0x3e, 0) \ +X(Lit15, 0x3f, 0) \ +X(Lit16, 0x40, 0) \ +X(Lit17, 0x41, 0) \ +X(Lit18, 0x42, 0) \ +X(Lit19, 0x43, 0) \ +X(Lit20, 0x44, 0) \ +X(Lit21, 0x45, 0) \ +X(Lit22, 0x46, 0) \ +X(Lit23, 0x47, 0) \ +X(Lit24, 0x48, 0) \ +X(Lit25, 0x49, 0) \ +X(Lit26, 0x4a, 0) \ +X(Lit27, 0x4b, 0) \ +X(Lit28, 0x4c, 0) \ +X(Lit29, 0x4d, 0) \ +X(Lit30, 0x4e, 0) \ +X(Lit31, 0x4f, 0) \ +X(Reg0, 0x50, 0) \ +X(Reg1, 0x51, 0) \ +X(Reg2, 0x52, 0) \ +X(Reg3, 0x53, 0) \ +X(Reg4, 0x54, 0) \ +X(Reg5, 0x55, 0) \ +X(Reg6, 0x56, 0) \ +X(Reg7, 0x57, 0) \ +X(Reg8, 0x58, 0) \ +X(Reg9, 0x59, 0) \ +X(Reg10, 0x5a, 0) \ +X(Reg11, 0x5b, 0) \ +X(Reg12, 0x5c, 0) \ +X(Reg13, 0x5d, 0) \ +X(Reg14, 0x5e, 0) \ +X(Reg15, 0x5f, 0) \ +X(Reg16, 0x60, 0) \ +X(Reg17, 0x61, 0) \ +X(Reg18, 0x62, 0) \ +X(Reg19, 0x63, 0) \ +X(Reg20, 0x64, 0) \ +X(Reg21, 0x65, 0) \ +X(Reg22, 0x66, 0) \ +X(Reg23, 0x67, 0) \ +X(Reg24, 0x68, 0) \ +X(Reg25, 0x69, 0) \ +X(Reg26, 0x6a, 0) \ +X(Reg27, 0x6b, 0) \ +X(Reg28, 0x6c, 0) \ +X(Reg29, 0x6d, 0) \ +X(Reg30, 0x6e, 0) \ +X(Reg31, 0x6f, 0) \ +X(BReg0, 0x70, 1) \ +X(BReg1, 0x71, 1) \ +X(BReg2, 0x72, 1) \ +X(BReg3, 0x73, 1) \ +X(BReg4, 0x74, 1) \ +X(BReg5, 0x75, 1) \ +X(BReg6, 0x76, 1) \ +X(BReg7, 0x77, 1) \ +X(BReg8, 0x78, 1) \ +X(BReg9, 0x79, 1) \ +X(BReg10, 0x7a, 1) \ +X(BReg11, 0x7b, 1) \ +X(BReg12, 0x7c, 1) \ +X(BReg13, 0x7d, 1) \ +X(BReg14, 0x7e, 1) \ +X(BReg15, 0x7f, 1) \ +X(BReg16, 0x80, 1) \ +X(BReg17, 0x81, 1) \ +X(BReg18, 0x82, 1) \ +X(BReg19, 0x83, 1) \ +X(BReg20, 0x84, 1) \ +X(BReg21, 0x85, 1) \ +X(BReg22, 0x86, 1) \ +X(BReg23, 0x87, 1) \ +X(BReg24, 0x88, 1) \ +X(BReg25, 0x89, 1) \ +X(BReg26, 0x8a, 1) \ +X(BReg27, 0x8b, 1) \ +X(BReg28, 0x8c, 1) \ +X(BReg29, 0x8d, 1) \ +X(BReg30, 0x8e, 1) \ +X(BReg31, 0x8f, 1) \ +X(RegX, 0x90, 1) \ +X(FBReg, 0x91, 1) \ +X(BRegX, 0x92, 2) \ +X(Piece, 0x93, 1) \ +X(DerefSize, 0x94, 1) \ +X(XDerefSize, 0x95, 1) \ +X(Nop, 0x96, 0) \ +X(PushObjectAddress, 0x97, 0) \ +X(Call2, 0x98, 1) \ +X(Call4, 0x99, 1) \ +X(CallRef, 0x9a, 1) \ +X(FormTlsAddress, 0x9b, 0) \ +X(CallFrameCfa, 0x9c, 0) \ +X(BitPiece, 0x9d, 2) #define DW_Expr_V4_XList(X) \ -X(ImplicitValue, 0x9e) \ -X(StackValue, 0x9f) +X(ImplicitValue, 0x9e, 2) \ +X(StackValue, 0x9f, 0) #define DW_Expr_V5_XList(X) \ -X(ImplicitPointer, 0xa0) \ -X(Addrx, 0xa1) \ -X(Constx, 0xa2) \ -X(EntryValue, 0xa3) \ -X(ConstType, 0xa4) \ -X(RegvalType, 0xa5) \ -X(DerefType, 0xa6) \ -X(XderefType, 0xa7) \ -X(Convert, 0xa8) \ -X(ReInterpret, 0xa9) +X(ImplicitPointer, 0xa0, 2) \ +X(Addrx, 0xa1, 1) \ +X(Constx, 0xa2, 1) \ +X(EntryValue, 0xa3, 2) \ +X(ConstType, 0xa4, 3) \ +X(RegvalType, 0xa5, 2) \ +X(DerefType, 0xa6, 2) \ +X(XDerefType, 0xa7, 2) \ +X(Convert, 0xa8, 1) \ +X(ReInterpret, 0xa9, 1) -#define DW_Expr_GNU_XList(X) \ -X(GNU_PushTlsAddress, 0xe0) \ -X(GNU_UnInit, 0xf0) \ -X(GNU_ImplicitPointer, 0xf2) \ -X(GNU_EntryValue, 0xf3) \ -X(GNU_ConstType, 0xf4) \ -X(GNU_RegvalType, 0xf5) \ -X(GNU_DerefType, 0xf6) \ -X(GNU_Convert, 0xf7) \ -X(GNU_ParameterRef, 0xfa) \ -X(GNU_AddrIndex, 0xfb) \ -X(GNU_ConstIndex, 0xfc) +#define DW_Expr_GNU_XList(X) \ +X(GNU_PushTlsAddress, 0xe0, 0) \ +X(GNU_UnInit, 0xf0, 0) \ +X(GNU_ImplicitPointer, 0xf2, 2) \ +X(GNU_EntryValue, 0xf3, 2) \ +X(GNU_ConstType, 0xf4, 3) \ +X(GNU_RegvalType, 0xf5, 2) \ +X(GNU_DerefType, 0xf6, 2) \ +X(GNU_Convert, 0xf7, 1) \ +X(GNU_ParameterRef, 0xfa, 1) \ +X(GNU_AddrIndex, 0xfb, 0) \ +X(GNU_ConstIndex, 0xfc, 1) typedef U64 DW_ExprOp; typedef enum DW_ExprOpEnum { -#define X(_N, _ID) DW_ExprOp_##_N = _ID, +#define X(_N, _ID, _OPER_COUNT) DW_ExprOp_##_N = _ID, DW_Expr_V3_XList(X) DW_Expr_V4_XList(X) DW_Expr_V5_XList(X) @@ -1779,6 +1779,8 @@ internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, B internal U64 dw_pick_default_lower_bound(DW_Language lang); +internal U64 dw_operand_count_from_expr_op(DW_ExprOp op); + //////////////////////////////// //~ rjf: String <=> Enum From 0e9739f96429044272f4b7c1b9f4eaddeb5229fe Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 30 Sep 2025 16:29:19 -0700 Subject: [PATCH 031/133] expression parser --- src/dwarf/dwarf_parse.c | 211 ++++++++++++++++++++++++++++++++++++++++ src/dwarf/dwarf_parse.h | 61 ++++++++---- 2 files changed, 251 insertions(+), 21 deletions(-) diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index 09e6a6a9..a963145d 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -3112,3 +3112,214 @@ dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Input *input, DW_Sect return names_table; } +internal DW_Expr +dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data) +{ + DW_Expr expr = {0}; + for (U64 cursor = 0; cursor < data.size; ) { + U64 inst_start = cursor; + + DW_ExprOp opcode = 0; + cursor += str8_deserial_read_struct(data, cursor, &opcode); + + DW_ExprOperand operands[4] = {0}; + switch (opcode) { + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { + // implicit operands + } break; + case DW_ExprOp_Const1U: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8); } break; + case DW_ExprOp_Const2U: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].u16); } break; + case DW_ExprOp_Const4U: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].u32); } break; + case DW_ExprOp_Const8U: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].u64); } break; + case DW_ExprOp_Const1S: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].s8); } break; + case DW_ExprOp_Const2S: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].s16); } break; + case DW_ExprOp_Const4S: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].s32); } break; + case DW_ExprOp_Const8S: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].s64); } break; + case DW_ExprOp_ConstU: { cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); } break; + case DW_ExprOp_ConstS: { cursor += str8_deserial_read_sleb128(data, cursor, &operands[0].s64); } break; + case DW_ExprOp_Addr: { cursor += str8_deserial_read(data, cursor, &operands[0].u64, addr_size, addr_size); } break; + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { + // implicit operands + } break; + case DW_ExprOp_RegX: { cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); } break; + case DW_ExprOp_ImplicitValue: { + U64 value_size = 0; String8 value = {0}; + cursor += str8_deserial_read_uleb128(data, cursor, &value_size); + cursor += str8_deserial_read_block(data, cursor, value_size, &operands[0].block); + } break; + case DW_ExprOp_Piece: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + } break; + case DW_ExprOp_BitPiece: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + cursor += str8_deserial_read_uleb128(data, cursor, &operands[1].u64); + } break; + case DW_ExprOp_Pick: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8); + } break; + case DW_ExprOp_PlusUConst: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + } break; + case DW_ExprOp_Skip: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].s16); + } break; + case DW_ExprOp_Bra: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].s16); + } break; + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { + cursor += str8_deserial_read_sleb128(data, cursor, &operands[0].s64); + } break; + case DW_ExprOp_BRegX: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + cursor += str8_deserial_read_sleb128(data, cursor, &operands[1].s64); + } break; + case DW_ExprOp_FBReg: { + cursor += str8_deserial_read_sleb128(data, cursor, &operands[0].s64); + } break; + case DW_ExprOp_Deref: { + // no operands + } break; + case DW_ExprOp_DerefSize: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8); + } break; + case DW_ExprOp_XDerefSize: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8); + } break; + case DW_ExprOp_Call2: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].u16); + } break; + case DW_ExprOp_Call4: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].u32); + } break; + case DW_ExprOp_CallRef: { + cursor += str8_deserial_read_dwarf_uint(data, cursor, format, &operands[0].u64); + } break; + case DW_ExprOp_ImplicitPointer: + case DW_ExprOp_GNU_ImplicitPointer: { + cursor += str8_deserial_read_dwarf_uint(data, cursor, format, &operands[0].u64); + cursor += str8_deserial_read_sleb128(data, cursor, &operands[1].s64); + } break; + case DW_ExprOp_Convert: + case DW_ExprOp_GNU_Convert: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + } break; + case DW_ExprOp_GNU_ParameterRef: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].u32); + } break; + case DW_ExprOp_DerefType: + case DW_ExprOp_GNU_DerefType: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8); + cursor += str8_deserial_read_uleb128(data, cursor, &operands[1].u64); + } break; + case DW_ExprOp_XDerefType: { + cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8); + cursor += str8_deserial_read_uleb128(data, cursor, &operands[1].u64); + } break; + case DW_ExprOp_ConstType: + case DW_ExprOp_GNU_ConstType: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + cursor += str8_deserial_read_struct(data, cursor, &operands[1].u8); + cursor += str8_deserial_read_block(data, cursor, operands[1].u8, &operands[2].block); + } break; + case DW_ExprOp_RegvalType: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + cursor += str8_deserial_read_uleb128(data, cursor, &operands[1].u64); + } break; + case DW_ExprOp_EntryValue: + case DW_ExprOp_GNU_EntryValue: { + U64 entry_value_expr_size = 0; + cursor += str8_deserial_read_uleb128(data, cursor, &entry_value_expr_size); + cursor += str8_deserial_read_block(data, cursor, entry_value_expr_size, &operands[0].block); + } break; + case DW_ExprOp_Addrx: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + } break; + case DW_ExprOp_Constx: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + } break; + case DW_ExprOp_CallFrameCfa: + case DW_ExprOp_FormTlsAddress: + case DW_ExprOp_PushObjectAddress: + case DW_ExprOp_Nop: + case DW_ExprOp_Eq: + case DW_ExprOp_Ge: + case DW_ExprOp_Gt: + case DW_ExprOp_Le: + case DW_ExprOp_Lt: + case DW_ExprOp_Ne: + case DW_ExprOp_Shl: + case DW_ExprOp_Shr: + case DW_ExprOp_Shra: + case DW_ExprOp_Xor: + case DW_ExprOp_XDeref: + case DW_ExprOp_Abs: + case DW_ExprOp_And: + case DW_ExprOp_Div: + case DW_ExprOp_Minus: + case DW_ExprOp_Mod: + case DW_ExprOp_Mul: + case DW_ExprOp_Neg: + case DW_ExprOp_Not: + case DW_ExprOp_Or: + case DW_ExprOp_Plus: + case DW_ExprOp_Rot: + case DW_ExprOp_Swap: + case DW_ExprOp_Dup: + case DW_ExprOp_Drop: + case DW_ExprOp_Over: + case DW_ExprOp_StackValue: + case DW_ExprOp_GNU_PushTlsAddress: { + // no operands + } break; + case DW_ExprOp_GNU_AddrIndex: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + } break; + case DW_ExprOp_GNU_ConstIndex: { + cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); + } break; + default: { InvalidPath; } break; + } + + U64 operand_count = dw_operand_count_from_expr_op(opcode); + DW_ExprInst *inst = push_array(arena, DW_ExprInst, 1); + inst->opcode = opcode; + inst->size = cursor - inst_start; + inst->operands = push_array(arena, DW_ExprOperand, operand_count); + MemoryCopy(inst->operands, operands, operand_count * sizeof(DW_ExprOperand)); + + DLLPushBack(expr.first, expr.last, inst); + expr.count += 1; + } + return expr; +} + diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index fe98b90e..bb453c6e 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -319,6 +319,40 @@ typedef struct DW_Reference U64 info_off; } DW_Reference; +//////////////////////////////// +//~ Expression + +typedef union DW_ExprOperand +{ + U8 u8; + U16 u16; + U32 u32; + U64 u64; + + S8 s8; + S16 s16; + S32 s32; + S64 s64; + + String8 block; +} DW_ExprOperand; + +typedef struct DW_ExprInst +{ + DW_ExprOp opcode; + DW_ExprOperand *operands; + U64 size; + struct DW_ExprInst *next; + struct DW_ExprInst *prev; +} DW_ExprInst; + +typedef struct DW_Expr +{ + U64 count; + DW_ExprInst *first; + DW_ExprInst *last; +} DW_Expr; + // hasher internal U64 dw_hash_from_string(String8 string); @@ -417,27 +451,8 @@ internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off); // line info -internal U64 dw_read_line_file(String8 line_data, - U64 line_off, - DW_Input *input, - DW_Version unit_version, - DW_Format unit_format, - DW_Ext ext, - U64 address_size, - DW_ListUnit *str_offsets, - U64 enc_count, - U64 *enc_arr, - DW_LineFile *line_file_out); -internal U64 dw_read_line_vm_header(Arena *arena, - String8 line_data, - U64 line_off, - DW_Input *input, - String8 cu_dir, - String8 cu_name, - U8 cu_address_size, - DW_ListUnit *cu_str_offsets, - DW_LineVMHeader *header_out); - +internal U64 dw_read_line_file(String8 line_data, U64 line_off, DW_Input *input, DW_Version unit_version, DW_Format unit_format, DW_Ext ext, U64 address_size, DW_ListUnit *str_offsets, U64 enc_count, U64 *enc_arr, DW_LineFile *line_file_out); +internal U64 dw_read_line_vm_header(Arena *arena, String8 line_data, U64 line_off, DW_Input *input, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out); internal void dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt); internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_inst_len, U64 max_ops_for_inst); internal DW_LineSeqNode * dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl); @@ -451,4 +466,8 @@ internal DW_LineTableParseResult dw_parsed_line_table_from_data(Arena *arena, St internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Input *input, DW_SectionKind section_kind); +// expression + +internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data); + #endif // DWARF_PARSE_H From 0f9df9bc40cb51f7a6b8d94e83134ccbd37f2e4e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 30 Sep 2025 16:36:35 -0700 Subject: [PATCH 032/133] change opcode type to U8 --- src/dwarf/dwarf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index 85c8f4c3..0ed2d6b2 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -1575,7 +1575,7 @@ X(GNU_ParameterRef, 0xfa, 1) \ X(GNU_AddrIndex, 0xfb, 0) \ X(GNU_ConstIndex, 0xfc, 1) -typedef U64 DW_ExprOp; +typedef U8 DW_ExprOp; typedef enum DW_ExprOpEnum { #define X(_N, _ID, _OPER_COUNT) DW_ExprOp_##_N = _ID, From 48c7e45535b37f804c4cdb8e390430460a0ba474 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 30 Sep 2025 17:14:59 -0700 Subject: [PATCH 033/133] helper for determining if bytecode has dependency on TLS --- src/lib_rdi_make/rdi_make.c | 19 ++++++++++++++++++- src/lib_rdi_make/rdi_make.h | 3 ++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 25fc7f63..19cf6a31 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -941,7 +941,7 @@ rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkList *dst, RDIM_ //- rjf: bytecode -RDI_PROC void +RDI_PROC RDIM_EvalBytecodeOp * rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p) { RDI_U16 ctrlbits = rdi_eval_op_ctrlbits_table[op]; @@ -955,6 +955,8 @@ rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp RDIM_SLLQueuePush(bytecode->first_op, bytecode->last_op, node); bytecode->op_count += 1; bytecode->encoded_size += 1 + p_size; + + return node; } RDI_PROC void @@ -1022,6 +1024,21 @@ rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *ri } } +RDI_PROC B32 +rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bytecode) +{ + B32 result = 0; + for(RDIM_EvalBytecodeOp *n = bytecode.first_op; n != 0; n = n->next) + { + if(n->op == RDI_EvalOp_TLSOff) + { + result = 1; + break; + } + } + return result; +} + //- rjf: locations RDI_PROC RDI_U64 diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index cab8df40..015bb7c3 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1648,10 +1648,11 @@ RDI_PROC void rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkLi //~ rjf: [Building] Location Info Building //- rjf: bytecode -RDI_PROC void rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p); +RDI_PROC RDIM_EvalBytecodeOp * rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p); RDI_PROC void rdim_bytecode_push_uconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_U64 x); RDI_PROC void rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S64 x); RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed); +RDI_PROC B32 rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bytecode); //- rjf: locations RDI_PROC RDI_U64 rdim_encoded_size_from_location_info(RDIM_LocationInfo *info); From 954633bba2d71c8c745989292b3f1669ecc7f02b Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 2 Oct 2025 18:01:49 -0700 Subject: [PATCH 034/133] add opcode for swapping top two values on the stack --- src/eval/eval_interpret.c | 6 ++++++ src/lib_rdi/rdi.c | 3 ++- src/lib_rdi/rdi.h | 6 ++++-- src/rdi/rdi.mdesk | 3 ++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index 4bc92189..38850f8c 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -841,6 +841,12 @@ e_interpret(String8 bytecode) case 8:{nval.u64 = bswap_u64(svals[0].u64);}break; } }break; + + case RDI_EvalOp_Swap: + { + // TODO: add support for pushing multiple values onto the stack + NotImplemented; + }break; } // rjf: push diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index dc297153..943411a9 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -58,7 +58,7 @@ sizeof(RDI_NameMapNode), sizeof(RDI_U8), }; -RDI_U16 rdi_eval_op_ctrlbits_table[52] = +RDI_U16 rdi_eval_op_ctrlbits_table[53] = { RDI_EVAL_CTRLBITS(0, 0, 0), RDI_EVAL_CTRLBITS(0, 0, 0), @@ -111,6 +111,7 @@ RDI_EVAL_CTRLBITS(1, 1, 1), RDI_EVAL_CTRLBITS(4, 0, 0), RDI_EVAL_CTRLBITS(4, 0, 0), RDI_EVAL_CTRLBITS(8, 0, 0), +RDI_EVAL_CTRLBITS(0, 2, 2), RDI_EVAL_CTRLBITS(0, 0, 0), }; diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index 4d052bce..44da5f21 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -523,7 +523,8 @@ RDI_EvalOp_ByteSwap = 47, RDI_EvalOp_CallSiteValue = 48, RDI_EvalOp_PartialValue = 49, RDI_EvalOp_PartialValueBit = 50, -RDI_EvalOp_COUNT = 51, +RDI_EvalOp_Swap = 51, +RDI_EvalOp_COUNT = 52, } RDI_EvalOpEnum; typedef RDI_U8 RDI_EvalTypeGroup; @@ -1122,6 +1123,7 @@ X(ByteSwap)\ X(CallSiteValue)\ X(PartialValue)\ X(PartialValueBit)\ +X(Swap)\ #define RDI_EvalTypeGroup_XList \ X(Other)\ @@ -1623,6 +1625,6 @@ RDI_PROC RDI_S32 rdi_eval_op_typegroup_are_compatible(RDI_EvalOp op, RDI_EvalTyp RDI_PROC RDI_U8 *rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RDI_U64 *size_out); extern RDI_U16 rdi_section_element_size_table[44]; -extern RDI_U16 rdi_eval_op_ctrlbits_table[52]; +extern RDI_U16 rdi_eval_op_ctrlbits_table[53]; #endif // RDI_H diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index d106d98d..6bbcfb95 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -1349,7 +1349,8 @@ RDI_EvalOpTable: {CallSiteValue 48 4 0 0} {PartialValue 49 4 0 0} {PartialValueBit 50 8 0 0} - {COUNT 51 0 0 0} + {Swap 51 0 2 2} // swaps the top two entries on the stack + {COUNT 52 0 0 0} } // NOTE(rjf): "ck" -> "conversion kind, when converted to type group", used in square matrix form From 1264115d13817d832a10fb8b9af679ae9d55d2c4 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 2 Oct 2025 17:07:38 -0700 Subject: [PATCH 035/133] define push and pop counts for expression opcodes --- src/dwarf/dwarf.c | 32 +++- src/dwarf/dwarf.h | 369 +++++++++++++++++++++++----------------------- 2 files changed, 216 insertions(+), 185 deletions(-) diff --git a/src/dwarf/dwarf.c b/src/dwarf/dwarf.c index 5e8eb10d..3b946ae1 100644 --- a/src/dwarf/dwarf.c +++ b/src/dwarf/dwarf.c @@ -390,7 +390,37 @@ internal U64 dw_operand_count_from_expr_op(DW_ExprOp op) { switch (op) { -#define X(_N, _ID, _OPER_COUNT) case _ID: return _OPER_COUNT; +#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT) case _ID: return _OPER_COUNT; + DW_Expr_V3_XList(X) + DW_Expr_V4_XList(X) + DW_Expr_V5_XList(X) + DW_Expr_GNU_XList(X) +#undef X + default: { NotImplemented; } break; + } + return 0; +} + +internal U64 +dw_pop_count_from_expr_op(DW_ExprOp op) +{ + switch (op) { +#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT) case _ID: return _POP_COUNT; + DW_Expr_V3_XList(X) + DW_Expr_V4_XList(X) + DW_Expr_V5_XList(X) + DW_Expr_GNU_XList(X) +#undef X + default: { NotImplemented; } break; + } + return 0; +} + +internal U64 +dw_push_count_from_expr_op(DW_ExprOp op) +{ + switch (op) { +#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT) case _ID: return _PUSH_COUNT; DW_Expr_V3_XList(X) DW_Expr_V4_XList(X) DW_Expr_V5_XList(X) diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index 0ed2d6b2..7a6b4b47 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -1391,198 +1391,199 @@ enum //////////////////////////////// // Expression Opcodes -#define DW_Expr_V3_XList(X) \ -X(Null, 0x00, 0) \ -X(Addr, 0x03, 1) \ -X(Deref, 0x06, 0) \ -X(Const1U, 0x08, 1) \ -X(Const1S, 0x09, 1) \ -X(Const2U, 0x0a, 1) \ -X(Const2S, 0x0b, 1) \ -X(Const4U, 0x0c, 1) \ -X(Const4S, 0x0d, 1) \ -X(Const8U, 0x0e, 1) \ -X(Const8S, 0x0f, 1) \ -X(ConstU, 0x10, 1) \ -X(ConstS, 0x11, 1) \ -X(Dup, 0x12, 0) \ -X(Drop, 0x13, 0) \ -X(Over, 0x14, 0) \ -X(Pick, 0x15, 1) \ -X(Swap, 0x16, 0) \ -X(Rot, 0x17, 0) \ -X(XDeref, 0x18, 0) \ -X(Abs, 0x19, 0) \ -X(And, 0x1a, 0) \ -X(Div, 0x1b, 0) \ -X(Minus, 0x1c, 0) \ -X(Mod, 0x1d, 0) \ -X(Mul, 0x1e, 0) \ -X(Neg, 0x1f, 0) \ -X(Not, 0x20, 0) \ -X(Or, 0x21, 0) \ -X(Plus, 0x22, 0) \ -X(PlusUConst, 0x23, 1) \ -X(Shl, 0x24, 0) \ -X(Shr, 0x25, 0) \ -X(Shra, 0x26, 0) \ -X(Xor, 0x27, 0) \ -X(Bra, 0x28, 1) \ -X(Eq, 0x29, 0) \ -X(Ge, 0x2a, 0) \ -X(Gt, 0x2b, 0) \ -X(Le, 0x2c, 0) \ -X(Lt, 0x2d, 0) \ -X(Ne, 0x2e, 0) \ -X(Skip, 0x2f, 1) \ -X(Lit0, 0x30, 0) \ -X(Lit1, 0x31, 0) \ -X(Lit2, 0x32, 0) \ -X(Lit3, 0x33, 0) \ -X(Lit4, 0x34, 0) \ -X(Lit5, 0x35, 0) \ -X(Lit6, 0x36, 0) \ -X(Lit7, 0x37, 0) \ -X(Lit8, 0x38, 0) \ -X(Lit9, 0x39, 0) \ -X(Lit10, 0x3a, 0) \ -X(Lit11, 0x3b, 0) \ -X(Lit12, 0x3c, 0) \ -X(Lit13, 0x3d, 0) \ -X(Lit14, 0x3e, 0) \ -X(Lit15, 0x3f, 0) \ -X(Lit16, 0x40, 0) \ -X(Lit17, 0x41, 0) \ -X(Lit18, 0x42, 0) \ -X(Lit19, 0x43, 0) \ -X(Lit20, 0x44, 0) \ -X(Lit21, 0x45, 0) \ -X(Lit22, 0x46, 0) \ -X(Lit23, 0x47, 0) \ -X(Lit24, 0x48, 0) \ -X(Lit25, 0x49, 0) \ -X(Lit26, 0x4a, 0) \ -X(Lit27, 0x4b, 0) \ -X(Lit28, 0x4c, 0) \ -X(Lit29, 0x4d, 0) \ -X(Lit30, 0x4e, 0) \ -X(Lit31, 0x4f, 0) \ -X(Reg0, 0x50, 0) \ -X(Reg1, 0x51, 0) \ -X(Reg2, 0x52, 0) \ -X(Reg3, 0x53, 0) \ -X(Reg4, 0x54, 0) \ -X(Reg5, 0x55, 0) \ -X(Reg6, 0x56, 0) \ -X(Reg7, 0x57, 0) \ -X(Reg8, 0x58, 0) \ -X(Reg9, 0x59, 0) \ -X(Reg10, 0x5a, 0) \ -X(Reg11, 0x5b, 0) \ -X(Reg12, 0x5c, 0) \ -X(Reg13, 0x5d, 0) \ -X(Reg14, 0x5e, 0) \ -X(Reg15, 0x5f, 0) \ -X(Reg16, 0x60, 0) \ -X(Reg17, 0x61, 0) \ -X(Reg18, 0x62, 0) \ -X(Reg19, 0x63, 0) \ -X(Reg20, 0x64, 0) \ -X(Reg21, 0x65, 0) \ -X(Reg22, 0x66, 0) \ -X(Reg23, 0x67, 0) \ -X(Reg24, 0x68, 0) \ -X(Reg25, 0x69, 0) \ -X(Reg26, 0x6a, 0) \ -X(Reg27, 0x6b, 0) \ -X(Reg28, 0x6c, 0) \ -X(Reg29, 0x6d, 0) \ -X(Reg30, 0x6e, 0) \ -X(Reg31, 0x6f, 0) \ -X(BReg0, 0x70, 1) \ -X(BReg1, 0x71, 1) \ -X(BReg2, 0x72, 1) \ -X(BReg3, 0x73, 1) \ -X(BReg4, 0x74, 1) \ -X(BReg5, 0x75, 1) \ -X(BReg6, 0x76, 1) \ -X(BReg7, 0x77, 1) \ -X(BReg8, 0x78, 1) \ -X(BReg9, 0x79, 1) \ -X(BReg10, 0x7a, 1) \ -X(BReg11, 0x7b, 1) \ -X(BReg12, 0x7c, 1) \ -X(BReg13, 0x7d, 1) \ -X(BReg14, 0x7e, 1) \ -X(BReg15, 0x7f, 1) \ -X(BReg16, 0x80, 1) \ -X(BReg17, 0x81, 1) \ -X(BReg18, 0x82, 1) \ -X(BReg19, 0x83, 1) \ -X(BReg20, 0x84, 1) \ -X(BReg21, 0x85, 1) \ -X(BReg22, 0x86, 1) \ -X(BReg23, 0x87, 1) \ -X(BReg24, 0x88, 1) \ -X(BReg25, 0x89, 1) \ -X(BReg26, 0x8a, 1) \ -X(BReg27, 0x8b, 1) \ -X(BReg28, 0x8c, 1) \ -X(BReg29, 0x8d, 1) \ -X(BReg30, 0x8e, 1) \ -X(BReg31, 0x8f, 1) \ -X(RegX, 0x90, 1) \ -X(FBReg, 0x91, 1) \ -X(BRegX, 0x92, 2) \ -X(Piece, 0x93, 1) \ -X(DerefSize, 0x94, 1) \ -X(XDerefSize, 0x95, 1) \ -X(Nop, 0x96, 0) \ -X(PushObjectAddress, 0x97, 0) \ -X(Call2, 0x98, 1) \ -X(Call4, 0x99, 1) \ -X(CallRef, 0x9a, 1) \ -X(FormTlsAddress, 0x9b, 0) \ -X(CallFrameCfa, 0x9c, 0) \ -X(BitPiece, 0x9d, 2) +// (opcode name, opcode id, operand count, pop count, push count) +#define DW_Expr_V3_XList(X) \ +X(Null, 0x00, 0, 0, 0) \ +X(Addr, 0x03, 1, 0, 1) \ +X(Deref, 0x06, 0, 1, 1) \ +X(Const1U, 0x08, 1, 0, 1) \ +X(Const1S, 0x09, 1, 0, 1) \ +X(Const2U, 0x0a, 1, 0, 1) \ +X(Const2S, 0x0b, 1, 0, 1) \ +X(Const4U, 0x0c, 1, 0, 1) \ +X(Const4S, 0x0d, 1, 0, 1) \ +X(Const8U, 0x0e, 1, 0, 1) \ +X(Const8S, 0x0f, 1, 0, 1) \ +X(ConstU, 0x10, 1, 0, 1) \ +X(ConstS, 0x11, 1, 0, 1) \ +X(Dup, 0x12, 0, 0, 1) \ +X(Drop, 0x13, 0, 1, 0) \ +X(Over, 0x14, 0, 0, 1) \ +X(Pick, 0x15, 1, 0, 1) \ +X(Swap, 0x16, 0, 0, 0) \ +X(Rot, 0x17, 0, 0, 0) \ +X(XDeref, 0x18, 0, 2, 1) \ +X(Abs, 0x19, 0, 1, 1) \ +X(And, 0x1a, 0, 2, 1) \ +X(Div, 0x1b, 0, 2, 1) \ +X(Minus, 0x1c, 0, 2, 1) \ +X(Mod, 0x1d, 0, 2, 1) \ +X(Mul, 0x1e, 0, 2, 1) \ +X(Neg, 0x1f, 0, 1, 1) \ +X(Not, 0x20, 0, 1, 1) \ +X(Or, 0x21, 0, 2, 1) \ +X(Plus, 0x22, 0, 2, 1) \ +X(PlusUConst, 0x23, 1, 1, 1) \ +X(Shl, 0x24, 0, 2, 1) \ +X(Shr, 0x25, 0, 2, 1) \ +X(Shra, 0x26, 0, 2, 1) \ +X(Xor, 0x27, 0, 2, 1) \ +X(Bra, 0x28, 1, 1, 0) \ +X(Eq, 0x29, 0, 2, 1) \ +X(Ge, 0x2a, 0, 2, 1) \ +X(Gt, 0x2b, 0, 2, 1) \ +X(Le, 0x2c, 0, 2, 1) \ +X(Lt, 0x2d, 0, 2, 1) \ +X(Ne, 0x2e, 0, 2, 1) \ +X(Skip, 0x2f, 1, 0, 0) \ +X(Lit0, 0x30, 0, 0, 0) \ +X(Lit1, 0x31, 0, 0, 0) \ +X(Lit2, 0x32, 0, 0, 0) \ +X(Lit3, 0x33, 0, 0, 0) \ +X(Lit4, 0x34, 0, 0, 0) \ +X(Lit5, 0x35, 0, 0, 0) \ +X(Lit6, 0x36, 0, 0, 0) \ +X(Lit7, 0x37, 0, 0, 0) \ +X(Lit8, 0x38, 0, 0, 0) \ +X(Lit9, 0x39, 0, 0, 0) \ +X(Lit10, 0x3a, 0, 0, 0) \ +X(Lit11, 0x3b, 0, 0, 0) \ +X(Lit12, 0x3c, 0, 0, 0) \ +X(Lit13, 0x3d, 0, 0, 0) \ +X(Lit14, 0x3e, 0, 0, 0) \ +X(Lit15, 0x3f, 0, 0, 0) \ +X(Lit16, 0x40, 0, 0, 0) \ +X(Lit17, 0x41, 0, 0, 0) \ +X(Lit18, 0x42, 0, 0, 0) \ +X(Lit19, 0x43, 0, 0, 0) \ +X(Lit20, 0x44, 0, 0, 0) \ +X(Lit21, 0x45, 0, 0, 0) \ +X(Lit22, 0x46, 0, 0, 0) \ +X(Lit23, 0x47, 0, 0, 0) \ +X(Lit24, 0x48, 0, 0, 0) \ +X(Lit25, 0x49, 0, 0, 0) \ +X(Lit26, 0x4a, 0, 0, 0) \ +X(Lit27, 0x4b, 0, 0, 0) \ +X(Lit28, 0x4c, 0, 0, 0) \ +X(Lit29, 0x4d, 0, 0, 0) \ +X(Lit30, 0x4e, 0, 0, 0) \ +X(Lit31, 0x4f, 0, 0, 0) \ +X(Reg0, 0x50, 0, 0, 1) \ +X(Reg1, 0x51, 0, 0, 1) \ +X(Reg2, 0x52, 0, 0, 1) \ +X(Reg3, 0x53, 0, 0, 1) \ +X(Reg4, 0x54, 0, 0, 1) \ +X(Reg5, 0x55, 0, 0, 1) \ +X(Reg6, 0x56, 0, 0, 1) \ +X(Reg7, 0x57, 0, 0, 1) \ +X(Reg8, 0x58, 0, 0, 1) \ +X(Reg9, 0x59, 0, 0, 1) \ +X(Reg10, 0x5a, 0, 0, 1) \ +X(Reg11, 0x5b, 0, 0, 1) \ +X(Reg12, 0x5c, 0, 0, 1) \ +X(Reg13, 0x5d, 0, 0, 1) \ +X(Reg14, 0x5e, 0, 0, 1) \ +X(Reg15, 0x5f, 0, 0, 1) \ +X(Reg16, 0x60, 0, 0, 1) \ +X(Reg17, 0x61, 0, 0, 1) \ +X(Reg18, 0x62, 0, 0, 1) \ +X(Reg19, 0x63, 0, 0, 1) \ +X(Reg20, 0x64, 0, 0, 1) \ +X(Reg21, 0x65, 0, 0, 1) \ +X(Reg22, 0x66, 0, 0, 1) \ +X(Reg23, 0x67, 0, 0, 1) \ +X(Reg24, 0x68, 0, 0, 1) \ +X(Reg25, 0x69, 0, 0, 1) \ +X(Reg26, 0x6a, 0, 0, 1) \ +X(Reg27, 0x6b, 0, 0, 1) \ +X(Reg28, 0x6c, 0, 0, 1) \ +X(Reg29, 0x6d, 0, 0, 1) \ +X(Reg30, 0x6e, 0, 0, 1) \ +X(Reg31, 0x6f, 0, 0, 1) \ +X(BReg0, 0x70, 1, 0, 1) \ +X(BReg1, 0x71, 1, 0, 1) \ +X(BReg2, 0x72, 1, 0, 1) \ +X(BReg3, 0x73, 1, 0, 1) \ +X(BReg4, 0x74, 1, 0, 1) \ +X(BReg5, 0x75, 1, 0, 1) \ +X(BReg6, 0x76, 1, 0, 1) \ +X(BReg7, 0x77, 1, 0, 1) \ +X(BReg8, 0x78, 1, 0, 1) \ +X(BReg9, 0x79, 1, 0, 1) \ +X(BReg10, 0x7a, 1, 0, 1) \ +X(BReg11, 0x7b, 1, 0, 1) \ +X(BReg12, 0x7c, 1, 0, 1) \ +X(BReg13, 0x7d, 1, 0, 1) \ +X(BReg14, 0x7e, 1, 0, 1) \ +X(BReg15, 0x7f, 1, 0, 1) \ +X(BReg16, 0x80, 1, 0, 1) \ +X(BReg17, 0x81, 1, 0, 1) \ +X(BReg18, 0x82, 1, 0, 1) \ +X(BReg19, 0x83, 1, 0, 1) \ +X(BReg20, 0x84, 1, 0, 1) \ +X(BReg21, 0x85, 1, 0, 1) \ +X(BReg22, 0x86, 1, 0, 1) \ +X(BReg23, 0x87, 1, 0, 1) \ +X(BReg24, 0x88, 1, 0, 1) \ +X(BReg25, 0x89, 1, 0, 1) \ +X(BReg26, 0x8a, 1, 0, 1) \ +X(BReg27, 0x8b, 1, 0, 1) \ +X(BReg28, 0x8c, 1, 0, 1) \ +X(BReg29, 0x8d, 1, 0, 1) \ +X(BReg30, 0x8e, 1, 0, 1) \ +X(BReg31, 0x8f, 1, 0, 1) \ +X(RegX, 0x90, 1, 0, 1) \ +X(FBReg, 0x91, 1, 0, 1) \ +X(BRegX, 0x92, 2, 0, 1) \ +X(Piece, 0x93, 1, 0, 0) \ +X(DerefSize, 0x94, 1, 1, 1) \ +X(XDerefSize, 0x95, 1, 2, 1) \ +X(Nop, 0x96, 0, 0, 0) \ +X(PushObjectAddress, 0x97, 0, 0, 1) \ +X(Call2, 0x98, 1, 0, 0) \ +X(Call4, 0x99, 1, 0, 0) \ +X(CallRef, 0x9a, 1, 0, 0) \ +X(FormTlsAddress, 0x9b, 0, 0, 1) \ +X(CallFrameCfa, 0x9c, 0, 0, 1) \ +X(BitPiece, 0x9d, 2, 0, 0) -#define DW_Expr_V4_XList(X) \ -X(ImplicitValue, 0x9e, 2) \ -X(StackValue, 0x9f, 0) +#define DW_Expr_V4_XList(X) \ +X(ImplicitValue, 0x9e, 2, 0, 1) \ +X(StackValue, 0x9f, 0, 0, 0) -#define DW_Expr_V5_XList(X) \ -X(ImplicitPointer, 0xa0, 2) \ -X(Addrx, 0xa1, 1) \ -X(Constx, 0xa2, 1) \ -X(EntryValue, 0xa3, 2) \ -X(ConstType, 0xa4, 3) \ -X(RegvalType, 0xa5, 2) \ -X(DerefType, 0xa6, 2) \ -X(XDerefType, 0xa7, 2) \ -X(Convert, 0xa8, 1) \ -X(ReInterpret, 0xa9, 1) +#define DW_Expr_V5_XList(X) \ +X(ImplicitPointer, 0xa0, 2, 0, 1) \ +X(Addrx, 0xa1, 1, 0, 1) \ +X(Constx, 0xa2, 1, 0, 1) \ +X(EntryValue, 0xa3, 2, 0, 0) \ +X(ConstType, 0xa4, 3, 0, 1) \ +X(RegvalType, 0xa5, 2, 0, 1) \ +X(DerefType, 0xa6, 2, 1, 1) \ +X(XDerefType, 0xa7, 2, 2, 1) \ +X(Convert, 0xa8, 1, 1, 1) \ +X(ReInterpret, 0xa9, 1, 1, 1) -#define DW_Expr_GNU_XList(X) \ -X(GNU_PushTlsAddress, 0xe0, 0) \ -X(GNU_UnInit, 0xf0, 0) \ -X(GNU_ImplicitPointer, 0xf2, 2) \ -X(GNU_EntryValue, 0xf3, 2) \ -X(GNU_ConstType, 0xf4, 3) \ -X(GNU_RegvalType, 0xf5, 2) \ -X(GNU_DerefType, 0xf6, 2) \ -X(GNU_Convert, 0xf7, 1) \ -X(GNU_ParameterRef, 0xfa, 1) \ -X(GNU_AddrIndex, 0xfb, 0) \ -X(GNU_ConstIndex, 0xfc, 1) +#define DW_Expr_GNU_XList(X) \ +X(GNU_PushTlsAddress, 0xe0, 0, 0, 1) \ +X(GNU_UnInit, 0xf0, 0, 0, 0) \ +X(GNU_ImplicitPointer, 0xf2, 2, 0, 1) \ +X(GNU_EntryValue, 0xf3, 2, 0, 0) \ +X(GNU_ConstType, 0xf4, 3, 0, 1) \ +X(GNU_RegvalType, 0xf5, 2, 0, 1) \ +X(GNU_DerefType, 0xf6, 2, 1, 1) \ +X(GNU_Convert, 0xf7, 1, 1, 1) \ +X(GNU_ParameterRef, 0xfa, 1, 0, 0) \ +X(GNU_AddrIndex, 0xfb, 0, 0, 1) \ +X(GNU_ConstIndex, 0xfc, 1, 0, 1) typedef U8 DW_ExprOp; typedef enum DW_ExprOpEnum { -#define X(_N, _ID, _OPER_COUNT) DW_ExprOp_##_N = _ID, +#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT) DW_ExprOp_##_N = _ID, DW_Expr_V3_XList(X) - DW_Expr_V4_XList(X) - DW_Expr_V5_XList(X) - DW_Expr_GNU_XList(X) + DW_Expr_V4_XList(X) + DW_Expr_V5_XList(X) + DW_Expr_GNU_XList(X) #undef X } DW_ExprOpEnum; From c7774c75823630f9ea844588c70723c8cda11d14 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 2 Oct 2025 17:08:29 -0700 Subject: [PATCH 036/133] helper for convert opcode --- src/lib_rdi_make/rdi_make.c | 6 ++++++ src/lib_rdi_make/rdi_make.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 19cf6a31..d4416425 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1004,6 +1004,12 @@ rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S6 } } +RDI_PROC void +rdim_bytecode_push_convert(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalTypeGroup in, RDI_EvalTypeGroup out) +{ + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_Convert, (U16)(in) | ((U16)(out) << 8)); +} + RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed) { diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 015bb7c3..470bb647 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1651,6 +1651,7 @@ RDI_PROC void rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkLi RDI_PROC RDIM_EvalBytecodeOp * rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p); RDI_PROC void rdim_bytecode_push_uconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_U64 x); RDI_PROC void rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S64 x); +RDI_PROC void rdim_bytecode_push_convert(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalTypeGroup in, RDI_EvalTypeGroup out); RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed); RDI_PROC B32 rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bytecode); From 1f9ce6e6baf085e98310f1cc6f0da4c8881d5513 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 2 Oct 2025 17:08:50 -0700 Subject: [PATCH 037/133] eval opcode stubs --- src/eval/eval_interpret.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index 38850f8c..e667a429 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -842,6 +842,21 @@ e_interpret(String8 bytecode) } }break; + case RDI_EvalOp_CallSiteValue: + { + NotImplemented; + }break; + + case RDI_EvalOp_PartialValue: + { + NotImplemented; + }break; + + case RDI_EvalOp_PartialValueBit: + { + NotImplemented; + }break; + case RDI_EvalOp_Swap: { // TODO: add support for pushing multiple values onto the stack From 4ba1ee6e06b45eee07cb278b12cb1c9fcfe749d7 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 2 Oct 2025 17:11:21 -0700 Subject: [PATCH 038/133] follow C type conversion rules in the expression transpiler --- src/rdi_from_dwarf/rdi_from_dwarf.c | 3261 ++++++++++++++++----------- src/rdi_from_dwarf/rdi_from_dwarf.h | 66 +- 2 files changed, 1951 insertions(+), 1376 deletions(-) diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index e1e279fa..89103aa1 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -8,7 +8,7 @@ // [ ] Error handling //////////////////////////////// - + static const U64 UNIT_CHUNK_CAP = 256; static const U64 UDT_CHUNK_CAP = 256; static const U64 TYPE_CHUNK_CAP = 256; @@ -35,30 +35,6 @@ RDIM_SymbolChunkList procs = {0}; RDIM_ScopeChunkList scopes = {0}; RDIM_InlineSiteChunkList inline_sites = {0}; -//////////////////////////////// - -internal B32 -rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc) -{ - B32 is_static = 1; - RDI_EvalOp dynamic_ops[] = { RDI_EvalOp_MemRead, RDI_EvalOp_RegRead, RDI_EvalOp_RegReadDyn, RDI_EvalOp_CFA }; - for EachNode (n, RDIM_EvalBytecodeOp, bc.first_op) { - for EachIndex(i, ArrayCount(dynamic_ops)) { - is_static = 0; - goto exit; - } - } - exit:; - return is_static; -} - -internal U64 -rdim_do_static_bytecode_eval(RDIM_EvalBytecode bc, U64 image_base) -{ - NotImplemented; - return 0; -} - //////////////////////////////// //~ rjf: Enum Conversion Helpers @@ -210,7 +186,7 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_HighPc); if (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) { U64 lo_pc = dw_address_from_attrib(input, cu, lo_pc_attrib); - + U64 hi_pc = 0; DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); if (hi_pc_class == DW_AttribClass_Address) { @@ -221,7 +197,7 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag } else { AssertAlways(!"unexpected attribute encoding"); } - + if (lo_pc >= image_base && hi_pc >= image_base) { if (lo_pc < hi_pc) { rng1u64_list_push(arena, &ranges, rng_1u64(lo_pc - image_base, hi_pc - image_base)); @@ -231,8 +207,8 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag } else { // invalid low and hi PC are likely are caused by an optimization pass during linking } - } else if ((lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) || - (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null)) { + } else if (lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null || + lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null) { // TODO: error handling } } @@ -273,74 +249,648 @@ d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input return params; } -internal RDI_TypeKind -d2r_unsigned_type_kind_from_size(U64 byte_size) +//////////////////////////////// + +internal B32 +rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bc) { - RDI_TypeKind result = RDI_TypeKind_NULL; - switch (byte_size) { - case 1: result = RDI_TypeKind_U8; break; - case 2: result = RDI_TypeKind_U16; break; - case 4: result = RDI_TypeKind_U32; break; - case 8: result = RDI_TypeKind_U64; break; + for EachNode(n, RDIM_EvalBytecodeOp, bc.first_op) { + if (n->op == RDI_EvalOp_TLSOff) { + return 1; + } } - return result; + return 0; } -internal RDI_TypeKind -d2r_signed_type_kind_from_size(U64 byte_size) +internal B32 +rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc) { - RDI_TypeKind result = RDI_TypeKind_NULL; - switch (byte_size) { - case 1: result = RDI_TypeKind_S8; break; - case 2: result = RDI_TypeKind_S16; break; - case 4: result = RDI_TypeKind_S32; break; - case 8: result = RDI_TypeKind_S64; break; + B32 is_static = 1; + RDI_EvalOp dynamic_ops[] = { RDI_EvalOp_MemRead, RDI_EvalOp_RegRead, RDI_EvalOp_RegReadDyn, RDI_EvalOp_CFA }; + for EachNode(n, RDIM_EvalBytecodeOp, bc.first_op) { + for EachIndex(i, ArrayCount(dynamic_ops)) { + if (dynamic_ops[i] == n->op) { + is_static = 0; + goto exit; + } + } } - return result; + exit:; + return is_static; } -internal RDI_EvalTypeGroup -d2r_type_group_from_type_kind(RDI_TypeKind x) +internal U64 +rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) { - switch (x) { - case RDI_TypeKind_NULL: - case RDI_TypeKind_Void: - case RDI_TypeKind_Handle: - break; - case RDI_TypeKind_UChar8: - case RDI_TypeKind_UChar16: - case RDI_TypeKind_UChar32: - case RDI_TypeKind_U8: - case RDI_TypeKind_U16: - case RDI_TypeKind_U32: - case RDI_TypeKind_U64: - case RDI_TypeKind_U128: - case RDI_TypeKind_U256: - case RDI_TypeKind_U512: - return RDI_EvalTypeGroup_U; - case RDI_TypeKind_Char8: - case RDI_TypeKind_Char16: - case RDI_TypeKind_Char32: - case RDI_TypeKind_S8: - case RDI_TypeKind_S16: - case RDI_TypeKind_S32: - case RDI_TypeKind_S64: - case RDI_TypeKind_S128: - case RDI_TypeKind_S256: - case RDI_TypeKind_S512: - return RDI_EvalTypeGroup_S; - case RDI_TypeKind_F32: - return RDI_EvalTypeGroup_F32; - case RDI_TypeKind_F64: - return RDI_EvalTypeGroup_F64; - default: InvalidPath; + Temp scratch = scratch_begin(0,0); + + typedef union { U16 u16; U32 u32; U64 u64; S64 s64; F32 f32; F64 f64; } Value; + U64 stack_cap = 128, stack_count = 0; + Value *stack = push_array(scratch.arena, Value, stack_cap); + + for EachNode(opcode_n, RDIM_EvalBytecodeOp, bc.first_op) { + // pop values from stack + Value *svals = 0; + { + U32 pop_count = RDI_POPN_FROM_CTRLBITS(rdi_eval_op_ctrlbits_table[opcode_n->op]); + if (pop_count > stack_count) { + // TODO: report error + Assert(!"malformed byte code"); + break; + } + stack_count -= pop_count; + svals = stack + stack_count; + } + + Value imm = { .u64 = opcode_n->p }; + Value nval = {0}; + switch (opcode_n->op) { + case RDI_EvalOp_Stop: { opcode_n = bc.last_op; } break; + case RDI_EvalOp_Noop: {} break; + case RDI_EvalOp_Cond: { NotImplemented; } break; + case RDI_EvalOp_Skip: { + NotImplemented; + } break; + case RDI_EvalOp_MemRead: { InvalidPath; } break; + case RDI_EvalOp_RegRead: { NotImplemented; } break; + case RDI_EvalOp_RegReadDyn: { NotImplemented; } break; + case RDI_EvalOp_FrameOff: { NotImplemented; } break; + case RDI_EvalOp_ModuleOff: { + nval.u64 = image_base + imm.u64; + } break; + case RDI_EvalOp_TLSOff: { + nval.u64 = image_base; + } break; + case RDI_EvalOp_ConstU8: + case RDI_EvalOp_ConstU16: + case RDI_EvalOp_ConstU32: + case RDI_EvalOp_ConstU64: + case RDI_EvalOp_ConstU128: { + nval = imm; + } break; + case RDI_EvalOp_ConstString: { NotImplemented; } break; + case RDI_EvalOp_Abs: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: + case RDI_EvalTypeGroup_S: { nval.s64 = abs_s64(svals[0].s64); } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = abs_f32(svals[0].f32); } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = abs_f64(svals[0].f64); } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Neg: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: + case RDI_EvalTypeGroup_S: { nval.u64 = ~svals[0].u64 + 1; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = -svals[0].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = -svals[0].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Add: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 + svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 + svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 + svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 + svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Sub: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 - svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[1].s64 - svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 - svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 - svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Mul: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 * svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 * svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 * svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 * svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Div: { + B32 is_div_by_zero = 0; + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { is_div_by_zero = svals[1].u64 == 0; } break; + case RDI_EvalTypeGroup_S: { is_div_by_zero = svals[1].s64 == 0; } break; + case RDI_EvalTypeGroup_F32: { is_div_by_zero = svals[1].f32 == 0.0f; } break; + case RDI_EvalTypeGroup_F64: { is_div_by_zero = svals[1].f64 == 0.0; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + + // TODO: report error + AssertAlways(!is_div_by_zero); + + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 / svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 / svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 / svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 / svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Mod: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 % svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 % svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 MOD is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 MOD is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_LShift: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 << svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 << svals[1].u64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 LShift is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 LShift is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_RShift: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 >> svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[1].s64 >> svals[1].u64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 RShift is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 RShift is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_BitAnd: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 | svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 | svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 bitwise AND is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 bitwise AND is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_BitXor: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 ^ svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 ^ svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 XOR is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 XOR is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_BitNot: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = ~svals[0].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = ~svals[0].u64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 bitwise NOT is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 bitwise NOT is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_LogAnd: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 && svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 && svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 AND is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 AND is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_LogOr: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 || svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 || svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 OR is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 OR is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_LogNot: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = !svals[0].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = !svals[0].u64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 NOT is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 NOT is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_EqEq: { + nval.u64 = !!MemoryMatch(&svals[0], &svals[1], sizeof(*svals)); + } break; + case RDI_EvalOp_NtEq: { + nval.u64 = !MemoryMatch(&svals[0], &svals[1], sizeof(*svals)); + } break; + case RDI_EvalOp_LsEq: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 <= svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 <= svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 <= svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 <= svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_GrEq: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 >= svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 >= svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 >= svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 >= svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Less: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 < svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 < svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 < svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 < svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Grtr: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 > svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 > svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 > svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 > svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Trunc: { + if (0 < imm.u64 && imm.u64 < 64) { + U64 mask = max_U64 >> (64 - imm.u64); + nval.u64 = svals[0].u64 & (max_U64 >> (64 - imm.u64)); + } else if (imm.u64 > 64) { + // TODO: report error + AssertAlways(!"malformed bytecode"); + } + } break; + case RDI_EvalOp_TruncSigned: { + if (0 < imm.u64 && imm.u64 < 64) { + U64 mask = max_U64 >> (64 - imm.u64); + nval.u64 = svals[0].u64 & (max_U64 >> (64 - imm.u64)); + U64 high = 0; + if (svals[0].u64 & (1 << (imm.u64 - 1))) { + high = ~mask; + } + nval.u64 = high | (svals[0].u64 & mask); + } else if (imm.u64 > 64) { + // TODO: report error + AssertAlways(!"malformed bytecode"); + } + } break; + case RDI_EvalOp_Convert: { + U32 in = imm.u64 & 0xff; + U32 out = (imm.u64 >> 8) & 0xff; + if (in != out) { + switch (in + out*RDI_EvalTypeGroup_COUNT) { + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f32; } break; + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f64; } break; + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f32; } break; + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f64; } break; + case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].u64; } break; + case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].s64; } break; + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].f64; } break; + case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].u64; } break; + case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].s64; } break; + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].f32; } break; + default: { Assert(!"unexpected conversion case"); } break; // report error + } + } + } break; + case RDI_EvalOp_Pick: { + if (stack_count > imm.u64) { + nval = stack[stack_count - imm.u64 - 1]; + } else { + // TODO: report error + AssertAlways(!"malformed bytecode"); + } + } break; + case RDI_EvalOp_Pop: {} break; + case RDI_EvalOp_Insert: { + if (stack_count > imm.u64) { + Value tval = stack[stack_count-1]; + Value *dst = stack + stack_count - 1 - imm.u64; + Value *shift = dst + 1; + MemoryCopy(shift, dst, imm.u64 * sizeof(Value)); + *dst = tval; + } else { + // TODO: report error + AssertAlways(!"malformed bytecode"); + } + } break; + case RDI_EvalOp_ValueRead: { + U64 bytes_to_read = imm.u64; + U64 offset = svals[0].u64; + if (offset + bytes_to_read <= sizeof(Value)) { + Value src_val = svals[1]; + MemoryCopy(&nval, (U8 *)&src_val + offset, bytes_to_read); + } + } break; + case RDI_EvalOp_ByteSwap: { + switch (imm.u64) { + case 0: {} break; + case 1: {} break; + case 2: { nval.u16 = bswap_u16(svals[0].u16); } break; + case 4: { nval.u32 = bswap_u16(svals[0].u32); } break; + case 8: { nval.u64 = bswap_u16(svals[0].u64); } break; + default: { AssertAlways(!"malformed bytecode"); } break; // TODO: report error + } + } break; + case RDI_EvalOp_Swap: { + NotImplemented; + } break; + default: { Assert(!"unknown op type"); } break; + } + + // push computed value to the stack + { + U64 push_count = RDI_PUSHN_FROM_CTRLBITS(rdi_eval_op_ctrlbits_table[opcode_n->op]); + if (push_count == 1) { + if (stack_count < stack_cap) { + stack[stack_count] = nval; + stack_count += 1; + } else { + AssertAlways(!"stack overflow"); // TODO: report error + } + } + } } - return RDI_EvalTypeGroup_Other; + + U64 result = 0; + if (stack_count >= 1) { + result = stack[0].u64 - image_base; + } + + scratch_end(scratch); + return result; } //////////////////////////////// //~ rjf: Bytecode Conversion Helpers +internal D2R_ValueTypeNode * +d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type) +{ + D2R_ValueTypeNode *n; + if (stack->free_list) { + n = stack->free_list; + SLLStackPop(stack->free_list); + } else { + n = push_array(arena, D2R_ValueTypeNode, 1); + } + n->type = type; + SLLStackPush(stack->top, n); + stack->count += 1; + return n; +} + +internal D2R_ValueType +d2r_value_type_stack_pop(D2R_ValueTypeStack *stack) +{ + D2R_ValueType result = D2R_ValueType_Generic; + if (stack->top) { + D2R_ValueTypeNode *n = stack->top; + result = n->type; + SLLStackPop(stack->top); + SLLStackPush(stack->free_list, n); + stack->count -= 1; + } + return result; +} + +internal D2R_ValueType +d2r_value_type_stack_peek(D2R_ValueTypeStack *stack) +{ + return stack->top ? stack->top->type : D2R_ValueType_Generic; +} + +internal D2R_ValueType +d2r_unsigned_value_type_from_bit_size(U64 bit_size) +{ + switch (bit_size) { + case 8: return D2R_ValueType_U8; + case 16: return D2R_ValueType_U16; + case 32: return D2R_ValueType_U32; + case 64: return D2R_ValueType_U64; + case 128: return D2R_ValueType_U128; + case 256: return D2R_ValueType_U256; + case 512: return D2R_ValueType_U512; + } + AssertAlways(!"no suitable unsigned type was found for the specified size"); + return D2R_ValueType_Generic; +} + +internal D2R_ValueType +d2r_signed_value_type_from_bit_size(U64 bit_size) +{ + switch (bit_size) { + case 8: return D2R_ValueType_S8; + case 16: return D2R_ValueType_S16; + case 32: return D2R_ValueType_S32; + case 64: return D2R_ValueType_S64; + case 128: return D2R_ValueType_S128; + case 256: return D2R_ValueType_S256; + case 512: return D2R_ValueType_S512; + } + AssertAlways(!"no suitable signed type was found for the specified size"); + return D2R_ValueType_Generic; +} + +internal D2R_ValueType +d2r_float_type_from_bit_size(U64 bit_size) +{ + switch (bit_size) { + case 4: return D2R_ValueType_F32; + case 8: return D2R_ValueType_F64; + } + AssertAlways(!"no suitable type was found for the specified size"); + return D2R_ValueType_Generic; +} + +internal RDI_EvalTypeGroup +d2r_value_type_to_rdi(D2R_ValueType v) +{ + switch (v) { + case D2R_ValueType_Generic: + return RDI_EvalTypeGroup_Other; + case D2R_ValueType_U8: + case D2R_ValueType_U16: + case D2R_ValueType_U32: + case D2R_ValueType_U64: + return RDI_EvalTypeGroup_U; + case D2R_ValueType_S8: + case D2R_ValueType_S16: + case D2R_ValueType_S32: + case D2R_ValueType_S64: + return RDI_EvalTypeGroup_S; + case D2R_ValueType_F32: + return RDI_EvalTypeGroup_F32; + case D2R_ValueType_F64: + return RDI_EvalTypeGroup_F64; + case D2R_ValueType_Address: + return RDI_EvalTypeGroup_U; + case D2R_ValueType_ImplicitValue: + AssertAlways(!"unable to convert value type to RDI equivalent"); + } + return RDI_EvalTypeGroup_Other; +} + +internal U64 +d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type) +{ + switch (value_type) { + case D2R_ValueType_Address: return addr_size; + case D2R_ValueType_U8: return 1; + case D2R_ValueType_U16: return 2; + case D2R_ValueType_U32: return 4; + case D2R_ValueType_U64: return 8; + case D2R_ValueType_U128: return 16; + case D2R_ValueType_U256: return 32; + case D2R_ValueType_U512: return 64; + case D2R_ValueType_S8: return 1; + case D2R_ValueType_S16: return 2; + case D2R_ValueType_S32: return 4; + case D2R_ValueType_S64: return 8; + case D2R_ValueType_S128: return 16; + case D2R_ValueType_S256: return 32; + case D2R_ValueType_S512: return 64; + case D2R_ValueType_F32: return 4; + case D2R_ValueType_F64: return 8; + default: return 0; + } +} + +internal D2R_ValueType +d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs) +{ + if (lhs == rhs) { + return lhs; + } + // unsigned vs unsigned + else if (D2R_ValueType_IsUnsigned(lhs) && D2R_ValueType_IsUnsigned(rhs)) { + return Max(lhs, rhs); + } + // signed vs signed + else if (D2R_ValueType_IsSigned(lhs) && D2R_ValueType_IsSigned(rhs)) { + return Max(lhs, rhs); + } + // (unsigned vs signed) || (signed vs unsigned) + else if (D2R_ValueType_IsUnsigned(lhs) && D2R_ValueType_IsSigned(rhs) || + D2R_ValueType_IsSigned(lhs) && D2R_ValueType_IsUnsigned(rhs)) { + U64 lhs_size = d2r_size_from_value_type(0, lhs); + U64 rhs_size = d2r_size_from_value_type(0, rhs); + if (lhs_size < rhs_size) { + return rhs; + } else if (lhs > rhs_size) { + return lhs; + } else { + return d2r_unsigned_value_type_from_bit_size(lhs_size * 8); + } + } + // float vs int + else if (D2R_ValueType_IsFloat(lhs) && D2R_ValueType_IsInt(rhs)) { + return lhs; + } + // int vs float + else if (D2R_ValueType_IsInt(lhs) && D2R_ValueType_IsFloat(rhs)) { + return rhs; + } + // float vs float + else if (D2R_ValueType_IsFloat(lhs) && D2R_ValueType_IsFloat(rhs)) { + return Max(lhs, rhs); + } + // address vs int + else if (lhs == D2R_ValueType_Address && D2R_ValueType_IsInt(rhs)) { + return D2R_ValueType_Address; + } + // int vs address + else if (D2R_ValueType_IsInt(lhs) && rhs == D2R_ValueType_Address) { + return D2R_ValueType_Address; + } + // address vs float + else if (lhs == D2R_ValueType_Address && D2R_ValueType_IsFloat(rhs)) { + return D2R_ValueType_Generic; + } + // float vs address + else if (D2R_ValueType_IsFloat(lhs) && rhs == D2R_ValueType_Address) { + return D2R_ValueType_Generic; + } + // no conversion for implicit value + else if (lhs == D2R_ValueType_ImplicitValue || rhs == D2R_ValueType_ImplicitValue) { + return D2R_ValueType_Generic; + } + AssertAlways(!"undefined conversion case"); + return D2R_ValueType_Generic; +} + +internal D2R_ValueType +d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc) +{ + D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); + if (rhs != common_type) { + rdim_bytecode_push_convert(arena, bc, d2r_value_type_to_rdi(rhs), d2r_value_type_to_rdi(common_type)); + } + if (lhs != common_type) { + rdim_bytecode_push_op(arena, bc, RDI_EvalOp_Swap, 0); + rdim_bytecode_push_convert(arena, bc, d2r_value_type_to_rdi(lhs), d2r_value_type_to_rdi(common_type)); + } + return common_type; +} + +internal void +d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op) +{ + D2R_ValueType rhs = d2r_value_type_stack_pop(stack); + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + D2R_ValueType common_type = d2r_apply_usual_arithmetic_conversions(arena, lhs, rhs, bc); + rdim_bytecode_push_op(arena, bc, op, d2r_value_type_to_rdi(common_type)); + d2r_value_type_stack_push(0, stack, common_type); +} + +internal void +d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op) +{ + D2R_ValueType rhs = d2r_value_type_stack_pop(stack); + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + D2R_ValueType common_type; + if (D2R_ValueType_IsInt(lhs) && rhs == D2R_ValueType_Address) { + rdim_bytecode_push_op(arena, bc, RDI_EvalOp_Swap, 0); + rdim_bytecode_push_convert(arena, bc, d2r_value_type_to_rdi(lhs), RDI_EvalTypeGroup_U); + rdim_bytecode_push_op(arena, bc, RDI_EvalOp_Swap, 0); + common_type = D2R_ValueType_Address; + } else if (lhs == D2R_ValueType_Address && D2R_ValueType_IsInt(rhs)) { + rdim_bytecode_push_convert(arena, bc, d2r_value_type_to_rdi(rhs), RDI_EvalTypeGroup_U); + common_type = D2R_ValueType_Address; + } else { + common_type = d2r_apply_usual_arithmetic_conversions(arena, lhs, rhs, bc); + } + rdim_bytecode_push_op(arena, bc, RDI_EvalOp_EqEq, d2r_value_type_to_rdi(common_type)); + d2r_value_type_stack_push(0, stack, D2R_ValueType_Bool); +} + internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, @@ -348,584 +898,542 @@ d2r_bytecode_from_expression(Arena *arena, U64 address_size, Arch arch, DW_ListUnit *addr_lu, - String8 expr, + String8 raw_expr, DW_CompUnit *cu, - B32 *is_addr_out) + D2R_ValueType *result_type_out) { Temp scratch = scratch_begin(&arena, 1); + Temp arena_restore_point = temp_begin(arena); RDIM_EvalBytecode bc = {0}; - *is_addr_out = 0; - - struct Frame { - struct Frame *next; - RDI_EvalTypeGroup value_type; - }; - struct Frame *stack = 0; -#define push_of_type(type) do { \ -struct Frame *f = push_array(scratch.arena, struct Frame, 1); \ -f->value_type = d2r_type_group_from_type_kind(type); \ -SLLStackPush(stack, f); \ -} while (0) -#define pop_type() stack->value_type; SLLStackPop(stack) -#define peek_type() stack->value_type - - - RDI_TypeKind addr_type_kind = RDI_TypeKind_NULL; - if (address_size == 4) { - addr_type_kind = RDI_TypeKind_U32; - } else if (address_size == 8) { - addr_type_kind = RDI_TypeKind_U64; - } - - - for (U64 cursor = 0; cursor < expr.size; ) { - U8 op = 0; - cursor += str8_deserial_read_struct(expr, cursor, &op); - - U64 size_param; - switch (op) { - case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: - case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: - case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: - case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: - case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: - case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: - case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: - case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: - case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: - case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: - case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { - U64 lit = op - DW_ExprOp_Lit0; - - rdim_bytecode_push_uconst(arena, &bc, lit); - push_of_type(RDI_TypeKind_U64); - } break; - - case DW_ExprOp_Const1U: { - U8 val = 0; - cursor += str8_deserial_read_struct(expr, cursor, &val); - - rdim_bytecode_push_uconst(arena, &bc, val); - push_of_type(RDI_TypeKind_U8); - } break; - case DW_ExprOp_Const2U: { - U16 val = 0; - cursor += str8_deserial_read_struct(expr, cursor, &val); - - rdim_bytecode_push_uconst(arena, &bc, val); - push_of_type(RDI_TypeKind_U16); - } break; - case DW_ExprOp_Const4U: { - U32 val = 0; - cursor += str8_deserial_read_struct(expr, cursor, &val); - - rdim_bytecode_push_uconst(arena, &bc, val); - push_of_type(RDI_TypeKind_U32); - } break; - case DW_ExprOp_Const8U: { - U64 val = 0; - cursor += str8_deserial_read_struct(expr, cursor, &val); - - rdim_bytecode_push_uconst(arena, &bc, val); - push_of_type(RDI_TypeKind_U64); - } break; - - case DW_ExprOp_Const1S: { - S8 val = 0; - cursor += str8_deserial_read_struct(expr, cursor, &val); - - rdim_bytecode_push_sconst(arena, &bc, val); - push_of_type(RDI_TypeKind_S8); - } break; - case DW_ExprOp_Const2S: { - S16 val = 0; - cursor += str8_deserial_read_struct(expr, cursor, &val); - - rdim_bytecode_push_sconst(arena, &bc, val); - push_of_type(RDI_TypeKind_S16); - } break; - case DW_ExprOp_Const4S: { - S32 val = 0; - cursor += str8_deserial_read_struct(expr, cursor, &val); - - rdim_bytecode_push_sconst(arena, &bc, val); - push_of_type(RDI_TypeKind_S32); - } break; - case DW_ExprOp_Const8S: { - S64 val = 0; - cursor += str8_deserial_read_struct(expr, cursor, &val); - - rdim_bytecode_push_sconst(arena, &bc, val); - push_of_type(RDI_TypeKind_S64); - } break; - - case DW_ExprOp_ConstU: { - U64 val = 0; - cursor += str8_deserial_read_uleb128(expr, cursor, &val); - - rdim_bytecode_push_uconst(arena, &bc, val); - push_of_type(RDI_TypeKind_U64); - } break; - - case DW_ExprOp_ConstS: { - S64 val = 0; - cursor += str8_deserial_read_sleb128(expr, cursor, &val); - - rdim_bytecode_push_sconst(arena, &bc, val); - push_of_type(RDI_TypeKind_S64); - } break; - - case DW_ExprOp_Addr: { - U64 addr = 0; - cursor += str8_deserial_read(expr, cursor, &addr, address_size, address_size); + DW_Expr expr = dw_expr_from_data(scratch.arena, cu->format, address_size, raw_expr); + D2R_ValueTypeStack *stack = push_array(scratch.arena, D2R_ValueTypeStack, 1); + RDIM_EvalBytecodeOp **converted_insts = push_array(scratch.arena, RDIM_EvalBytecodeOp *, expr.count); + B32 is_ok = 1; + U64 inst_idx = 0; + for EachNode(inst, DW_ExprInst, expr.first) { + RDIM_EvalBytecodeOp *last_op = bc.last_op; + + U64 pop_count = dw_pop_count_from_expr_op(inst->opcode); + if (pop_count > stack->count) { + // TODO: report error + Assert(!"not enough values on the stack to evaluate instruction"); + is_ok = 0; + break; + } + + switch (inst->opcode) { + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { + U64 lit = inst->opcode - DW_ExprOp_Lit0; + rdim_bytecode_push_uconst(arena, &bc, lit); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U8); + } break; + case DW_ExprOp_Const1U: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u8); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U8); + } break; + case DW_ExprOp_Const2U: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u16); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U16); + } break; + case DW_ExprOp_Const4U: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u32); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U32); + } break; + case DW_ExprOp_Const8U: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u32); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U64); + } break; + case DW_ExprOp_Const1S: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s8); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S8); + } break; + case DW_ExprOp_Const2S: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s16); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S16); + } break; + case DW_ExprOp_Const4S: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s32); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S32); + } break; + case DW_ExprOp_Const8S: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s64); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S64); + } break; + case DW_ExprOp_ConstU: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u64); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U64); + } break; + case DW_ExprOp_ConstS: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s64); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S64); + } break; + case DW_ExprOp_Addr: { + if (inst->operands[0].u64 >= image_base) { + U64 voff = inst->operands[0].u64 - image_base; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } else { + is_ok = 0; + } + } break; + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { + U64 reg_code_dw = inst->opcode - DW_ExprOp_Reg0; + U64 reg_size = dw_reg_size_from_code(arch, reg_code_dw); + U64 reg_pos = dw_reg_pos_from_code(arch, reg_code_dw); + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); + U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); + d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(reg_size)); + } break; + case DW_ExprOp_RegX: { + U64 reg_size = dw_reg_size_from_code(arch, inst->operands[0].u64); + U64 reg_pos = dw_reg_pos_from_code(arch, inst->operands[0].u64); + RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, inst->operands[0].u64); + U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); + d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(reg_size)); + } break; + case DW_ExprOp_ImplicitValue: { + if (inst->operands[0].block.size <= sizeof(U64)) { + U64 implicit_value; + MemoryCopyStr8(&implicit_value, inst->operands[0].block); + rdim_bytecode_push_uconst(arena, &bc, implicit_value); + d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(inst->operands[0].block.size * 8)); + } else { + // TODO: currenlty no way to encode string in RDIM_EvalBytecodeOp + NotImplemented; + } + } break; + case DW_ExprOp_Piece: { + U64 partial_value_size32 = safe_cast_u32(inst->operands[0].u64); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValue, partial_value_size32); + } break; + case DW_ExprOp_BitPiece: { + U32 piece_bit_size32 = safe_cast_u32(inst->operands[0].u64); + U32 piece_bit_off32 = safe_cast_u32(inst->operands[1].u64); + U64 partial_value = Compose64Bit(piece_bit_size32, piece_bit_off32); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValueBit, partial_value); + } break; + case DW_ExprOp_Pick: { + U64 idx = 0; + D2R_ValueTypeNode *n; + for (n = stack->top; n != 0 || idx == inst->operands[0].u64; n = n->next, idx += 1) { } + if (idx == inst->operands[0].u64) { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, inst->operands[0].u64); + d2r_value_type_stack_push(scratch.arena, stack, n->type); + } else { + // TODO: report error + AssertAlways(!"out of bounds pick"); + } + } break; + case DW_ExprOp_Over: { + if (stack->top && stack->top->next) { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 1); + d2r_value_type_stack_push(scratch.arena, stack, stack->top->next->type); + } else { + // TODO: report error + AssertAlways(!"out of bounds over"); + } + } break; + case DW_ExprOp_PlusUConst: { + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + D2R_ValueType common_type = d2r_pick_common_value_type(lhs, D2R_ValueType_U64); + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u64); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, d2r_value_type_to_rdi(common_type)); + d2r_value_type_stack_push(scratch.arena, stack, common_type); + } break; + case DW_ExprOp_Skip: { + B32 skip_fwd = inst->operands[0].s16 >= 0; + U16 delta = abs_s64(inst->operands[0].s16); + U16 cursor = 0; + U64 inst_count = 0; + for (DW_ExprInst *i = skip_fwd ? inst : inst->prev; i != 0 && cursor < delta; i = skip_fwd ? inst->next : inst->prev) { + cursor += inst->size; + inst_count += 1; + } + + // TODO: report error (skip does not land on first byte of an instruction) + AssertAlways(cursor == delta); + // TODO: report overflow + AssertAlways(inst_count <= min_S16); + AssertAlways(inst_idx <= max_U32); + + U64 imm = Compose64Bit(inst_idx, skip_fwd ? (S16)inst_count : -(S16)inst_count); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Skip, imm); + } break; + case DW_ExprOp_Bra: { + NotImplemented; + } break; + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { + U64 reg_code_dw = inst->opcode - DW_ExprOp_BReg0; + S64 reg_off = inst->operands[0].s64; + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, reg_code_rdi); + if (reg_off > 0) { + rdim_bytecode_push_sconst(arena, &bc, reg_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); + } + + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + case DW_ExprOp_BRegX: { + U64 reg_code_dw = inst->operands[0].u64; + S64 reg_off = inst->operands[1].s64; + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); + if (reg_off > 0) { + rdim_bytecode_push_sconst(arena, &bc, reg_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); + } + + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + case DW_ExprOp_FBReg: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, inst->operands[0].s64); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + case DW_ExprOp_Deref: { + D2R_ValueType address_type = d2r_value_type_stack_pop(stack); + if (address_type != D2R_ValueType_Address && !D2R_ValueType_IsInt(address_type)) { + // TODO: report error + Assert(!"value must be of integral type"); + break; + } + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, address_size); + d2r_value_type_stack_push(scratch.arena, stack, address_type); + } break; + case DW_ExprOp_DerefSize: { + D2R_ValueType address_type = d2r_value_type_stack_pop(stack); + if (!D2R_ValueType_IsInt(address_type) && address_type != D2R_ValueType_Address ) { + // TODO: report error + Assert(!"value must be of integral type"); + break; + } + U8 deref_size_in_bytes = inst->operands[0].u64; + if (0 < deref_size_in_bytes && deref_size_in_bytes <= address_size) { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, deref_size_in_bytes); + } else { + // TODO: error handling + AssertAlways(!"ill formed expression"); + } + d2r_value_type_stack_push(scratch.arena, stack, address_type); + } break; + case DW_ExprOp_XDeref: { + // TODO: error handling + AssertAlways(!"multiple address spaces are not supported"); + } break; + // TODO: error handling + case DW_ExprOp_XDerefSize: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_Call2: + case DW_ExprOp_Call4: + case DW_ExprOp_CallRef: { + // TODO: error handling + AssertAlways(!"calls are not supported"); + } break; + case DW_ExprOp_ImplicitPointer: + case DW_ExprOp_GNU_ImplicitPointer: { + // TODO: + AssertAlways(!"sample"); + } break; + case DW_ExprOp_Convert: + case DW_ExprOp_GNU_Convert: { + D2R_ValueType out = D2R_ValueType_Generic; + if (inst->operands[0].u64 == 0) { + // + // 2.5.1 + // Instead of a base type, elements can have a generic type, + // which is an integral type that has the size of an address + // on the target machine and unspecified signedness. + // + out = D2R_ValueType_Generic; + } else { + // find ref tag + DW_TagNode *tag_node = dw_tag_node_from_info_off(cu, inst->operands[0].u64); + DW_Tag tag = tag_node->tag; + if (tag.kind == DW_TagKind_BaseType) { + // extract encoding attribute + DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); + + // DW_ATE -> RDI_EvalTypeGroup + switch (encoding) { + case DW_ATE_Null: { + out = D2R_ValueType_Generic; + } break; + case DW_ATE_Address: { + out = D2R_ValueType_Address; + } break; + case DW_ATE_Boolean: { + out = D2R_ValueType_S8; + } break; + case DW_ATE_SignedChar: + case DW_ATE_Signed: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_signed_value_type_from_bit_size(byte_size * 8); + } break; + case DW_ATE_UnsignedChar: + case DW_ATE_Unsigned: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_unsigned_value_type_from_bit_size(byte_size * 8); + } break; + case DW_ATE_Float: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_float_type_from_bit_size(byte_size * 8); + } break; + default: InvalidPath; break; + } + } else { + AssertAlways(!"unexpected tag"); // TODO: error handling + } + } + + D2R_ValueType in = d2r_value_type_stack_pop(stack); + d2r_value_type_stack_push(scratch.arena, stack, out); + rdim_bytecode_push_convert(arena, &bc, d2r_value_type_to_rdi(in), d2r_value_type_to_rdi(out)); + } break; + // TODO: + case DW_ExprOp_GNU_ParameterRef: { AssertAlways(!"sample"); } break; + // TODO: + case DW_ExprOp_DerefType: + case DW_ExprOp_GNU_DerefType: { AssertAlways(!"sample"); } break; + // TODO: + case DW_ExprOp_ConstType: + case DW_ExprOp_GNU_ConstType: { AssertAlways(!"sample"); } break; + // TODO: + case DW_ExprOp_RegvalType: { AssertAlways(!"sample"); } break; + case DW_ExprOp_EntryValue: + case DW_ExprOp_GNU_EntryValue: { + D2R_ValueType call_site_result_type = 0; + RDIM_EvalBytecode call_site_bc = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, inst->operands[0].block, cu, &call_site_result_type); + + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_CallSiteValue, safe_cast_u32(call_site_bc.encoded_size)); + rdim_bytecode_concat_in_place(&bc, &call_site_bc); + + d2r_value_type_stack_push(scratch.arena, stack, call_site_result_type); + } break; + case DW_ExprOp_Addrx: { + U64 addr = dw_addr_from_list_unit(addr_lu, inst->operands[0].u64); + if (addr != max_U64) { if (addr >= image_base) { U64 voff = addr - image_base; rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); - push_of_type(addr_type_kind); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); } else { // TODO: error handling AssertAlways(!"unable to relocate address"); } - - *is_addr_out = 1; - } break; - - case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: - case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: - case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: - case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: - case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: - case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: - case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: - case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: - case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: - case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: - case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { - U64 reg_code_dw = op - DW_ExprOp_Reg0; - U64 reg_size = dw_reg_size_from_code(arch, reg_code_dw); - U64 reg_pos = dw_reg_pos_from_code(arch, reg_code_dw); - - RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); - U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); - push_of_type(d2r_unsigned_type_kind_from_size(reg_size)); - } break; - - case DW_ExprOp_RegX: { - U64 reg_code_dw = 0; - cursor += str8_deserial_read_uleb128(expr, cursor, ®_code_dw); - - U64 reg_size = dw_reg_size_from_code(arch, reg_code_dw); - U64 reg_pos = dw_reg_pos_from_code(arch, reg_code_dw); - - RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); - U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); - push_of_type(d2r_unsigned_type_kind_from_size(reg_size)); - - *is_addr_out = 1; - } break; - - case DW_ExprOp_ImplicitValue: { - U64 val_size = 0; - String8 val = {0}; - cursor += str8_deserial_read_uleb128(expr, cursor, &val_size); - cursor += str8_deserial_read_block(expr, cursor, val_size, &val); - if (val.size <= sizeof(U64)) { - U64 val64 = 0; - MemoryCopy(&val64, val.str, val.size); - - rdim_bytecode_push_uconst(arena, &bc, val64); - push_of_type(d2r_unsigned_type_kind_from_size(val_size)); - } else { - // TODO: currenlty no way to encode string in RDIM_EvalBytecodeOp - NotImplemented; - } - } break; - - case DW_ExprOp_Piece: { - U64 piece_byte_size = 0; - cursor += str8_deserial_read_uleb128(expr, cursor, &piece_byte_size); - - U64 partial_value_size32 = safe_cast_u32(piece_byte_size); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValue, partial_value_size32); - } break; - - case DW_ExprOp_BitPiece: { - U64 piece_bit_size = 0; - U64 piece_bit_off = 0; - cursor += str8_deserial_read_uleb128(expr, cursor, &piece_bit_size); - cursor += str8_deserial_read_uleb128(expr, cursor, &piece_bit_off); - - U32 piece_bit_size32 = safe_cast_u32(piece_bit_size); - U32 piece_bit_off32 = safe_cast_u32(piece_bit_off); - - U64 partial_value = ((U64)piece_bit_size32 << 32) | (U64)piece_bit_off32; - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValueBit, partial_value); - } break; - - case DW_ExprOp_Pick: { - U8 stack_idx = 0; - cursor += str8_deserial_read_struct(expr, cursor, &stack_idx); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, stack_idx); - } break; - - case DW_ExprOp_PlusUConst: { - U64 addend = 0; - cursor += str8_deserial_read_uleb128(expr, cursor, &addend); - rdim_bytecode_push_uconst(arena, &bc, addend); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_U); - } break; - - case DW_ExprOp_Skip: { - S16 skip = 0; - cursor += str8_deserial_read_struct(expr, cursor, &skip); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Skip, skip); - } break; - - case DW_ExprOp_Bra: { - NotImplemented; - } break; - - case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: - case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: - case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: - case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: - case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: - case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: - case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: - case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: - case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: - case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: - case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { - U64 reg_code_dw = op - DW_ExprOp_BReg0; - S64 reg_off = 0; - cursor += str8_deserial_read_sleb128(expr, cursor, ®_off); - - RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); - if (reg_off > 0) { - rdim_bytecode_push_sconst(arena, &bc, reg_off); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); - } - push_of_type(RDI_TypeKind_S64); - - *is_addr_out = 1; - } break; - - case DW_ExprOp_BRegX: { - U64 reg_code_dw = 0; - S64 reg_off = 0; - cursor += str8_deserial_read_uleb128(expr, cursor, ®_code_dw); - cursor += str8_deserial_read_sleb128(expr, cursor, ®_off); - - RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); - if (reg_off > 0) { - rdim_bytecode_push_sconst(arena, &bc, reg_off); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); - } - push_of_type(RDI_TypeKind_S64); - - *is_addr_out = 1; - } break; - - case DW_ExprOp_FBReg: { - S64 frame_off = 0; - cursor += str8_deserial_read_sleb128(expr, cursor, &frame_off); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, frame_off); - - *is_addr_out = 1; - } break; - - case DW_ExprOp_Deref: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, address_size); - } break; - - case DW_ExprOp_DerefSize: { - U8 deref_size_in_bytes = 0; - cursor += str8_deserial_read_struct(expr, cursor, &deref_size_in_bytes); - if (0 < deref_size_in_bytes && deref_size_in_bytes <= address_size) { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, deref_size_in_bytes); - } else { - // TODO: error handling - AssertAlways(!"ill formed expression"); - } - } break; - - case DW_ExprOp_XDerefSize: { + } else { // TODO: error handling - AssertAlways(!"no suitable conversion"); - } break; - - case DW_ExprOp_Call2: - case DW_ExprOp_Call4: - case DW_ExprOp_CallRef: { - // TODO: error handling - AssertAlways(!"calls are not supported"); - } break; - - case DW_ExprOp_ImplicitPointer: - case DW_ExprOp_GNU_ImplicitPointer: { - // TODO: - AssertAlways(!"sample"); - } break; - - case DW_ExprOp_Convert: - case DW_ExprOp_GNU_Convert: { - U64 type_info_off = 0; - cursor += str8_deserial_read_uleb128(expr, cursor, &type_info_off); - - RDI_EvalTypeGroup in = stack ? d2r_type_group_from_type_kind(stack->value_type) : RDI_EvalTypeGroup_Other; - RDI_EvalTypeGroup out = RDI_EvalTypeGroup_Other; - - if (type_info_off == 0) { - // - // 2.5.1 - // Instead of a base type, elements can have a generic type, - // which is an integral type that has the size of an address - // on the target machine and unspecified signedness. - // - out = d2r_type_group_from_type_kind(addr_type_kind); - } else { - // find ref tag - DW_TagNode *tag_node = dw_tag_node_from_info_off(cu, type_info_off); - DW_Tag tag = tag_node->tag; - if (tag.kind == DW_TagKind_BaseType) { - // extract encoding attribute - DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); - - // DW_ATE -> RDI_EvalTypeGroup - switch (encoding) { - case DW_ATE_SignedChar: - case DW_ATE_Signed: out = RDI_EvalTypeGroup_S; break; - case DW_ATE_UnsignedChar: - case DW_ATE_Unsigned: out = RDI_EvalTypeGroup_U; break; - case DW_ATE_Float: { - U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); - switch (byte_size) { - case 4: out = RDI_EvalTypeGroup_F32; break; - case 8: out = RDI_EvalTypeGroup_F64; break; - default: InvalidPath; - } - } break; - default: InvalidPath; - } - } else { - AssertAlways(!"unexpected tag"); // TODO: error handling - } - } - - if (in == RDI_EvalTypeGroup_Other) { - push_of_type(out); - break; - } - - // TODO: error handling - AssertAlways(in != RDI_EvalTypeGroup_Other); - AssertAlways(out != RDI_EvalTypeGroup_Other); - - U16 operand = (U16)in | ((U16)out << 8); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Convert, operand); - } break; - - case DW_ExprOp_GNU_ParameterRef: { - // TODO: - AssertAlways(!"sample"); - } break; - - case DW_ExprOp_DerefType: - case DW_ExprOp_GNU_DerefType: { - // TODO: - AssertAlways(!"sample"); - } break; - - case DW_ExprOp_ConstType: - case DW_ExprOp_GNU_ConstType: { - // TODO: - AssertAlways(!"sample"); - } break; - - case DW_ExprOp_RegvalType: { - // TODO: - AssertAlways(!"sample"); - } break; - - case DW_ExprOp_EntryValue: - case DW_ExprOp_GNU_EntryValue: { - U64 entry_value_expr_size = 0; - String8 entry_value_expr = {0}; - cursor += str8_deserial_read_uleb128(expr, cursor, &entry_value_expr_size); - cursor += str8_deserial_read_block(expr, cursor, entry_value_expr_size, &entry_value_expr); - - B32 dummy = 0; - RDIM_EvalBytecode call_site_bc = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, entry_value_expr, cu, &dummy); - - U32 encoded_size32 = safe_cast_u32(call_site_bc.encoded_size); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_CallSiteValue, encoded_size32); - rdim_bytecode_concat_in_place(&bc, &call_site_bc); - } break; - - case DW_ExprOp_Addrx: { - U64 addr_idx = 0; - cursor += str8_deserial_read_uleb128(expr, cursor, &addr_idx); - U64 addr = dw_addr_from_list_unit(addr_lu, addr_idx); - if (addr != max_U64) { - if (addr >= image_base) { - U64 voff = addr - image_base; - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); - } else { - // TODO: error handling - AssertAlways(!"unable to relocate address"); - } - } else { - // TODO: error handling - AssertAlways(!"out of bounds index"); - } - } break; - - case DW_ExprOp_CallFrameCfa: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, 0); - } break; - - case DW_ExprOp_FormTlsAddress: { - // TODO: - AssertAlways(!"RDI_EvalOp_TLSOff accepts immediate"); - } break; - - case DW_ExprOp_PushObjectAddress: { - AssertAlways(!"sample"); - } break; - - case DW_ExprOp_Nop: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Noop, 0); - } break; - - case DW_ExprOp_Eq: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_EqEq, peek_type()); - } break; - - case DW_ExprOp_Ge: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_GrEq, peek_type()); - } break; - - case DW_ExprOp_Gt: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Grtr, peek_type()); - } break; - - case DW_ExprOp_Le: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_LsEq, peek_type()); - } break; - - case DW_ExprOp_Lt: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Less, peek_type()); - } break; - - case DW_ExprOp_Ne: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_NtEq, peek_type()); - } break; - - case DW_ExprOp_Shl: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_LShift, peek_type()); - } break; - - case DW_ExprOp_Shr: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, RDI_EvalTypeGroup_U); - } break; - - case DW_ExprOp_Shra: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, RDI_EvalTypeGroup_S); - } break; - - case DW_ExprOp_Xor: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitXor, peek_type()); - } break; - - case DW_ExprOp_XDeref: { - // TODO: error handling - Assert(!"multiple address spaces are not supported"); - } break; - - case DW_ExprOp_Abs: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Abs, peek_type()); - } break; - - case DW_ExprOp_And: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitAnd, peek_type()); - } break; - - case DW_ExprOp_Div: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Div, peek_type()); - } break; - - case DW_ExprOp_Minus: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Sub, peek_type()); - } break; - - case DW_ExprOp_Mod: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mod, peek_type()); - } break; - - case DW_ExprOp_Mul: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mul, peek_type()); - } break; - - case DW_ExprOp_Neg: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Neg, peek_type()); - } break; - - case DW_ExprOp_Not: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitNot, peek_type()); - } break; - - case DW_ExprOp_Or: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitOr, peek_type()); - } break; - - case DW_ExprOp_Plus: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, peek_type()); - } break; - - case DW_ExprOp_Rot: { - AssertAlways(!"no suitable conversion"); - } break; - - case DW_ExprOp_Swap: { - AssertAlways(!"no suitable conversion"); - } break; - - case DW_ExprOp_Dup: { - AssertAlways(!"no suitable conversion"); - } break; - - case DW_ExprOp_Drop: { - AssertAlways(!"no suitable conversion"); - } break; - - case DW_ExprOp_Over: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 1); - } break; - - case DW_ExprOp_StackValue: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Stop, 0); - } break; - - case DW_ExprOp_GNU_PushTlsAddress: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, 0); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Sub, peek_type()); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_TLSOff, 0); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, peek_type()); - } break; - - default: InvalidPath; break; + AssertAlways(!"out of bounds index"); + } + } break; + case DW_ExprOp_CallFrameCfa: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, 0); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + case DW_ExprOp_FormTlsAddress: { + // TODO: + AssertAlways(!"RDI_EvalOp_TLSOff accepts immediate"); + } break; + case DW_ExprOp_PushObjectAddress: { + AssertAlways(!"sample"); + } break; + case DW_ExprOp_Nop: {} break; + case DW_ExprOp_Eq: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_EqEq); } break; + case DW_ExprOp_Ge: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_GrEq); } break; + case DW_ExprOp_Gt: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_Grtr); } break; + case DW_ExprOp_Le: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_LsEq); } break; + case DW_ExprOp_Lt: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_Less); } break; + case DW_ExprOp_Ne: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_NtEq); } break; + case DW_ExprOp_Div: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Div); } break; + case DW_ExprOp_Minus: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Sub); } break; + case DW_ExprOp_Mul: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Mul); } break; + case DW_ExprOp_Plus: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Add); } break; + case DW_ExprOp_Xor: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitXor); } break; + case DW_ExprOp_And: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitAnd); } break; + case DW_ExprOp_Or: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitOr); } break; + case DW_ExprOp_Shl: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_LShift); } break; + case DW_ExprOp_Shr: { + D2R_ValueType rhs = d2r_value_type_stack_pop(stack); + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + if (D2R_ValueType_IsInt(rhs) && D2R_ValueType_IsInt(lhs)) { + D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); + D2R_ValueType result_type = d2r_unsigned_value_type_from_bit_size(d2r_size_from_value_type((address_size), common_type) * 8); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, d2r_value_type_to_rdi(result_type)); + d2r_value_type_stack_push(scratch.arena, stack, result_type); + } else { + // TODO: report error + AssertAlways(!"operands must be of integral type"); + } + } break; + case DW_ExprOp_Shra: { + D2R_ValueType rhs = d2r_value_type_stack_pop(stack); + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + if (D2R_ValueType_IsInt(lhs) && D2R_ValueType_IsInt(rhs)) { + D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); + D2R_ValueType result_type = d2r_signed_value_type_from_bit_size(d2r_size_from_value_type((address_size), common_type) * 8); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, d2r_value_type_to_rdi(result_type)); + d2r_value_type_stack_push(scratch.arena, stack, result_type); + } else { + // TODO: report error + AssertAlways(!"operands must be of integral type"); + } + } break; + case DW_ExprOp_Mod: { + D2R_ValueType rhs = d2r_value_type_stack_pop(stack); + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + if (!D2R_ValueType_IsInt(rhs) || !D2R_ValueType_IsInt(lhs)) { + // TODO: report error + AssertAlways(!"operands must be of integral type"); + is_ok = 0; + break; + } + D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mod, d2r_value_type_to_rdi(common_type)); + d2r_value_type_stack_push(scratch.arena, stack, common_type); + } break; + case DW_ExprOp_Abs: { + if (!D2R_ValueType_IsInt(d2r_value_type_stack_peek(stack)) && !D2R_ValueType_IsFloat(d2r_value_type_stack_peek(stack))) { + // TODO: report error + AssertAlways(!"operand must be of integral type or float"); + is_ok = 0; + break; + } + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Abs, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); + } break; + case DW_ExprOp_Neg: { + if (!D2R_ValueType_IsInt(d2r_value_type_stack_peek(stack))) { + // TODO: report error + AssertAlways(!"operand must be of integral type"); + is_ok = 0; + break; + } + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Neg, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); + } break; + case DW_ExprOp_Not: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitNot, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); + } break; + case DW_ExprOp_Dup: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 0); + d2r_value_type_stack_push(scratch.arena, stack, d2r_value_type_stack_peek(stack)); + } break; + case DW_ExprOp_Rot: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_Swap: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_Drop: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_StackValue: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Stop, 0); + if (stack->top->type == D2R_ValueType_Address) { + stack->top->type = d2r_unsigned_value_type_from_bit_size(address_size * 8); + } + } break; + case DW_ExprOp_GNU_PushTlsAddress: { + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + if (!D2R_ValueType_IsInt(lhs)) { + // TODO: report error + AssertAlways(!"lhs must be of integral type"); + } + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_TLSOff, 0); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, d2r_value_type_to_rdi(lhs)); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + + default: InvalidPath; break; } + if (!is_ok) { break; } + + // store converted instruction + if (last_op != bc.last_op) { + RDIM_EvalBytecodeOp *first_converted_op = last_op ? last_op->next : bc.first_op; + converted_insts[inst_idx] = first_converted_op; + } + + inst_idx += 1; + } + + if (is_ok) { + // fixup bytecode + for EachNode(op, RDIM_EvalBytecodeOp, bc.first_op) { + if (op->op == RDI_EvalOp_Skip) { + // unpack skip info + U32 inst_idx = Extract32(op->p, 0); + S16 skip_count_signed = (S16)Extract32(op->p, 1); + U16 skip_count = abs_s64(skip_count_signed); + B32 skip_fwd = skip_count_signed > 0; + + // setup being/end links + RDIM_EvalBytecodeOp *begin = 0, *end = 0; + if (skip_fwd) { + if (inst_idx + skip_count <= expr.count) { + begin = converted_insts[inst_idx]; + end = (inst_idx + skip_count) < expr.count ? converted_insts[inst_idx + skip_count] : 0; + } else { + // TODO: report error + AssertAlways(!"out of bounds skip"); + } + } else { + if (skip_count <= inst_idx) { + begin = converted_insts[inst_idx - skip_count]; + end = converted_insts[inst_idx]; + } else { + // TODO: report error + AssertAlways(!"out of bounds skip"); + } + } + + // compute skip delta + U64 skip_delta = 0; + for (RDIM_EvalBytecodeOp *n = begin; n != end; n = n->next) { + skip_delta += n->p_size; + } + + // rewrite skip operand with byte delta + AssertAlways(skip_delta <= max_S16); + op->p = skip_fwd ? (S16)skip_delta : -(S16)skip_delta; + } + } + + if (result_type_out) { + *result_type_out = d2r_value_type_stack_peek(stack); + } + } else { + MemoryZeroStruct(&bc); + temp_end(arena_restore_point); } -#undef peek_type -#undef pop_type -#undef push_of_type scratch_end(scratch); return bc; } @@ -935,13 +1443,13 @@ d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Inp { RDIM_Location *loc = 0; if (expr.size) { - B32 is_addr = 0; - RDIM_EvalBytecode bytecode = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, expr, cu, &is_addr); + D2R_ValueType result_type = 0; + RDIM_EvalBytecode bytecode = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, expr, cu, &result_type); RDIM_LocationInfo *loc_info = push_array(arena, RDIM_LocationInfo, 1); - loc_info->kind = is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; + loc_info->kind = result_type == D2R_ValueType_Address ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; loc_info->bytecode = bytecode; - + loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); } return loc; @@ -1037,7 +1545,7 @@ d2r_var_locset_from_tag(Arena *arena, loc_info->kind = RDI_LocationKind_ValBytecodeStream; loc_info->bytecode = bc; RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); - + // push location cases for EachNode(range_n, RDIM_Rng1U64Node, curr_scope->voff_ranges.first) { rdim_push_location_case(arena, scopes, &locset, loc, range_n->v); @@ -1211,19 +1719,19 @@ d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter) goto exit; } } - + while (iter->stack) { // go to sibling iter->stack->node = iter->stack->node->sibling; if (iter->stack->node) { break; } - + // no more siblings, go up D2R_TagFrame *f = iter->stack; SLLStackPop(iter->stack); SLLStackPush(iter->free_list, f); } - - exit:; + +exit:; // update iterator iter->visit_children = 1; iter->tag_node = iter->stack ? iter->stack->node : 0; @@ -1281,13 +1789,13 @@ d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *inpu // find type type = d2r_type_from_offset(type_table, ref.info_off); - + // was type converted? if (type == 0) { // issue type conversion DW_TagNode *ref_node = dw_tag_node_from_info_off(cu, ref.info_off); d2r_convert_types(arena, type_table, input, cu, cu_lang, arch_addr_size, ref_node); - + // if we do not have a converted type at this point then debug info is malformed type = d2r_type_from_offset(type_table, ref.info_off); Assert(type); @@ -1313,7 +1821,7 @@ d2r_convert_types(Arena *arena, for (D2R_TagIterator *it = d2r_tag_iterator_init(scratch.arena, root); it->tag_node != 0; d2r_tag_iterator_next(scratch.arena, it)) { DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; - + // skip converted tags if (d2r_is_tag_converted(tag_node)) { d2r_tag_iterator_skip_children(it); @@ -1321,376 +1829,376 @@ d2r_convert_types(Arena *arena, } // mark the tag as converted here, because during conversion we may recurse on the same tag d2r_flag_converted_tag(tag_node); - + switch (tag.kind) { - case DW_TagKind_ClassType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_IncompleteClass; - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Class; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - type->direct_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - } - } break; - case DW_TagKind_StructureType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteStruct; - - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Struct; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - } - } break; - case DW_TagKind_UnionType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteUnion; - - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Union; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - } - } break; - case DW_TagKind_EnumerationType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteEnum; - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Enum; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - type->direct_type = enum_base_type; - } - } break; - case DW_TagKind_SubroutineType: { - RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - - // collect parameters - RDIM_TypeList param_list = {0}; - for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind == DW_TagKind_FormalParameter) { - RDIM_Type *param_type = d2r_type_from_attrib(type_table, input, cu, n->tag, DW_AttribKind_Type); - rdim_type_list_push(scratch.arena, ¶m_list, param_type); - } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { - rdim_type_list_push(scratch.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); - } else { - // TODO: error handling - AssertAlways(!"unexpected tag"); - } - } - - // init proceudre type - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Function; - type->byte_size = arch_addr_size; - type->direct_type = ret_type; - type->count = param_list.count; - type->param_types = rdim_array_from_type_list(arena, param_list); - + case DW_TagKind_ClassType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_IncompleteClass; + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + Assert(!tag_node->first_child); d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_Typedef: { + } else { RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->direct_type = direct_type; - for (RDIM_Type *n = direct_type; n != 0; n = n->direct_type) { - if (n->byte_size) { - type->byte_size = n->byte_size; - break; - } - } - } break; - case DW_TagKind_BaseType: { - DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); - U64 byte_size = dw_byte_size_from_tag(input, cu, tag); - - // convert base type encoding to RDI version - RDI_TypeKind kind = RDI_TypeKind_NULL; - switch (encoding) { - case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; - case DW_ATE_Address: kind = RDI_TypeKind_Void; break; - case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; - case DW_ATE_ComplexFloat: { - switch (byte_size) { - case 4: kind = RDI_TypeKind_ComplexF32; break; - case 8: kind = RDI_TypeKind_ComplexF64; break; - case 10: kind = RDI_TypeKind_ComplexF80; break; - case 16: kind = RDI_TypeKind_ComplexF128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Float: { - switch (byte_size) { - case 2: kind = RDI_TypeKind_F16; break; - case 4: kind = RDI_TypeKind_F32; break; - case 6: kind = RDI_TypeKind_F48; break; - case 8: kind = RDI_TypeKind_F64; break; - case 16: kind = RDI_TypeKind_F128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Signed: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_S8; break; - case 2: kind = RDI_TypeKind_S16; break; - case 4: kind = RDI_TypeKind_S32; break; - case 8: kind = RDI_TypeKind_S64; break; - case 16: kind = RDI_TypeKind_S128; break; - case 32: kind = RDI_TypeKind_S256; break; - case 64: kind = RDI_TypeKind_S512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_SignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_Char8; break; - case 2: kind = RDI_TypeKind_Char16; break; - case 4: kind = RDI_TypeKind_Char32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Unsigned: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_U8; break; - case 2: kind = RDI_TypeKind_U16; break; - case 4: kind = RDI_TypeKind_U32; break; - case 8: kind = RDI_TypeKind_U64; break; - case 16: kind = RDI_TypeKind_U128; break; - case 32: kind = RDI_TypeKind_U256; break; - case 64: kind = RDI_TypeKind_U512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_UnsignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_UChar8; break; - case 2: kind = RDI_TypeKind_UChar16; break; - case 4: kind = RDI_TypeKind_UChar32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_ImaginaryFloat: { - NotImplemented; - } break; - case DW_ATE_PackedDecimal: { - NotImplemented; - } break; - case DW_ATE_NumericString: { - NotImplemented; - } break; - case DW_ATE_Edited: { - NotImplemented; - } break; - case DW_ATE_SignedFixed: { - NotImplemented; - } break; - case DW_ATE_UnsignedFixed: { - NotImplemented; - } break; - case DW_ATE_DecimalFloat: { - NotImplemented; - } break; - case DW_ATE_Utf: { - NotImplemented; - } break; - case DW_ATE_Ucs: { - NotImplemented; - } break; - case DW_ATE_Ascii: { - NotImplemented; - } break; - default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling - } - - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->direct_type = type_table->builtin_types[kind]; - type->byte_size = byte_size; - } break; - case DW_TagKind_PointerType: { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); - - U64 byte_size = arch_addr_size; - if (cu->version == DW_Version_5 || cu->relaxed) { - dw_try_byte_size_from_tag(input, cu, tag, &byte_size); - } - - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Ptr; - type->byte_size = byte_size; - type->direct_type = direct_type; - } break; - case DW_TagKind_RestrictType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Restrict; - type->direct_type = direct_type; - } break; - case DW_TagKind_VolatileType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Volatile; - type->direct_type = direct_type; - } break; - case DW_TagKind_ConstType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Const; - type->direct_type = direct_type; - } break; - case DW_TagKind_ArrayType: { - // * DWARF vs RDI Array Type Graph * - // - // For example lets take following decl: - // - // int (*foo[2])[3]; - // - // This compiles to in DWARF: - // - // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] - // \ - // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] - // \ - // -> (B1) DW_TAG_BaseType (int) - // - // RDI expects: - // - // foo -> Array[2] -> Pointer -> Array[3] -> int - // - // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and - // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. - // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from - // B to A. - struct SubrangeNode { struct SubrangeNode *next; U64 count; }; - struct SubrangeNode *subrange_stack = 0; - for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind != DW_TagKind_SubrangeType) { - // TODO: error handling - AssertAlways(!"unexpected tag"); - continue; - } - - // resolve lower bound - U64 lower_bound = 0; - if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_LowerBound)) { - lower_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_LowerBound); - } else { - lower_bound = dw_pick_default_lower_bound(cu_lang); - } - - // resolve upper bound - U64 upper_bound = 0; - if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_Count)) { - U64 count = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_Count); - upper_bound = lower_bound + count; - } else if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_UpperBound)) { - upper_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_UpperBound); - // turn upper bound into exclusive range - upper_bound += 1; - } else { - // zero sized array - } - - struct SubrangeNode *s = push_array(scratch.arena, struct SubrangeNode, 1); - s->count = upper_bound - lower_bound; - SLLStackPush(subrange_stack, s); - } - - RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *direct_type = array_base_type; - U64 size_cursor = array_base_type->byte_size; - for EachNode(s, struct SubrangeNode, subrange_stack) { - size_cursor *= s->count; - - RDIM_Type *t; - if (s->next) { t = d2r_create_type(arena, type_table); } - else { t = d2r_create_type_from_offset(arena, type_table, tag.info_off); } - - t->kind = RDI_TypeKind_Array; - t->direct_type = direct_type; - t->byte_size = size_cursor; - t->count = s->count; - - direct_type = t; - } - - d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_SubrangeType: { + type->kind = RDI_TypeKind_Class; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + type->direct_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + } + } break; + case DW_TagKind_StructureType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteStruct; + // TODO: error handling - AssertAlways(!"unexpected tag"); - } break; - case DW_TagKind_Inheritance: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind != DW_TagKind_StructureType && parent_tag.kind != DW_TagKind_ClassType) { + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Struct; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + } + } break; + case DW_TagKind_UnionType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteUnion; + + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Union; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + } + } break; + case DW_TagKind_EnumerationType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteEnum; + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Enum; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + type->direct_type = enum_base_type; + } + } break; + case DW_TagKind_SubroutineType: { + RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + + // collect parameters + RDIM_TypeList param_list = {0}; + for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind == DW_TagKind_FormalParameter) { + RDIM_Type *param_type = d2r_type_from_attrib(type_table, input, cu, n->tag, DW_AttribKind_Type); + rdim_type_list_push(scratch.arena, ¶m_list, param_type); + } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { + rdim_type_list_push(scratch.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); + } else { // TODO: error handling - AssertAlways(!"unexpected parent tag"); + AssertAlways(!"unexpected tag"); + } + } + + // init proceudre type + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Function; + type->byte_size = arch_addr_size; + type->direct_type = ret_type; + type->count = param_list.count; + type->param_types = rdim_array_from_type_list(arena, param_list); + + d2r_tag_iterator_skip_children(it); + } break; + case DW_TagKind_Typedef: { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->direct_type = direct_type; + for (RDIM_Type *n = direct_type; n != 0; n = n->direct_type) { + if (n->byte_size) { + type->byte_size = n->byte_size; + break; + } + } + } break; + case DW_TagKind_BaseType: { + DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); + U64 byte_size = dw_byte_size_from_tag(input, cu, tag); + + // convert base type encoding to RDI version + RDI_TypeKind kind = RDI_TypeKind_NULL; + switch (encoding) { + case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; + case DW_ATE_Address: kind = RDI_TypeKind_Void; break; + case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; + case DW_ATE_ComplexFloat: { + switch (byte_size) { + case 4: kind = RDI_TypeKind_ComplexF32; break; + case 8: kind = RDI_TypeKind_ComplexF64; break; + case 10: kind = RDI_TypeKind_ComplexF80; break; + case 16: kind = RDI_TypeKind_ComplexF128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling } - - RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); - member->kind = RDI_MemberKind_Base; - member->type = type; - member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); } break; + case DW_ATE_Float: { + switch (byte_size) { + case 2: kind = RDI_TypeKind_F16; break; + case 4: kind = RDI_TypeKind_F32; break; + case 6: kind = RDI_TypeKind_F48; break; + case 8: kind = RDI_TypeKind_F64; break; + case 16: kind = RDI_TypeKind_F128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Signed: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_S8; break; + case 2: kind = RDI_TypeKind_S16; break; + case 4: kind = RDI_TypeKind_S32; break; + case 8: kind = RDI_TypeKind_S64; break; + case 16: kind = RDI_TypeKind_S128; break; + case 32: kind = RDI_TypeKind_S256; break; + case 64: kind = RDI_TypeKind_S512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_SignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_Char8; break; + case 2: kind = RDI_TypeKind_Char16; break; + case 4: kind = RDI_TypeKind_Char32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Unsigned: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_U8; break; + case 2: kind = RDI_TypeKind_U16; break; + case 4: kind = RDI_TypeKind_U32; break; + case 8: kind = RDI_TypeKind_U64; break; + case 16: kind = RDI_TypeKind_U128; break; + case 32: kind = RDI_TypeKind_U256; break; + case 64: kind = RDI_TypeKind_U512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_UnsignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_UChar8; break; + case 2: kind = RDI_TypeKind_UChar16; break; + case 4: kind = RDI_TypeKind_UChar32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_ImaginaryFloat: { + NotImplemented; + } break; + case DW_ATE_PackedDecimal: { + NotImplemented; + } break; + case DW_ATE_NumericString: { + NotImplemented; + } break; + case DW_ATE_Edited: { + NotImplemented; + } break; + case DW_ATE_SignedFixed: { + NotImplemented; + } break; + case DW_ATE_UnsignedFixed: { + NotImplemented; + } break; + case DW_ATE_DecimalFloat: { + NotImplemented; + } break; + case DW_ATE_Utf: { + NotImplemented; + } break; + case DW_ATE_Ucs: { + NotImplemented; + } break; + case DW_ATE_Ascii: { + NotImplemented; + } break; + default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + } + + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->direct_type = type_table->builtin_types[kind]; + type->byte_size = byte_size; + } break; + case DW_TagKind_PointerType: { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); + + U64 byte_size = arch_addr_size; + if (cu->version == DW_Version_5 || cu->relaxed) { + dw_try_byte_size_from_tag(input, cu, tag, &byte_size); + } + + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Ptr; + type->byte_size = byte_size; + type->direct_type = direct_type; + } break; + case DW_TagKind_RestrictType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Restrict; + type->direct_type = direct_type; + } break; + case DW_TagKind_VolatileType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Volatile; + type->direct_type = direct_type; + } break; + case DW_TagKind_ConstType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Const; + type->direct_type = direct_type; + } break; + case DW_TagKind_ArrayType: { + // * DWARF vs RDI Array Type Graph * + // + // For example lets take following decl: + // + // int (*foo[2])[3]; + // + // This compiles to in DWARF: + // + // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] + // \ + // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] + // \ + // -> (B1) DW_TAG_BaseType (int) + // + // RDI expects: + // + // foo -> Array[2] -> Pointer -> Array[3] -> int + // + // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and + // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. + // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from + // B to A. + struct SubrangeNode { struct SubrangeNode *next; U64 count; }; + struct SubrangeNode *subrange_stack = 0; + for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind != DW_TagKind_SubrangeType) { + // TODO: error handling + AssertAlways(!"unexpected tag"); + continue; + } + + // resolve lower bound + U64 lower_bound = 0; + if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_LowerBound)) { + lower_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_LowerBound); + } else { + lower_bound = dw_pick_default_lower_bound(cu_lang); + } + + // resolve upper bound + U64 upper_bound = 0; + if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_Count)) { + U64 count = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_Count); + upper_bound = lower_bound + count; + } else if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_UpperBound)) { + upper_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_UpperBound); + // turn upper bound into exclusive range + upper_bound += 1; + } else { + // zero sized array + } + + struct SubrangeNode *s = push_array(scratch.arena, struct SubrangeNode, 1); + s->count = upper_bound - lower_bound; + SLLStackPush(subrange_stack, s); + } + + RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = array_base_type; + U64 size_cursor = array_base_type->byte_size; + for EachNode(s, struct SubrangeNode, subrange_stack) { + size_cursor *= s->count; + + RDIM_Type *t; + if (s->next) { t = d2r_create_type(arena, type_table); } + else { t = d2r_create_type_from_offset(arena, type_table, tag.info_off); } + + t->kind = RDI_TypeKind_Array; + t->direct_type = direct_type; + t->byte_size = size_cursor; + t->count = s->count; + + direct_type = t; + } + + d2r_tag_iterator_skip_children(it); + } break; + case DW_TagKind_SubrangeType: { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } break; + case DW_TagKind_Inheritance: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind != DW_TagKind_StructureType && parent_tag.kind != DW_TagKind_ClassType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = type; + member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); + } break; } } scratch_end(scratch); @@ -1710,85 +2218,85 @@ d2r_convert_udts(Arena *arena, DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; switch (tag.kind) { - case DW_TagKind_ClassType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; + case DW_TagKind_ClassType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_StructureType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_UnionType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_EnumerationType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_Member: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + B32 is_parent_udt = parent_tag.kind == DW_TagKind_StructureType || + parent_tag.kind == DW_TagKind_ClassType || + parent_tag.kind == DW_TagKind_UnionType; + if (is_parent_udt) { + DW_Attrib *data_member_location = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_DataMemberLocation); + DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); + if (data_member_location_class == DW_AttribClass_LocList) { + AssertAlways(!"UDT member with multiple locations are not supported"); } - } break; - case DW_TagKind_StructureType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_UnionType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_EnumerationType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_Member: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - B32 is_parent_udt = parent_tag.kind == DW_TagKind_StructureType || - parent_tag.kind == DW_TagKind_ClassType || - parent_tag.kind == DW_TagKind_UnionType; - if (is_parent_udt) { - DW_Attrib *data_member_location = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_DataMemberLocation); - DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); - if (data_member_location_class == DW_AttribClass_LocList) { - AssertAlways(!"UDT member with multiple locations are not supported"); - } - - RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTMember *udt_member = rdim_udt_push_member(arena, &udts, parent_type->udt); - udt_member->kind = RDI_MemberKind_DataField; - udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - udt_member->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - udt_member->off = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation); - } else { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - } break; - case DW_TagKind_Enumerator: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_EnumerationType) { - RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &udts, parent_type->udt); - udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - udt_member->val = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ConstValue); - } else { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - } break; + + RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTMember *udt_member = rdim_udt_push_member(arena, &udts, parent_type->udt); + udt_member->kind = RDI_MemberKind_DataField; + udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + udt_member->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + udt_member->off = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation); + } else { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + } break; + case DW_TagKind_Enumerator: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_EnumerationType) { + RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &udts, parent_type->udt); + udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + udt_member->val = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ConstValue); + } else { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + } break; } } scratch_end(scratch); @@ -1811,110 +2319,39 @@ d2r_convert_symbols(Arena *arena, DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; switch (tag.kind) { - case DW_TagKind_Null: { InvalidPath; } break; - case DW_TagKind_ClassType: - case DW_TagKind_StructureType: - case DW_TagKind_UnionType: { - // visit children to collect methods and variables - } break; - case DW_TagKind_EnumerationType: - case DW_TagKind_SubroutineType: - case DW_TagKind_Typedef: - case DW_TagKind_BaseType: - case DW_TagKind_PointerType: - case DW_TagKind_RestrictType: - case DW_TagKind_VolatileType: - case DW_TagKind_ConstType: - case DW_TagKind_ArrayType: - case DW_TagKind_SubrangeType: - case DW_TagKind_Inheritance: - case DW_TagKind_Enumerator: - case DW_TagKind_Member: { - d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_SubProgram: { - DW_InlKind inl = dw_u64_from_attrib(input, cu, tag, DW_AttribKind_Inline); - switch (inl) { - case DW_Inl_NotInlined: { - U64 param_count = 0; - RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); - - // get return type - RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - - // fill out proc type - RDIM_Type *proc_type = d2r_create_type(arena, type_table); - proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; - proc_type->direct_type = ret_type; - proc_type->count = param_count; - proc_type->param_types = params; - - // get container type - RDIM_Type *container_type = 0; - if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { - container_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); - } - - // get frame base expression - String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_FrameBase); - - // get proc container symbol - RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP); - - // make scope - Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - root_scope->symbol = proc; - - // fill out proc - proc->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); - proc->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - proc->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); - proc->type = proc_type; - proc->container_symbol = 0; - proc->container_type = container_type; - proc->root_scope = root_scope; - proc->location_cases = d2r_locset_from_attrib(arena, &scopes, root_scope, &locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); - - // sub program with user-defined parent tag is a method - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_ClassType || parent_tag.kind == DW_TagKind_StructureType) { - RDI_MemberKind member_kind = RDI_MemberKind_NULL; - DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Virtuality); - switch (virtuality) { - case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; - case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; - case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal - //default: InvalidPath; break; - } - - RDIM_Type *type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); - member->kind = member_kind; - member->type = type; - member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - } else if (parent_tag.kind != DW_TagKind_CompileUnit) { - //AssertAlways(!"unexpected tag"); - } - - it->stack->scope = root_scope; - } break; - case DW_Inl_DeclaredNotInlined: - case DW_Inl_DeclaredInlined: - case DW_Inl_Inlined: { - d2r_tag_iterator_skip_children(it); - } break; - default: InvalidPath; break; - } - } break; - case DW_TagKind_InlinedSubroutine: { + case DW_TagKind_Null: { InvalidPath; } break; + case DW_TagKind_ClassType: + case DW_TagKind_StructureType: + case DW_TagKind_UnionType: { + // visit children to collect methods and variables + } break; + case DW_TagKind_EnumerationType: + case DW_TagKind_SubroutineType: + case DW_TagKind_Typedef: + case DW_TagKind_BaseType: + case DW_TagKind_PointerType: + case DW_TagKind_RestrictType: + case DW_TagKind_VolatileType: + case DW_TagKind_ConstType: + case DW_TagKind_ArrayType: + case DW_TagKind_SubrangeType: + case DW_TagKind_Inheritance: + case DW_TagKind_Enumerator: + case DW_TagKind_Member: { + d2r_tag_iterator_skip_children(it); + } break; + case DW_TagKind_SubProgram: { + DW_InlKind inl = DW_Inl_NotInlined; + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Inline)) { inl = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Inline); } + + switch (inl) { + case DW_Inl_NotInlined: { U64 param_count = 0; RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); - + // get return type RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - + // fill out proc type RDIM_Type *proc_type = d2r_create_type(arena, type_table); proc_type->kind = RDI_TypeKind_Function; @@ -1922,124 +2359,199 @@ d2r_convert_symbols(Arena *arena, proc_type->direct_type = ret_type; proc_type->count = param_count; proc_type->param_types = params; - + // get container type - RDIM_Type *owner = 0; + RDIM_Type *container_type = 0; if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { - owner = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); + container_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); } - - // fill out inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); - inline_site->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - inline_site->type = proc_type; - inline_site->owner = owner; - inline_site->line_table = 0; - + + // get frame base expression + String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_FrameBase); + + // get proc container symbol + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP); + // make scope Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - root_scope->inline_site = inline_site; - } break; - case DW_TagKind_Variable: { - String8 name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - RDIM_Type *type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - + root_scope->symbol = proc; + + // fill out proc + proc->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); + proc->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + proc->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); + proc->type = proc_type; + proc->container_symbol = 0; + proc->container_type = container_type; + proc->root_scope = root_scope; + proc->location_cases = d2r_locset_from_attrib(arena, &scopes, root_scope, &locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); + + // sub program with user-defined parent tag is a method DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || - parent_tag.kind == DW_TagKind_InlinedSubroutine || - parent_tag.kind == DW_TagKind_LexicalBlock) { - RDIM_Scope *scope = it->stack->next->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &scopes, scope); - local->kind = RDI_LocalKind_Variable; - local->name = name; - local->type = type; - local->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); - } else { - - // NOTE: due to a bug in clang in stb_sprint.h local variables - // are declared in global scope without a name - if (name.size == 0) { break; } - - B32 is_thread_var = 0; - U64 voff = 0; - { - DW_Attrib *loc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_Location); - DW_AttribClass loc_class = dw_value_class_from_attrib(cu, loc_attrib); - if (loc_class == DW_AttribClass_ExprLoc) { - String8 expr = dw_exprloc_from_attrib(input, cu, loc_attrib); - B32 is_addr = 0; - RDIM_EvalBytecode bc = d2r_bytecode_from_expression(arena, input, image_base, arch_addr_size, arch, cu->addr_lu, expr, cu, &is_addr); - - for EachNode(n, RDIM_EvalBytecodeOp, bc.first_op) { - if (n->op == RDI_EvalOp_TLSOff) { - is_thread_var = 1; - break; - } - } - - if (is_addr) { - if (rdim_is_eval_bytecode_static(bc)) { - voff = rdim_do_static_bytecode_eval(bc, image_base); - } + if (parent_tag.kind == DW_TagKind_ClassType || parent_tag.kind == DW_TagKind_StructureType) { + RDI_MemberKind member_kind = RDI_MemberKind_NULL; + DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Virtuality); + switch (virtuality) { + case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; + case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; + case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal + //default: InvalidPath; break; + } + + RDIM_Type *type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = member_kind; + member->type = type; + member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + } else if (parent_tag.kind != DW_TagKind_CompileUnit) { + //AssertAlways(!"unexpected tag"); + } + + it->stack->scope = root_scope; + } break; + case DW_Inl_DeclaredNotInlined: + case DW_Inl_DeclaredInlined: + case DW_Inl_Inlined: { + d2r_tag_iterator_skip_children(it); + } break; + default: InvalidPath; break; + } + } break; + case DW_TagKind_InlinedSubroutine: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *owner = 0; + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { + owner = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); + } + + // fill out inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); + inline_site->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + inline_site->type = proc_type; + inline_site->owner = owner; + inline_site->line_table = 0; + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + root_scope->inline_site = inline_site; + } break; + case DW_TagKind_Variable: { + String8 name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + RDIM_Type *type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || + parent_tag.kind == DW_TagKind_InlinedSubroutine || + parent_tag.kind == DW_TagKind_LexicalBlock) { + RDIM_Scope *scope = it->stack->next->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &scopes, scope); + local->kind = RDI_LocalKind_Variable; + local->name = name; + local->type = type; + local->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + } else { + + // NOTE: due to a bug in clang in stb_sprint.h local variables + // are declared in global scope without a name + if (name.size == 0) { break; } + + U64 voff = max_U64; + B32 is_thread_var = 0; + { + DW_Attrib *loc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_Location); + DW_AttribClass loc_class = dw_value_class_from_attrib(cu, loc_attrib); + if (loc_class == DW_AttribClass_ExprLoc) { + Temp temp = temp_begin(scratch.arena); + + String8 expr = dw_exprloc_from_attrib(input, cu, loc_attrib); + D2R_ValueType expr_type = 0; + RDIM_EvalBytecode bc = d2r_bytecode_from_expression(temp.arena, input, image_base, arch_addr_size, arch, cu->addr_lu, expr, cu, &expr_type); + + // evaluate bytecode to virutal offset if possible + if (expr_type == D2R_ValueType_Address) { + B32 is_static = rdim_is_eval_bytecode_static(bc); + if (is_static) { + voff = rdim_virt_off_from_eval_bytecode(bc, image_base); } } + + // is this a thread variable? + is_thread_var = rdim_is_bytecode_tls_dependent(bc); + + temp_end(temp); } - - RDIM_SymbolChunkList *var_chunks; U64 var_chunks_cap; - if (is_thread_var) { var_chunks = &tvars; var_chunks_cap = TVAR_CHUNK_CAP; } - else { var_chunks = &gvars; var_chunks_cap = GVAR_CHUNK_CAP; } - - RDIM_Symbol *var = rdim_symbol_chunk_list_push(arena, var_chunks, var_chunks_cap); - var->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); - var->name = name; - var->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); - var->type = type; - var->offset = voff; - var->container_symbol = 0; - var->container_type = 0; // TODO: NotImplemented; } - } break; - case DW_TagKind_FormalParameter: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || parent_tag.kind == DW_TagKind_InlinedSubroutine) { - RDIM_Scope *scope = it->stack->next->scope; - RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); - param->kind = RDI_LocalKind_Parameter; - param->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - param->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - param->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); - } else { - // TODO: error handling - AssertAlways(!"this is a local variable"); - } - } break; - case DW_TagKind_LexicalBlock: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || - parent_tag.kind == DW_TagKind_InlinedSubroutine || - parent_tag.kind == DW_TagKind_LexicalBlock) { - Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - } - } break; - case DW_TagKind_CallSite: { - // TODO - } break; - case DW_TagKind_CallSiteParameter: { - // TODO - } break; - case DW_TagKind_Label: - case DW_TagKind_CompileUnit: - case DW_TagKind_UnspecifiedParameters: - case DW_TagKind_Namespace: - case DW_TagKind_ImportedDeclaration: - case DW_TagKind_PtrToMemberType: - case DW_TagKind_TemplateTypeParameter: - case DW_TagKind_ReferenceType: { - // TODO: - } break; - default: NotImplemented; break; + + RDIM_SymbolChunkList *var_chunks; U64 var_chunks_cap; + if (is_thread_var) { var_chunks = &tvars; var_chunks_cap = TVAR_CHUNK_CAP; } + else { var_chunks = &gvars; var_chunks_cap = GVAR_CHUNK_CAP; } + + RDIM_Symbol *var = rdim_symbol_chunk_list_push(arena, var_chunks, var_chunks_cap); + var->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); + var->name = name; + var->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); + var->type = type; + var->offset = voff; + var->container_symbol = 0; + var->container_type = 0; // TODO: NotImplemented; + } + } break; + case DW_TagKind_FormalParameter: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || parent_tag.kind == DW_TagKind_InlinedSubroutine) { + RDIM_Scope *scope = it->stack->next->scope; + RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); + param->kind = RDI_LocalKind_Parameter; + param->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + param->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + param->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + } else { + // TODO: error handling + AssertAlways(!"this is a local variable"); + } + } break; + case DW_TagKind_LexicalBlock: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || + parent_tag.kind == DW_TagKind_InlinedSubroutine || + parent_tag.kind == DW_TagKind_LexicalBlock) { + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + } + } break; + case DW_TagKind_CallSite: { + // TODO + } break; + case DW_TagKind_CallSiteParameter: { + // TODO + } break; + case DW_TagKind_Label: + case DW_TagKind_CompileUnit: + case DW_TagKind_UnspecifiedParameters: + case DW_TagKind_Namespace: + case DW_TagKind_ImportedDeclaration: + case DW_TagKind_PtrToMemberType: + case DW_TagKind_TemplateTypeParameter: + case DW_TagKind_ReferenceType: { + // TODO: + } break; + default: NotImplemented; break; } } scratch_end(scratch); @@ -2049,71 +2561,70 @@ internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params) { Temp scratch = scratch_begin(&arena, 1); - if (lane_idx() == 0) { //////////////////////////////// - + ProfBegin("compute exe hash"); U64 exe_hash = rdi_hash(params->exe_data.str, params->exe_data.size); ProfEnd(); - + //////////////////////////////// - + Arch arch = Arch_Null; U64 image_base = 0; DW_Input input = {0}; - + switch(params->exe_kind) { - default:{}break; - case ExecutableImageKind_CoffPe: { - PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); - String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); - COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(raw_sections, 0, sizeof(COFF_SectionHeader) * pe.section_count); - String8 string_table = str8_substr(params->exe_data, pe.string_table_range); - arch = pe.arch; - image_base = pe.image_base; - binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); - input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); - } break; - case ExecutableImageKind_Elf32: - case ExecutableImageKind_Elf64: { - ELF_Bin bin = elf_bin_from_data(scratch.arena, params->dbg_data); - arch = arch_from_elf_machine(bin.hdr.e_machine); - image_base = elf_base_addr_from_bin(&bin); - binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); - input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); - } break; + default:{}break; + case ExecutableImageKind_CoffPe: { + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); + String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); + COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(raw_sections, 0, sizeof(COFF_SectionHeader) * pe.section_count); + String8 string_table = str8_substr(params->exe_data, pe.string_table_range); + arch = pe.arch; + image_base = pe.image_base; + binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); + input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); + } break; + case ExecutableImageKind_Elf32: + case ExecutableImageKind_Elf64: { + ELF_Bin bin = elf_bin_from_data(scratch.arena, params->dbg_data); + arch = arch_from_elf_machine(bin.hdr.e_machine); + image_base = elf_base_addr_from_bin(&bin); + binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); + input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); + } break; } - + //////////////////////////////// - + top_level_info = rdim_make_top_level_info(params->exe_name, arch, exe_hash, binary_sections); - + //////////////////////////////// - + U64 arch_addr_size = rdi_addr_size_from_arch(top_level_info.arch); - + //////////////////////////////// - + RDIM_Scope *global_scope = rdim_scope_chunk_list_push(arena, &scopes, SCOPE_CHUNK_CAP); - + //////////////////////////////// - + ProfBegin("Parse Unit Contrib Map"); D2R_CompUnitContribMap cu_contrib_map = {0}; if (input.sec[DW_Section_ARanges].data.size) { cu_contrib_map = d2r_cu_contrib_map_from_aranges(arena, &input, image_base); } ProfEnd(); - + ProfBegin("Parse Comop Unit Ranges"); DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); Rng1U64List cu_range_list = dw_unit_ranges_from_data(scratch.arena, input.sec[DW_Section_Info].data); Rng1U64Array cu_ranges = rng1u64_array_from_list(scratch.arena, &cu_range_list); ProfEnd(); - + //////////////////////////////// - + ProfBegin("Parse Compile Unit Headers"); // TODO(rjf): parse should always be relaxed. any verification checks we do // should just be logged via log_info(...), and then the caller of this @@ -2124,9 +2635,9 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); } ProfEnd(); - + //////////////////////////////// - + ProfBegin("Parse Line Tables"); DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); for EachIndex(cu_idx, cu_ranges.count) { @@ -2137,15 +2648,15 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) cu_line_tables[cu_idx] = dw_parsed_line_table_from_data(scratch.arena, cu_stmt_list, &input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu); } ProfEnd(); - + //////////////////////////////// - + ProfBegin("Convert Line Tables"); HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); for EachIndex(cu_idx, cu_ranges.count) { cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); - + DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; @@ -2164,78 +2675,78 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } src_file_map[file_idx] = src_file; } - + for EachNode(line_seq, DW_LineSeqNode, line_table->first_seq) { if (line_seq->count == 0) { continue; } - + U64 *voffs = push_array(arena, U64, line_seq->count); U32 *line_nums = push_array(arena, U32, line_seq->count); U16 *col_nums = 0; U64 line_idx = 0; - + DW_LineNode *file_line_n = line_seq->first; U64 file_line_count = 0; - + for EachNode(line_n, DW_LineNode, file_line_n) { if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { U64 file_index = file_line_n->v.file_index; U64 *file_voffs = &voffs[line_idx]; U32 *file_line_nums = &line_nums[line_idx]; U16 *file_col_nums = 0; - + U64 lines_written = 0; U64 prev_ln = max_U64; DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; for (; file_line_n != sentinel; file_line_n = file_line_n->next) { if (file_line_n->v.line != prev_ln) { if (file_line_n->v.address == 0) { continue; } - + voffs[line_idx] = file_line_n->v.address - image_base; line_nums[line_idx] = file_line_n->v.line; - + ++lines_written; ++line_idx; - + prev_ln = file_line_n->v.line; } } - + RDIM_SrcFile *src_file = src_file_map[file_index]; RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, lines_written); rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); - + file_line_count = 1; } else { file_line_count += 1; } } - + // handle last line if (file_line_n) { U64 file_index = file_line_n->v.file_index; U64 *file_voffs = &voffs[line_idx]; U32 *file_line_nums = &line_nums[line_idx]; U16 *file_col_nums = 0; - + for (; file_line_n != 0; file_line_n = file_line_n->next, line_idx += 1) { // TODO: error handling AssertAlways(file_line_n->v.address >= image_base); voffs[line_idx] = file_line_n->v.address - image_base; line_nums[line_idx] = file_line_n->v.line; } - + RDIM_SrcFile *src_file = src_file_map[file_index]; RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, file_line_count); rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); } - + //Assert(line_idx == line_seq->count); } } ProfEnd(); - + //////////////////////////////// - + RDIM_Type *builtin_types[RDI_TypeKind_Count] = {0}; for (RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; type_kind <= RDI_TypeKind_LastBuiltIn; type_kind += 1) { RDIM_Type *type = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); @@ -2246,53 +2757,53 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } builtin_types[RDI_TypeKind_Void]->byte_size = arch_addr_size; builtin_types[RDI_TypeKind_Handle]->byte_size = arch_addr_size; - + builtin_types[RDI_TypeKind_Variadic] = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); builtin_types[RDI_TypeKind_Variadic]->kind = RDI_TypeKind_Variadic; - + //////////////////////////////// - + ProfBegin("Convert Units"); for EachIndex(cu_idx, cu_ranges.count) { Temp comp_temp = temp_begin(scratch.arena); - + DW_CompUnit *cu = &cu_arr[cu_idx]; - + // parse and build tag tree DW_TagTree tag_tree = dw_tag_tree_from_cu(comp_temp.arena, &input, cu); - + // skip DWO { if (cu->dwo_id) { goto next_cu; } - + String8 dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_DwoName); if (dwo_name.size) { goto next_cu; } - + String8 gnu_dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_GNU_DwoName); if (gnu_dwo_name.size) { goto next_cu; } } - + // build (info offset -> tag) hash table to resolve tags with abstract origin cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); - + // extract compile unit info String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); - + // init type table D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); type_table->ht = hash_table_init(comp_temp.arena, 0x4000); type_table->types = &types; type_table->type_chunk_cap = TYPE_CHUNK_CAP; type_table->builtin_types = builtin_types; - + // convert debug info d2r_convert_types(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); d2r_convert_udts(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); d2r_convert_symbols(arena, type_table, global_scope, &input, cu, cu_lang, arch_addr_size, image_base, arch, tag_tree.root); - + RDIM_Rng1U64ChunkList cu_voff_ranges = {0}; if (cu_idx < cu_contrib_map.count) { cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); @@ -2300,7 +2811,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // TODO: synthesize cu ranges from scopes NotImplemented; } - + // convert compile unit { RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); @@ -2314,15 +2825,15 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) unit->line_table = cu_line_tables_rdi[cu_idx]; unit->voff_ranges = cu_voff_ranges; } - + next_cu:; temp_end(comp_temp); } ProfEnd(); } - + lane_sync(); - + RDIM_BakeParams bake_params = {0}; bake_params.top_level_info = top_level_info; bake_params.binary_sections = binary_sections; @@ -2337,7 +2848,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) bake_params.procedures = procs; bake_params.scopes = scopes; bake_params.inline_sites = inline_sites; - + scratch_end(scratch); return bake_params; } diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index ae9155b0..c66d3e95 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -45,6 +45,48 @@ typedef struct D2R_CompUnitContribMap RDIM_Rng1U64ChunkList *voff_range_arr; } D2R_CompUnitContribMap; +#define D2R_ValueType_IsSigned(x) ((x) == D2R_ValueType_S8 || (x) == D2R_ValueType_S16 || (x) == D2R_ValueType_S32 || (x) == D2R_ValueType_S64 || (x) == D2R_ValueType_S128 || (x) == D2R_ValueType_S256 || (x) == D2R_ValueType_S512) +#define D2R_ValueType_IsUnsigned(x) ((x) == D2R_ValueType_U8 || (x) == D2R_ValueType_U16 || (x) == D2R_ValueType_U32 || (x) == D2R_ValueType_U64 || (x) == D2R_ValueType_U128 || (x) == D2R_ValueType_U256 || (x) == D2R_ValueType_U512) +#define D2R_ValueType_IsFloat(x) ((x) == D2R_ValueType_F32 || (x) == D2R_ValueType_F64) +#define D2R_ValueType_IsInt(x) (D2R_ValueType_IsSigned(x) || D2R_ValueType_IsUnsigned(x) || (x) == D2R_ValueType_Address) +typedef enum D2R_ValueType +{ + D2R_ValueType_Generic, + D2R_ValueType_U8, + D2R_ValueType_U16, + D2R_ValueType_U32, + D2R_ValueType_U64, + D2R_ValueType_U128, + D2R_ValueType_U256, + D2R_ValueType_U512, + D2R_ValueType_S8, + D2R_ValueType_S16, + D2R_ValueType_S32, + D2R_ValueType_S64, + D2R_ValueType_S128, + D2R_ValueType_S256, + D2R_ValueType_S512, + D2R_ValueType_F32, + D2R_ValueType_F64, + D2R_ValueType_Address, + D2R_ValueType_ImplicitValue, + D2R_ValueType_Bool = D2R_ValueType_S8, +} D2R_ValueType; + +typedef struct D2R_ValueTypeNode +{ + D2R_ValueType type; + + struct D2R_ValueTypeNode *next; +} D2R_ValueTypeNode; + +typedef struct D2R_ValueTypeStack +{ + U64 count; + D2R_ValueTypeNode *top; + D2R_ValueTypeNode *free_list; +} D2R_ValueTypeStack; + //////////////////////////////// //~ rjf: Enum Conversion Helpers @@ -66,10 +108,32 @@ internal RDI_TypeKind d2r_unsigned_type_kind_from_size(U64 byte_size); internal RDI_TypeKind d2r_signed_type_kind_from_size(U64 byte_size); internal RDI_EvalTypeGroup d2r_type_group_from_type_kind(RDI_TypeKind x); +//////////////////////////////// +//~ RDIM Bytecode Helpers + +internal B32 rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bc); +internal B32 rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc); +internal U64 rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base); + //////////////////////////////// //~ rjf: Bytecode Conversion Helpers -internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, B32 *is_addr_out); +internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type); +internal D2R_ValueType d2r_value_type_stack_pop(D2R_ValueTypeStack *stack); +internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack); + +internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size); +internal D2R_ValueType d2r_signed_value_type_from_bit_size(U64 bit_size); +internal D2R_ValueType d2r_float_type_from_bit_size(U64 bit_size); +internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v); +internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type); +internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs); + +internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc); +internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op); +internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op); + +internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out); internal RDIM_Location * d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr); internal RDIM_Location * d2r_location_from_attrib(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); internal RDIM_LocationCaseList d2r_locset_from_attrib(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); From 555f8ec6ff53c86553b179a6079af950e4aeb006 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 2 Oct 2025 18:02:57 -0700 Subject: [PATCH 039/133] grab ranges in compile unit tag for the unit vmap --- src/base/base_math.c | 11 +++++++++-- src/base/base_math.h | 3 ++- src/rdi_from_dwarf/rdi_from_dwarf.c | 21 +++++++++++++++------ src/rdi_from_dwarf/rdi_from_dwarf.h | 18 +++++++++--------- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/base/base_math.c b/src/base/base_math.c index 16e3ad28..266d6a45 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -708,12 +708,19 @@ rgba_from_u32(U32 hex) //~ rjf: List Type Functions internal void +rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n) +{ + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng) { Rng1U64Node *n = push_array(arena, Rng1U64Node, 1); MemoryCopyStruct(&n->v, &rng); - SLLQueuePush(list->first, list->last, n); - list->count += 1; + rng1u64_list_push_node(list, n); + return n; } internal void diff --git a/src/base/base_math.h b/src/base/base_math.h index 416dfeeb..37dd6c7a 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -678,7 +678,8 @@ internal Vec4F32 rgba_from_u32(U32 hex); //////////////////////////////// //~ rjf: List Type Functions -internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng); +internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n); +internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng); internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat); internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list); internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value); diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 89103aa1..1b9f61e4 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -169,13 +169,20 @@ internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag) { // collect non-contiguous range - Rng1U64List ranges = dw_rnglist_from_tag_attrib_kind(arena, input, cu, tag, DW_AttribKind_Ranges); + Rng1U64List raw_ranges = dw_rnglist_from_tag_attrib_kind(arena, input, cu, tag, DW_AttribKind_Ranges); + + // exclude invalid ranges caused by linker optimizations + Rng1U64List ranges = {0}; + for (Rng1U64Node *n = raw_ranges.first, *next = 0; n != 0; n = next) { + next = n->next; + if (n->v.min < image_base || n->v.min > n->v.max) { + continue; + } + rng1u64_list_push_node(&ranges, n); + } // debase ranges for EachNode(r, Rng1U64Node, ranges.first) { - // TODO: error handling - AssertAlways(r->v.min >= image_base); - AssertAlways(r->v.max >= image_base); r->v.min -= image_base; r->v.max -= image_base; } @@ -2808,8 +2815,10 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) if (cu_idx < cu_contrib_map.count) { cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); } else { - // TODO: synthesize cu ranges from scopes - NotImplemented; + Rng1U64List range_list = d2r_range_list_from_tag(scratch.arena, &input, cu, image_base, cu->tag); + for EachNode(n, Rng1U64Node, range_list.first) { + rdim_rng1u64_chunk_list_push(arena, &cu_voff_ranges, 512, (RDIM_Rng1U64){ .min = n->v.min, .max = n->v.max }); + } } // convert compile unit diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index c66d3e95..c394181e 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -119,19 +119,19 @@ internal U64 rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_ba //~ rjf: Bytecode Conversion Helpers internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type); -internal D2R_ValueType d2r_value_type_stack_pop(D2R_ValueTypeStack *stack); -internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack); +internal D2R_ValueType d2r_value_type_stack_pop(D2R_ValueTypeStack *stack); +internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack); -internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size); -internal D2R_ValueType d2r_signed_value_type_from_bit_size(U64 bit_size); -internal D2R_ValueType d2r_float_type_from_bit_size(U64 bit_size); +internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size); +internal D2R_ValueType d2r_signed_value_type_from_bit_size(U64 bit_size); +internal D2R_ValueType d2r_float_type_from_bit_size(U64 bit_size); internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v); -internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type); -internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs); +internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type); +internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs); internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc); -internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op); -internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op); +internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op); +internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op); internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out); internal RDIM_Location * d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr); From 9acff9ecd20269a13219c71da99c45dfac8bdca8 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 2 Oct 2025 18:06:50 -0700 Subject: [PATCH 040/133] use check sum defn from rdi.h --- src/linker/rdi/rdi_builder.h | 9 --------- src/linker/rdi/rdi_cv.c | 11 +++++------ 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/linker/rdi/rdi_builder.h b/src/linker/rdi/rdi_builder.h index 8afb0122..fa529f71 100644 --- a/src/linker/rdi/rdi_builder.h +++ b/src/linker/rdi/rdi_builder.h @@ -14,15 +14,6 @@ StaticAssert(sizeof(RDI_Header) == AlignPow2(sizeof(RDI_Header), 8), g_rdi_heade #define RDI_IsBuiltinType(x) (RDI_TypeKind_FirstBuiltIn <= (x) && (x) <= RDI_TypeKind_LastBuiltIn) #define RDI_IsPtrType(x) ((x) == RDI_TypeKind_Ptr || (x) == RDI_TypeKind_LRef || (x) == RDI_TypeKind_RRef) -typedef enum -{ - RDI_Checksum_Null, - RDI_Checksum_MD5, - RDI_Checksum_SHA1, - RDI_Checksum_SHA256, - RDI_Checksum_TimeStamp -} RDI_ChecksumKind; - //////////////////////////////// typedef enum diff --git a/src/linker/rdi/rdi_cv.c b/src/linker/rdi/rdi_cv.c index e5f31251..ac0b99f2 100644 --- a/src/linker/rdi/rdi_cv.c +++ b/src/linker/rdi/rdi_cv.c @@ -234,11 +234,10 @@ internal RDI_ChecksumKind rdi_checksum_from_cv_c13(CV_C13ChecksumKind kind) { switch (kind) { - case CV_C13ChecksumKind_Null: return RDI_Checksum_Null; - case CV_C13ChecksumKind_MD5: return RDI_Checksum_MD5; - case CV_C13ChecksumKind_SHA1: return RDI_Checksum_SHA1; - case CV_C13ChecksumKind_SHA256: return RDI_Checksum_SHA256; + case CV_C13ChecksumKind_Null: return RDI_ChecksumKind_NULL; + case CV_C13ChecksumKind_MD5: return RDI_ChecksumKind_MD5; + case CV_C13ChecksumKind_SHA1: return RDI_ChecksumKind_SHA1; + case CV_C13ChecksumKind_SHA256: return RDI_ChecksumKind_SHA256; } - InvalidPath; - return RDI_Checksum_Null; + return RDI_ChecksumKind_NULL; } From f8229a390d5ab691de3930374f01b3ac2862667e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 2 Oct 2025 18:15:27 -0700 Subject: [PATCH 041/133] merge conf fix --- src/rdi_from_dwarf/rdi_from_dwarf.c | 11 ----------- src/rdi_from_dwarf/rdi_from_dwarf.h | 1 - 2 files changed, 12 deletions(-) diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 1b9f61e4..19b6dc82 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -258,17 +258,6 @@ d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input //////////////////////////////// -internal B32 -rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bc) -{ - for EachNode(n, RDIM_EvalBytecodeOp, bc.first_op) { - if (n->op == RDI_EvalOp_TLSOff) { - return 1; - } - } - return 0; -} - internal B32 rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc) { diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index c394181e..5b297184 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -111,7 +111,6 @@ internal RDI_EvalTypeGroup d2r_type_group_from_type_kind(RDI_TypeKind x); //////////////////////////////// //~ RDIM Bytecode Helpers -internal B32 rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bc); internal B32 rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc); internal U64 rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base); From 073a0fcf3a6f1d2f9cc51cf804a1965e19f2c83d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 18:32:58 -0700 Subject: [PATCH 042/133] add checksum checking for timestamps; fix incorrect sha256 async checksum calculation; plug file-ood back in --- src/raddbg/raddbg_views.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 92f20e13..14cea6d4 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2053,7 +2053,7 @@ rd_sha256_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) U128 hash = {0}; str8_deserial_read_struct(key, 0, &hash); String8 data = c_data_from_hash(access, hash); - SHA1 sha256 = sha1_from_data(data); + SHA256 sha256 = sha256_from_data(data); StaticAssert(sizeof(result) >= sizeof(sha256), artifact_size_check); MemoryCopy(&result, &sha256, Min(sizeof(result), sizeof(sha256))); access_close(access); @@ -2299,7 +2299,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) checksum_kind = src->checksum_kind; RDI_SectionKind checksum_section_kind = rdi_section_kind_from_checksum_kind(checksum_kind); U64 checksum_size = rdi_section_element_size_table[checksum_section_kind]; - U8 *checksum_data = rdi_section_raw_element_from_kind_idx(rdi, checksum_section_kind, src->checksum_idx); + U8 *checksum_data = (U8 *)rdi_section_raw_element_from_kind_idx(rdi, checksum_section_kind, src->checksum_idx); checksum_expected = str8_copy(scratch.arena, str8(checksum_data, checksum_size)); break; } @@ -2332,30 +2332,15 @@ RD_VIEW_UI_FUNCTION_DEF(text) String8 sha256_string = str8_struct(&sha256); file_is_out_of_date = !str8_match(sha256_string, checksum_expected, 0); }break; + case RDI_ChecksumKind_Timestamp: + { + FileProperties props = os_properties_from_file_path(rd_regs()->file_path); + String8 timestamp_string = str8_struct(&props.modified); + file_is_out_of_date = !str8_match(timestamp_string, checksum_expected, 0); + }break; } - // TODO(rjf): turn this back on once done... - file_is_out_of_date = 0; - scratch_end(scratch); - - // TODO(rjf): @dbgi2 -#if 0 - U64 file_timestamp = os_properties_from_file_path(rd_regs()->file_path).modified; - if(file_timestamp != 0) - { - for(DI_KeyNode *n = dbgi_keys.first; n != 0; n = n->next) - { - DI_Key key = n->v; - if(key.min_timestamp < file_timestamp && key.min_timestamp != 0 && key.path.size != 0) - { - file_is_out_of_date = 1; - out_of_date_dbgi_name = str8_skip_last_slash(key.path); - break; - } - } - } -#endif } ////////////////////////////// From 32e344c8061d2152707938a55d26d0ad74958e6a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 2 Oct 2025 18:33:58 -0700 Subject: [PATCH 043/133] remove dbgi name from ood warning --- src/raddbg/raddbg_views.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 14cea6d4..beb48052 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2257,7 +2257,6 @@ RD_VIEW_UI_FUNCTION_DEF(text) //- rjf: determine if file is out-of-date // B32 file_is_out_of_date = 0; - String8 out_of_date_dbgi_name = {0}; { Temp scratch = scratch_begin(0, 0); @@ -2367,9 +2366,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) { UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(1, 1)) UI_TextPadding(0) { - UI_TagF("weak") ui_labelf("This file has changed since "); - ui_label(out_of_date_dbgi_name); - UI_TagF("weak") ui_labelf(" was produced."); + UI_TagF("weak") ui_labelf("This file has changed since it was compiled."); } } } From b1b83c4e3d3ea6a66040f4301596e17a89c7d339 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 3 Oct 2025 17:16:45 -0700 Subject: [PATCH 044/133] bugfix const64 interp --- src/dwarf/dwarf_parse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index a963145d..b944156a 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -982,7 +982,7 @@ internal U64 dw_interp_const64(U64 type_byte_size, DW_ATE type_encoding, DW_FormKind form_kind, DW_Form form) { U64 result = max_U64; - if (form_kind == DW_Form_Data1 || form_kind == DW_Form_Data2 || form_kind == DW_Form_Data4 || form_kind == DW_Form_Data16) { + if (form_kind == DW_Form_Data1 || form_kind == DW_Form_Data2 || form_kind == DW_Form_Data4 || form_kind == DW_Form_Data8 || form_kind == DW_Form_Data16) { if (form.data.size <= sizeof(result)) { if (!dw_try_u64_from_const_value(type_byte_size, type_encoding, form.data, &result)) { Assert(!"unable to decode data"); @@ -1007,7 +1007,7 @@ dw_interp_const64(U64 type_byte_size, DW_ATE type_encoding, DW_FormKind form_kin internal U64 dw_interp_const_u64(DW_FormKind form_kind, DW_Form form) { - return dw_interp_const64(DW_ATE_Unsigned, sizeof(U64), form_kind, form); + return dw_interp_const64(sizeof(U64), DW_ATE_Unsigned, form_kind, form); } internal U32 From da0028033daee2fe44c2b85cc8fd0d48c5861707 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 3 Oct 2025 20:10:09 -0700 Subject: [PATCH 045/133] changed dumper to print .debug_info in more compact form --- src/dwarf/dwarf_dump.c | 361 +++++++++++++++++++++++------------------ 1 file changed, 204 insertions(+), 157 deletions(-) diff --git a/src/dwarf/dwarf_dump.c b/src/dwarf/dwarf_dump.c index 9a1a784e..21452a46 100644 --- a/src/dwarf/dwarf_dump.c +++ b/src/dwarf/dwarf_dump.c @@ -1548,6 +1548,144 @@ dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_In //////////////////////////////// //~ rjf: Dump Entry Point +internal String8 +dw_string_from_attrib_value(Arena *arena, DW_Input *input, Arch arch, DW_CompUnit *unit, DW_LineVMHeader *line_vm, DW_Attrib *attrib) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8List attrib_fmt = {0}; + + // rjf: log attrib's value based on vlass + DW_AttribClass value_class = dw_value_class_from_attrib(unit, attrib); + switch(value_class) + { + default: {str8_list_pushf(scratch.arena, &attrib_fmt, "`unknown value class`");}break; + case DW_AttribClass_Undefined: {str8_list_pushf(scratch.arena, &attrib_fmt, "`undefined value class`");}break; + case DW_AttribClass_Address: {str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", dw_address_from_attrib(input, unit, attrib));}break; + case DW_AttribClass_Const: {str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", dw_const_u64_from_attrib(input, unit, attrib));}break; + case DW_AttribClass_Block: + { + String8 block = dw_block_from_attrib(input, unit, attrib); + String8List block_strs = numeric_str8_list_from_data(scratch.arena, 16, block, 1); + String8 block_str = str8_list_join(scratch.arena, &block_strs, &(StringJoin){.sep = str8_lit(", ")}); + str8_list_pushf(scratch.arena, &attrib_fmt, "{ %S }", block_str); + }break; + case DW_AttribClass_ExprLoc: + { + String8 exprloc = dw_exprloc_from_attrib(input, unit, attrib); + String8 exprloc_str = dw_single_line_string_from_expression(scratch.arena, exprloc, unit->info_range.min, unit->address_size, arch, unit->version, unit->ext, unit->format); + str8_list_pushf(scratch.arena, &attrib_fmt, "{ %S }", exprloc_str); + }break; + case DW_AttribClass_Flag: + { + B32 flag = dw_flag_from_attrib(input, unit, attrib); + str8_list_pushf(scratch.arena, &attrib_fmt, "%llu (%s)", flag, flag == 0 ? "false" : "true"); + }break; + case DW_AttribClass_LinePtr: + case DW_AttribClass_LocListPtr: + case DW_AttribClass_MacPtr: + case DW_AttribClass_RngListPtr: + case DW_AttribClass_RngList: + case DW_AttribClass_StrOffsetsPtr: + case DW_AttribClass_AddrPtr: + { + if(attrib->form_kind == DW_Form_SecOffset) + { + str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", attrib->form.sec_offset); + } + else + { + str8_list_pushf(scratch.arena, &attrib_fmt, "`unexpected form kind %S`", dw_string_from_form_kind(scratch.arena, unit->version, attrib->form_kind)); + } + }break; + case DW_AttribClass_Reference: + { + if(attrib->form_kind == DW_Form_Ref1 || + attrib->form_kind == DW_Form_Ref2 || + attrib->form_kind == DW_Form_Ref4 || + attrib->form_kind == DW_Form_Ref8 || + attrib->form_kind == DW_Form_RefUData) + { + U64 info_off = unit->info_range.min + attrib->form.ref; + str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", info_off); + if(!contains_1u64(unit->info_range, info_off)) + { + str8_list_pushf(scratch.arena, &attrib_fmt, ": `(out of this unit's bounds)`"); + } + } + else + { + str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", attrib->form.ref); + } + }break; + case DW_AttribClass_String: + { + if(attrib->form_kind == DW_Form_Strp || attrib->form_kind == DW_Form_LineStrp || attrib->form_kind == DW_Form_StrpSup) + { + str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x ", attrib->form.sec_offset); + } + String8 string = dw_string_from_attrib(input, unit, attrib); + str8_list_pushf(scratch.arena, &attrib_fmt, "\"%S\"", string); + }break; + } + + // rjf: extend attrib's value with enum info + { + String8 enum_info = {0}; + switch(attrib->attrib_kind) + { + case DW_AttribKind_Language: + { + DW_Language lang = dw_const_u64_from_attrib(input, unit, attrib); + enum_info = dw_string_from_language(scratch.arena, lang); + }break; + case DW_AttribKind_DeclFile: + { + U64 file_idx = dw_const_u64_from_attrib(input, unit, attrib); + DW_LineFile *file = dw_file_from_attrib(unit, line_vm, attrib); + if(file != 0) + { + enum_info = dw_path_from_file(scratch.arena, line_vm, file); + } + }break; + case DW_AttribKind_DeclLine: + { + enum_info = str8f(scratch.arena, "%I64u", dw_const_u64_from_attrib(input, unit, attrib)); + }break; + case DW_AttribKind_Inline: + { + DW_InlKind inl = dw_const_u64_from_attrib(input, unit, attrib); + enum_info = dw_string_from_inl(scratch.arena, inl); + }break; + case DW_AttribKind_Accessibility: + { + DW_AccessKind access = dw_const_u64_from_attrib(input, unit, attrib); + enum_info = dw_string_from_access_kind(scratch.arena, access); + }break; + case DW_AttribKind_CallingConvention: + { + DW_CallingConventionKind calling_convetion = dw_const_u64_from_attrib(input, unit, attrib); + enum_info = dw_string_from_calling_convetion(scratch.arena, calling_convetion); + }break; + case DW_AttribKind_Encoding: + { + DW_ATE encoding = dw_const_u64_from_attrib(input, unit, attrib); + enum_info = dw_string_from_attrib_type_encoding(scratch.arena, encoding); + }break; + } + + if(enum_info.size) + { + str8_list_pushf(scratch.arena, &attrib_fmt, " `%S`", enum_info); + } + } + + String8 result = str8_list_join(arena, &attrib_fmt, 0); + + scratch_end(scratch); + return result; +} + internal String8List dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubsetFlags subset_flags) { @@ -1559,39 +1697,51 @@ dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubs Temp scratch = scratch_begin(&arena, 1); Rng1U64Array segment_vranges = {0}; DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, input); - Rng1U64List unit_ranges_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data); - Rng1U64Array unit_ranges = rng1u64_array_from_list(scratch.arena, &unit_ranges_list); B32 relaxed = 1; + + DW_CompUnit *cu_arr; + { + DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, input); + Rng1U64List cu_range_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data); + Rng1U64Array cu_ranges = rng1u64_array_from_list(scratch.arena, &cu_range_list); + cu_arr = push_array(scratch.arena, DW_CompUnit, cu_ranges.count); + for EachIndex(cu_idx, cu_ranges.count) + { + cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, input, lu_input, cu_ranges.v[cu_idx].min, relaxed); + } + } ////////////////////////////// //- rjf: dump .debug_info // DumpSubset(DebugInfo) { + Rng1U64List unit_ranges_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data); + Rng1U64Array unit_ranges = rng1u64_array_from_list(scratch.arena, &unit_ranges_list); for EachIndex(unit_idx, unit_ranges.count) { Temp unit_temp = temp_begin(scratch.arena); //- rjf: unpack unit Rng1U64 unit_range = unit_ranges.v[unit_idx]; - DW_CompUnit unit = dw_cu_from_info_off(unit_temp.arena, input, lu_input, unit_range.min, relaxed); - String8 unit_dir = dw_string_from_tag_attrib_kind(input, &unit, unit.tag, DW_AttribKind_CompDir ); - String8 unit_name = dw_string_from_tag_attrib_kind(input, &unit, unit.tag, DW_AttribKind_Name ); - String8 stmt_list = dw_line_ptr_from_tag_attrib_kind(input, &unit, unit.tag, DW_AttribKind_StmtList); + DW_CompUnit *unit = &cu_arr[unit_idx]; + String8 unit_dir = dw_string_from_tag_attrib_kind(input, unit, unit->tag, DW_AttribKind_CompDir ); + String8 unit_name = dw_string_from_tag_attrib_kind(input, unit, unit->tag, DW_AttribKind_Name ); + String8 stmt_list = dw_line_ptr_from_tag_attrib_kind(input, unit, unit->tag, DW_AttribKind_StmtList); DW_LineVMHeader line_vm = {0}; - dw_read_line_vm_header(unit_temp.arena, stmt_list, 0, input, unit_dir, unit_name, unit.address_size, unit.str_offsets_lu, &line_vm); + dw_read_line_vm_header(unit_temp.arena, stmt_list, 0, input, unit_dir, unit_name, unit->address_size, unit->str_offsets_lu, &line_vm); //- rjf: log top-level unit info dumpf("unit: // compile_unit[%I64u]\n{\n", unit_idx); - dumpf(" version: %u\n", unit.version); - dumpf(" address_size: %I64u\n", unit.address_size); - dumpf(" abbrev_off: 0x%I64x\n", unit.abbrev_off); - dumpf(" info_range: [0x%I64x, 0x%I64x) // (%M)\n", unit.info_range.min, unit.info_range.max, dim_1u64(unit.info_range)); + dumpf(" version: %u\n", unit->version); + dumpf(" address_size: %I64u\n", unit->address_size); + dumpf(" abbrev_off: 0x%I64x\n", unit->abbrev_off); + dumpf(" info_range: [0x%I64x, 0x%I64x) // (%M)\n", unit->info_range.min, unit->info_range.max, dim_1u64(unit->info_range)); //- rjf: log tags S64 tag_depth = 0; U64 tag_idx = 0; - for(U64 info_off = unit.first_tag_info_off; info_off < unit.info_range.max; tag_idx += 1) + for(U64 info_off = unit->first_tag_info_off; info_off < unit->info_range.max; tag_idx += 1) { Temp tag_temp = temp_begin(scratch.arena); @@ -1599,152 +1749,46 @@ dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubs String8 tag_indent = str8_prefix(indent, (tag_depth+1)*2); U64 tag_info_off = info_off; DW_Tag tag = {0}; - info_off += dw_read_tag_cu(tag_temp.arena, input, &unit, tag_info_off, &tag); + info_off += dw_read_tag_cu(tag_temp.arena, input, unit, tag_info_off, &tag); // rjf: log top-level tag info - dumpf("%Stag: // compile_unit[%I64u].tag[%I64u]\n%S{\n", tag_indent, unit_idx, tag_idx, tag_indent); - dumpf("%S kind: %S\n", tag_indent, dw_string_from_tag_kind(tag_temp.arena, tag.kind)); - dumpf("%S info_off: 0x%I64x\n", tag_indent, tag_info_off); - dumpf("%S abbrev_id: %I64u\n", tag_indent, tag.abbrev_id); + dumpf("%Stag: // info_off: 0x%I64x, abbrev_id: %I64u, compile_unit[%I64u].tag[%I64u]\n%S{\n", tag_indent, tag_info_off, tag.abbrev_id, unit_idx, tag_idx, tag_indent); + dumpf("%S kind: %S\n", tag_indent, dw_string_from_tag_kind(tag_temp.arena, tag.kind)); - // rjf: log attribs - for(DW_AttribNode *attrib_n = tag.attribs.first; - attrib_n != 0; - attrib_n = attrib_n->next) + // log attribs { - Temp attrib_temp = temp_begin(tag_temp.arena); - DW_Attrib *attrib = &attrib_n->v; - - // rjf: log attrib begin - dumpf("%S attrib: {"); - - // rjf: log basic info - dumpf(" off: 0x%I64x", attrib->info_off); - dumpf(", kind: %S", dw_string_from_attrib_kind(attrib_temp.arena, unit.version, unit.ext, attrib->attrib_kind)); - dumpf(", form_kind: %S", dw_string_from_form_kind(attrib_temp.arena, unit.version, attrib->form_kind)); - - // rjf: log attrib's value based on vlass - dumpf(", "); - DW_AttribClass value_class = dw_value_class_from_attrib(&unit, attrib); - switch(value_class) + // compute columns' max widths + U64 attrib_name_max_size = 0, form_kind_max_size = 0, value_max_size = 0; + for EachNode(attrib_n, DW_AttribNode, tag.attribs.first) { - default: {dumpf("`unknown value class`");}break; - case DW_AttribClass_Undefined: {dumpf("`undefined value class`");}break; - case DW_AttribClass_Address: {dumpf("0x%I64x", dw_address_from_attrib(input, &unit, attrib));}break; - case DW_AttribClass_Const: {dumpf("0x%I64x", dw_const_u64_from_attrib(input, &unit, attrib));}break; - case DW_AttribClass_Block: - { - String8 block = dw_block_from_attrib(input, &unit, attrib); - String8List block_strs = numeric_str8_list_from_data(attrib_temp.arena, 16, block, 1); - String8 block_str = str8_list_join(attrib_temp.arena, &block_strs, &(StringJoin){.sep = str8_lit(", ")}); - dump(block_str); - }break; - case DW_AttribClass_ExprLoc: - { - String8 exprloc = dw_exprloc_from_attrib(input, &unit, attrib); - String8 exprloc_str = dw_single_line_string_from_expression(attrib_temp.arena, exprloc, unit_range.min, unit.address_size, arch, unit.version, unit.ext, unit.format); - dump(exprloc_str); - }break; - case DW_AttribClass_Flag: - { - B32 flag = dw_flag_from_attrib(input, &unit, attrib); - dumpf("%llu: %s", flag, flag == 0 ? "false" : "true"); - }break; - case DW_AttribClass_LinePtr: - case DW_AttribClass_LocListPtr: - case DW_AttribClass_MacPtr: - case DW_AttribClass_RngListPtr: - case DW_AttribClass_RngList: - case DW_AttribClass_StrOffsetsPtr: - case DW_AttribClass_AddrPtr: - { - if(attrib->form_kind == DW_Form_SecOffset) - { - dumpf("0x%I64x", attrib->form.sec_offset); - } - else - { - dumpf("`unexpected form kind %S`", dw_string_from_form_kind(attrib_temp.arena, unit.version, attrib->form_kind)); - } - }break; - case DW_AttribClass_Reference: - { - if(attrib->form_kind == DW_Form_Ref1 || - attrib->form_kind == DW_Form_Ref2 || - attrib->form_kind == DW_Form_Ref4 || - attrib->form_kind == DW_Form_Ref8 || - attrib->form_kind == DW_Form_RefUData) - { - U64 info_off = unit.info_range.min + attrib->form.ref; - dumpf("0x%I64x", info_off); - if(!contains_1u64(unit.info_range, attrib->form.ref)) - { - dumpf(": `(out of this unit's bounds)`"); - } - } - else - { - dumpf("0x%I64x", attrib->form.ref); - } - }break; - case DW_AttribClass_String: - { - if(attrib->form_kind == DW_Form_Strp) - { - dumpf("0x%I64x", attrib->form.sec_offset); - } - String8 string = dw_string_from_attrib(input, &unit, attrib); - dumpf(": \"%S\"", string); - }break; + Temp attrib_temp = temp_begin(tag_temp.arena); + attrib_name_max_size = Max(attrib_name_max_size, dw_string_from_attrib_kind(attrib_temp.arena, unit->version, unit->ext, attrib_n->v.attrib_kind).size); + form_kind_max_size = Max(form_kind_max_size, dw_string_from_form_kind(attrib_temp.arena, unit->version, attrib_n->v.form_kind).size); + value_max_size = Max(value_max_size, dw_string_from_attrib_value(attrib_temp.arena, input, arch, unit, &line_vm, &attrib_n->v).size); + temp_end(attrib_temp); } - - // rjf: extend attrib's value with enum info - switch(attrib->attrib_kind) + value_max_size = Min(120, value_max_size); + + // log + for EachNode(attrib_n, DW_AttribNode, tag.attribs.first) { - case DW_AttribKind_Language: - { - DW_Language lang = dw_const_u64_from_attrib(input, &unit, attrib); - dumpf(": %S", dw_string_from_language(attrib_temp.arena, lang)); - }break; - case DW_AttribKind_DeclFile: - { - U64 file_idx = dw_const_u64_from_attrib(input, &unit, attrib); - DW_LineFile *file = dw_file_from_attrib(&unit, &line_vm, attrib); - if(file != 0) - { - dumpf(": %S", dw_path_from_file(attrib_temp.arena, &line_vm, file)); - } - }break; - case DW_AttribKind_DeclLine: - { - dumpf(": %I64u", dw_const_u64_from_attrib(input, &unit, attrib)); - }break; - case DW_AttribKind_Inline: - { - DW_InlKind inl = dw_const_u64_from_attrib(input, &unit, attrib); - dumpf(": %S", dw_string_from_inl(attrib_temp.arena, inl)); - }break; - case DW_AttribKind_Accessibility: - { - DW_AccessKind access = dw_const_u64_from_attrib(input, &unit, attrib); - dumpf(": %S", dw_string_from_access_kind(attrib_temp.arena, access)); - }break; - case DW_AttribKind_CallingConvention: - { - DW_CallingConventionKind calling_convetion = dw_const_u64_from_attrib(input, &unit, attrib); - dumpf(": %S", dw_string_from_calling_convetion(attrib_temp.arena, calling_convetion)); - }break; - case DW_AttribKind_Encoding: - { - DW_ATE encoding = dw_const_u64_from_attrib(input, &unit, attrib); - dumpf(": %S", dw_string_from_attrib_type_encoding(attrib_temp.arena, encoding)); - }break; + DW_Attrib *attrib = &attrib_n->v; + + Temp attrib_temp = temp_begin(tag_temp.arena); + + String8 attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, unit->version, unit->ext, attrib->attrib_kind); + String8 form_kind_str = dw_string_from_form_kind(attrib_temp.arena, unit->version, attrib->form_kind); + String8 value_str = dw_string_from_attrib_value(attrib_temp.arena, input, arch, unit, &line_vm, attrib); + + dumpf("%S attrib: { kind: %S, %.*sform_kind: %S, %.*svalue: %S, %.*s} // info_off: 0x%I64x\n", + tag_indent, + attrib_kind_str, attrib_name_max_size - attrib_kind_str.size, indent.str, + form_kind_str, form_kind_max_size - form_kind_str.size, indent.str, + value_str, value_str.size < value_max_size ? value_max_size - value_str.size: 0, indent.str, + attrib->info_off, unit_idx, tag_idx); + + temp_end(attrib_temp); } - - // rjf: log attrib end - dumpf(" }\n"); - - temp_end(attrib_temp); } // rjf: log tag closes @@ -1758,7 +1802,7 @@ dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubs { tag_depth += 1; } - if(tag.abbrev_id) + if(!tag.abbrev_id) { tag_depth -= 1; } @@ -1822,17 +1866,20 @@ dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubs // DumpSubset(DebugLine) { + Rng1U64List unit_ranges_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Line].data); + Rng1U64Array unit_ranges = rng1u64_array_from_list(scratch.arena, &unit_ranges_list); for EachIndex(unit_idx, unit_ranges.count) { Temp unit_temp = temp_begin(scratch.arena); // rjf: unpack unit - String8 unit_data = str8_substr(input->sec[DW_Section_Line].data, unit_ranges.v[unit_idx]); - String8 cu_dir = {0}; - String8 cu_name = {0}; - DW_ListUnit cu_str_offsets = {0}; + String8 raw_lines = str8_substr(input->sec[DW_Section_Line].data, unit_ranges.v[unit_idx]); + DW_CompUnit *cu = &cu_arr[unit_idx]; + String8 cu_stmt_list = dw_line_ptr_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_StmtList); + String8 cu_dir = dw_string_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_CompDir); + String8 cu_name = dw_string_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_Name); DW_LineVMHeader line_vm = {0}; - U64 line_vm_size = dw_read_line_vm_header(unit_temp.arena, unit_data, 0, input, cu_dir, cu_name, line_vm.address_size, &cu_str_offsets, &line_vm); + U64 line_vm_size = dw_read_line_vm_header(unit_temp.arena, raw_lines, 0, input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu, &line_vm); if(line_vm_size == 0) { continue; @@ -1892,7 +1939,7 @@ dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubs // rjf: log opcodes DeferLoop(dumpf(" opcodes:\n {\n"), dumpf(" }\n\n")) { - String8 opcodes = str8_skip(unit_data, line_vm_size); + String8 opcodes = str8_skip(raw_lines, line_vm_size); B32 end_of_seq = 0; DW_LineVMState vm_state = {0}; dw_line_vm_reset(&vm_state, line_vm.default_is_stmt); From 811f316ca2f2588c91912ecf2a75d80d140eb4cf Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 11:20:12 -0700 Subject: [PATCH 046/133] fix clang warnings in dwarf -> rdi --- src/rdi_from_dwarf/rdi_from_dwarf.c | 3133 ++++++++++++++------------- 1 file changed, 1568 insertions(+), 1565 deletions(-) diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 19b6dc82..81a3d30a 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -8,7 +8,7 @@ // [ ] Error handling //////////////////////////////// - + static const U64 UNIT_CHUNK_CAP = 256; static const U64 UDT_CHUNK_CAP = 256; static const U64 TYPE_CHUNK_CAP = 256; @@ -170,7 +170,7 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag { // collect non-contiguous range Rng1U64List raw_ranges = dw_rnglist_from_tag_attrib_kind(arena, input, cu, tag, DW_AttribKind_Ranges); - + // exclude invalid ranges caused by linker optimizations Rng1U64List ranges = {0}; for (Rng1U64Node *n = raw_ranges.first, *next = 0; n != 0; n = next) { @@ -193,7 +193,7 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_HighPc); if (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) { U64 lo_pc = dw_address_from_attrib(input, cu, lo_pc_attrib); - + U64 hi_pc = 0; DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); if (hi_pc_class == DW_AttribClass_Address) { @@ -204,7 +204,7 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag } else { AssertAlways(!"unexpected attribute encoding"); } - + if (lo_pc >= image_base && hi_pc >= image_base) { if (lo_pc < hi_pc) { rng1u64_list_push(arena, &ranges, rng_1u64(lo_pc - image_base, hi_pc - image_base)); @@ -214,8 +214,8 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag } else { // invalid low and hi PC are likely are caused by an optimization pass during linking } - } else if (lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null || - lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null) { + } else if ((lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) || + (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null)) { // TODO: error handling } } @@ -279,11 +279,11 @@ internal U64 rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) { Temp scratch = scratch_begin(0,0); - + typedef union { U16 u16; U32 u32; U64 u64; S64 s64; F32 f32; F64 f64; } Value; U64 stack_cap = 128, stack_count = 0; Value *stack = push_array(scratch.arena, Value, stack_cap); - + for EachNode(opcode_n, RDIM_EvalBytecodeOp, bc.first_op) { // pop values from stack Value *svals = 0; @@ -297,330 +297,330 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) stack_count -= pop_count; svals = stack + stack_count; } - + Value imm = { .u64 = opcode_n->p }; Value nval = {0}; switch (opcode_n->op) { - case RDI_EvalOp_Stop: { opcode_n = bc.last_op; } break; - case RDI_EvalOp_Noop: {} break; - case RDI_EvalOp_Cond: { NotImplemented; } break; - case RDI_EvalOp_Skip: { - NotImplemented; - } break; - case RDI_EvalOp_MemRead: { InvalidPath; } break; - case RDI_EvalOp_RegRead: { NotImplemented; } break; - case RDI_EvalOp_RegReadDyn: { NotImplemented; } break; - case RDI_EvalOp_FrameOff: { NotImplemented; } break; - case RDI_EvalOp_ModuleOff: { - nval.u64 = image_base + imm.u64; - } break; - case RDI_EvalOp_TLSOff: { - nval.u64 = image_base; - } break; - case RDI_EvalOp_ConstU8: - case RDI_EvalOp_ConstU16: - case RDI_EvalOp_ConstU32: - case RDI_EvalOp_ConstU64: - case RDI_EvalOp_ConstU128: { - nval = imm; - } break; - case RDI_EvalOp_ConstString: { NotImplemented; } break; - case RDI_EvalOp_Abs: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: - case RDI_EvalTypeGroup_S: { nval.s64 = abs_s64(svals[0].s64); } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = abs_f32(svals[0].f32); } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = abs_f64(svals[0].f64); } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Neg: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: - case RDI_EvalTypeGroup_S: { nval.u64 = ~svals[0].u64 + 1; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = -svals[0].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = -svals[0].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Add: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 + svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 + svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 + svals[1].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 + svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Sub: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 - svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[1].s64 - svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 - svals[1].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 - svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Mul: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 * svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 * svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 * svals[1].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 * svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Div: { - B32 is_div_by_zero = 0; - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { is_div_by_zero = svals[1].u64 == 0; } break; - case RDI_EvalTypeGroup_S: { is_div_by_zero = svals[1].s64 == 0; } break; - case RDI_EvalTypeGroup_F32: { is_div_by_zero = svals[1].f32 == 0.0f; } break; - case RDI_EvalTypeGroup_F64: { is_div_by_zero = svals[1].f64 == 0.0; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - - // TODO: report error - AssertAlways(!is_div_by_zero); - - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 / svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 / svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 / svals[1].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 / svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Mod: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 % svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 % svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 MOD is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 MOD is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_LShift: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 << svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 << svals[1].u64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 LShift is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 LShift is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_RShift: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 >> svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[1].s64 >> svals[1].u64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 RShift is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 RShift is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_BitAnd: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 | svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 | svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 bitwise AND is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 bitwise AND is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_BitXor: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 ^ svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 ^ svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 XOR is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 XOR is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_BitNot: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = ~svals[0].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = ~svals[0].u64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 bitwise NOT is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 bitwise NOT is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_LogAnd: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 && svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 && svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 AND is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 AND is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_LogOr: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 || svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 || svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 OR is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 OR is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_LogNot: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = !svals[0].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = !svals[0].u64; } break; - case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 NOT is not supported"); } break; // TODO: report error - case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 NOT is not supported"); } break; // TODO: report error - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_EqEq: { - nval.u64 = !!MemoryMatch(&svals[0], &svals[1], sizeof(*svals)); - } break; - case RDI_EvalOp_NtEq: { - nval.u64 = !MemoryMatch(&svals[0], &svals[1], sizeof(*svals)); - } break; - case RDI_EvalOp_LsEq: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 <= svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 <= svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 <= svals[1].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 <= svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_GrEq: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 >= svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 >= svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 >= svals[1].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 >= svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Less: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 < svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 < svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 < svals[1].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 < svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Grtr: { - switch (imm.u64) { - case RDI_EvalTypeGroup_Other: {} break; - case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 > svals[1].u64; } break; - case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 > svals[1].s64; } break; - case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 > svals[1].f32; } break; - case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 > svals[1].f64; } break; - default: { AssertAlways(!"unexpected eval type group"); } break; // report error - } - } break; - case RDI_EvalOp_Trunc: { - if (0 < imm.u64 && imm.u64 < 64) { - U64 mask = max_U64 >> (64 - imm.u64); - nval.u64 = svals[0].u64 & (max_U64 >> (64 - imm.u64)); - } else if (imm.u64 > 64) { - // TODO: report error - AssertAlways(!"malformed bytecode"); - } - } break; - case RDI_EvalOp_TruncSigned: { - if (0 < imm.u64 && imm.u64 < 64) { - U64 mask = max_U64 >> (64 - imm.u64); - nval.u64 = svals[0].u64 & (max_U64 >> (64 - imm.u64)); - U64 high = 0; - if (svals[0].u64 & (1 << (imm.u64 - 1))) { - high = ~mask; + case RDI_EvalOp_Stop: { opcode_n = bc.last_op; } break; + case RDI_EvalOp_Noop: {} break; + case RDI_EvalOp_Cond: { NotImplemented; } break; + case RDI_EvalOp_Skip: { + NotImplemented; + } break; + case RDI_EvalOp_MemRead: { InvalidPath; } break; + case RDI_EvalOp_RegRead: { NotImplemented; } break; + case RDI_EvalOp_RegReadDyn: { NotImplemented; } break; + case RDI_EvalOp_FrameOff: { NotImplemented; } break; + case RDI_EvalOp_ModuleOff: { + nval.u64 = image_base + imm.u64; + } break; + case RDI_EvalOp_TLSOff: { + nval.u64 = image_base; + } break; + case RDI_EvalOp_ConstU8: + case RDI_EvalOp_ConstU16: + case RDI_EvalOp_ConstU32: + case RDI_EvalOp_ConstU64: + case RDI_EvalOp_ConstU128: { + nval = imm; + } break; + case RDI_EvalOp_ConstString: { NotImplemented; } break; + case RDI_EvalOp_Abs: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: + case RDI_EvalTypeGroup_S: { nval.s64 = abs_s64(svals[0].s64); } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = abs_f32(svals[0].f32); } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = abs_f64(svals[0].f64); } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error } - nval.u64 = high | (svals[0].u64 & mask); - } else if (imm.u64 > 64) { - // TODO: report error - AssertAlways(!"malformed bytecode"); - } - } break; - case RDI_EvalOp_Convert: { - U32 in = imm.u64 & 0xff; - U32 out = (imm.u64 >> 8) & 0xff; - if (in != out) { - switch (in + out*RDI_EvalTypeGroup_COUNT) { - case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f32; } break; - case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f64; } break; - case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f32; } break; - case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f64; } break; - case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].u64; } break; - case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].s64; } break; - case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].f64; } break; - case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].u64; } break; - case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].s64; } break; - case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].f32; } break; - default: { Assert(!"unexpected conversion case"); } break; // report error + } break; + case RDI_EvalOp_Neg: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: + case RDI_EvalTypeGroup_S: { nval.u64 = ~svals[0].u64 + 1; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = -svals[0].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = -svals[0].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error } - } - } break; - case RDI_EvalOp_Pick: { - if (stack_count > imm.u64) { - nval = stack[stack_count - imm.u64 - 1]; - } else { + } break; + case RDI_EvalOp_Add: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 + svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 + svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 + svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 + svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Sub: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 - svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[1].s64 - svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 - svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 - svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Mul: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 * svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 * svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 * svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 * svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Div: { + B32 is_div_by_zero = 0; + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { is_div_by_zero = svals[1].u64 == 0; } break; + case RDI_EvalTypeGroup_S: { is_div_by_zero = svals[1].s64 == 0; } break; + case RDI_EvalTypeGroup_F32: { is_div_by_zero = svals[1].f32 == 0.0f; } break; + case RDI_EvalTypeGroup_F64: { is_div_by_zero = svals[1].f64 == 0.0; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + // TODO: report error - AssertAlways(!"malformed bytecode"); - } - } break; - case RDI_EvalOp_Pop: {} break; - case RDI_EvalOp_Insert: { - if (stack_count > imm.u64) { - Value tval = stack[stack_count-1]; - Value *dst = stack + stack_count - 1 - imm.u64; - Value *shift = dst + 1; - MemoryCopy(shift, dst, imm.u64 * sizeof(Value)); - *dst = tval; - } else { - // TODO: report error - AssertAlways(!"malformed bytecode"); - } - } break; - case RDI_EvalOp_ValueRead: { - U64 bytes_to_read = imm.u64; - U64 offset = svals[0].u64; - if (offset + bytes_to_read <= sizeof(Value)) { - Value src_val = svals[1]; - MemoryCopy(&nval, (U8 *)&src_val + offset, bytes_to_read); - } - } break; - case RDI_EvalOp_ByteSwap: { - switch (imm.u64) { - case 0: {} break; - case 1: {} break; - case 2: { nval.u16 = bswap_u16(svals[0].u16); } break; - case 4: { nval.u32 = bswap_u16(svals[0].u32); } break; - case 8: { nval.u64 = bswap_u16(svals[0].u64); } break; - default: { AssertAlways(!"malformed bytecode"); } break; // TODO: report error - } - } break; - case RDI_EvalOp_Swap: { - NotImplemented; - } break; - default: { Assert(!"unknown op type"); } break; + AssertAlways(!is_div_by_zero); + + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 / svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 / svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 / svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 / svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Mod: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 % svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 % svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 MOD is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 MOD is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_LShift: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 << svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 << svals[1].u64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 LShift is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 LShift is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_RShift: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 >> svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[1].s64 >> svals[1].u64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 RShift is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 RShift is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_BitAnd: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 | svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 | svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 bitwise AND is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 bitwise AND is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_BitXor: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 ^ svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 ^ svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 XOR is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 XOR is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_BitNot: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = ~svals[0].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = ~svals[0].u64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 bitwise NOT is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 bitwise NOT is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_LogAnd: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 && svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 && svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 AND is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 AND is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_LogOr: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 || svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].u64 || svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 OR is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 OR is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_LogNot: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = !svals[0].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = !svals[0].u64; } break; + case RDI_EvalTypeGroup_F32: { AssertAlways(!"F32 NOT is not supported"); } break; // TODO: report error + case RDI_EvalTypeGroup_F64: { AssertAlways(!"F64 NOT is not supported"); } break; // TODO: report error + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_EqEq: { + nval.u64 = !!MemoryMatch(&svals[0], &svals[1], sizeof(*svals)); + } break; + case RDI_EvalOp_NtEq: { + nval.u64 = !MemoryMatch(&svals[0], &svals[1], sizeof(*svals)); + } break; + case RDI_EvalOp_LsEq: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 <= svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 <= svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 <= svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 <= svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_GrEq: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 >= svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 >= svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 >= svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 >= svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Less: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 < svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 < svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 < svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 < svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Grtr: { + switch (imm.u64) { + case RDI_EvalTypeGroup_Other: {} break; + case RDI_EvalTypeGroup_U: { nval.u64 = svals[0].u64 > svals[1].u64; } break; + case RDI_EvalTypeGroup_S: { nval.s64 = svals[0].s64 > svals[1].s64; } break; + case RDI_EvalTypeGroup_F32: { nval.f32 = svals[0].f32 > svals[1].f32; } break; + case RDI_EvalTypeGroup_F64: { nval.f64 = svals[0].f64 > svals[1].f64; } break; + default: { AssertAlways(!"unexpected eval type group"); } break; // report error + } + } break; + case RDI_EvalOp_Trunc: { + if (0 < imm.u64 && imm.u64 < 64) { + U64 mask = max_U64 >> (64 - imm.u64); + nval.u64 = svals[0].u64 & (max_U64 >> (64 - imm.u64)); + } else if (imm.u64 > 64) { + // TODO: report error + AssertAlways(!"malformed bytecode"); + } + } break; + case RDI_EvalOp_TruncSigned: { + if (0 < imm.u64 && imm.u64 < 64) { + U64 mask = max_U64 >> (64 - imm.u64); + nval.u64 = svals[0].u64 & (max_U64 >> (64 - imm.u64)); + U64 high = 0; + if (svals[0].u64 & (1 << (imm.u64 - 1))) { + high = ~mask; + } + nval.u64 = high | (svals[0].u64 & mask); + } else if (imm.u64 > 64) { + // TODO: report error + AssertAlways(!"malformed bytecode"); + } + } break; + case RDI_EvalOp_Convert: { + U32 in = imm.u64 & 0xff; + U32 out = (imm.u64 >> 8) & 0xff; + if (in != out) { + switch (in + out*RDI_EvalTypeGroup_COUNT) { + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f32; } break; + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f64; } break; + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f32; } break; + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f64; } break; + case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].u64; } break; + case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].s64; } break; + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].f64; } break; + case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].u64; } break; + case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].s64; } break; + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].f32; } break; + default: { Assert(!"unexpected conversion case"); } break; // report error + } + } + } break; + case RDI_EvalOp_Pick: { + if (stack_count > imm.u64) { + nval = stack[stack_count - imm.u64 - 1]; + } else { + // TODO: report error + AssertAlways(!"malformed bytecode"); + } + } break; + case RDI_EvalOp_Pop: {} break; + case RDI_EvalOp_Insert: { + if (stack_count > imm.u64) { + Value tval = stack[stack_count-1]; + Value *dst = stack + stack_count - 1 - imm.u64; + Value *shift = dst + 1; + MemoryCopy(shift, dst, imm.u64 * sizeof(Value)); + *dst = tval; + } else { + // TODO: report error + AssertAlways(!"malformed bytecode"); + } + } break; + case RDI_EvalOp_ValueRead: { + U64 bytes_to_read = imm.u64; + U64 offset = svals[0].u64; + if (offset + bytes_to_read <= sizeof(Value)) { + Value src_val = svals[1]; + MemoryCopy(&nval, (U8 *)&src_val + offset, bytes_to_read); + } + } break; + case RDI_EvalOp_ByteSwap: { + switch (imm.u64) { + case 0: {} break; + case 1: {} break; + case 2: { nval.u16 = bswap_u16(svals[0].u16); } break; + case 4: { nval.u32 = bswap_u16(svals[0].u32); } break; + case 8: { nval.u64 = bswap_u16(svals[0].u64); } break; + default: { AssertAlways(!"malformed bytecode"); } break; // TODO: report error + } + } break; + case RDI_EvalOp_Swap: { + NotImplemented; + } break; + default: { Assert(!"unknown op type"); } break; } - + // push computed value to the stack { U64 push_count = RDI_PUSHN_FROM_CTRLBITS(rdi_eval_op_ctrlbits_table[opcode_n->op]); @@ -634,12 +634,12 @@ rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base) } } } - + U64 result = 0; if (stack_count >= 1) { result = stack[0].u64 - image_base; } - + scratch_end(scratch); return result; } @@ -687,13 +687,13 @@ internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size) { switch (bit_size) { - case 8: return D2R_ValueType_U8; - case 16: return D2R_ValueType_U16; - case 32: return D2R_ValueType_U32; - case 64: return D2R_ValueType_U64; - case 128: return D2R_ValueType_U128; - case 256: return D2R_ValueType_U256; - case 512: return D2R_ValueType_U512; + case 8: return D2R_ValueType_U8; + case 16: return D2R_ValueType_U16; + case 32: return D2R_ValueType_U32; + case 64: return D2R_ValueType_U64; + case 128: return D2R_ValueType_U128; + case 256: return D2R_ValueType_U256; + case 512: return D2R_ValueType_U512; } AssertAlways(!"no suitable unsigned type was found for the specified size"); return D2R_ValueType_Generic; @@ -703,13 +703,13 @@ internal D2R_ValueType d2r_signed_value_type_from_bit_size(U64 bit_size) { switch (bit_size) { - case 8: return D2R_ValueType_S8; - case 16: return D2R_ValueType_S16; - case 32: return D2R_ValueType_S32; - case 64: return D2R_ValueType_S64; - case 128: return D2R_ValueType_S128; - case 256: return D2R_ValueType_S256; - case 512: return D2R_ValueType_S512; + case 8: return D2R_ValueType_S8; + case 16: return D2R_ValueType_S16; + case 32: return D2R_ValueType_S32; + case 64: return D2R_ValueType_S64; + case 128: return D2R_ValueType_S128; + case 256: return D2R_ValueType_S256; + case 512: return D2R_ValueType_S512; } AssertAlways(!"no suitable signed type was found for the specified size"); return D2R_ValueType_Generic; @@ -719,8 +719,8 @@ internal D2R_ValueType d2r_float_type_from_bit_size(U64 bit_size) { switch (bit_size) { - case 4: return D2R_ValueType_F32; - case 8: return D2R_ValueType_F64; + case 4: return D2R_ValueType_F32; + case 8: return D2R_ValueType_F64; } AssertAlways(!"no suitable type was found for the specified size"); return D2R_ValueType_Generic; @@ -729,53 +729,56 @@ d2r_float_type_from_bit_size(U64 bit_size) internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v) { - switch (v) { - case D2R_ValueType_Generic: - return RDI_EvalTypeGroup_Other; - case D2R_ValueType_U8: - case D2R_ValueType_U16: - case D2R_ValueType_U32: - case D2R_ValueType_U64: - return RDI_EvalTypeGroup_U; - case D2R_ValueType_S8: - case D2R_ValueType_S16: - case D2R_ValueType_S32: - case D2R_ValueType_S64: - return RDI_EvalTypeGroup_S; - case D2R_ValueType_F32: - return RDI_EvalTypeGroup_F32; - case D2R_ValueType_F64: - return RDI_EvalTypeGroup_F64; - case D2R_ValueType_Address: - return RDI_EvalTypeGroup_U; - case D2R_ValueType_ImplicitValue: - AssertAlways(!"unable to convert value type to RDI equivalent"); + RDI_EvalTypeGroup result = RDI_EvalTypeGroup_Other; + switch(v) + { + case D2R_ValueType_Generic: + {result = RDI_EvalTypeGroup_Other;}break; + case D2R_ValueType_U8: + case D2R_ValueType_U16: + case D2R_ValueType_U32: + case D2R_ValueType_U64: + {result = RDI_EvalTypeGroup_U;}break; + case D2R_ValueType_S8: + case D2R_ValueType_S16: + case D2R_ValueType_S32: + case D2R_ValueType_S64: + {result = RDI_EvalTypeGroup_S;}break; + case D2R_ValueType_F32: + {result = RDI_EvalTypeGroup_F32;}break; + case D2R_ValueType_F64: + {result = RDI_EvalTypeGroup_F64;}break; + case D2R_ValueType_Address: + {result = RDI_EvalTypeGroup_U;}break; + default: + case D2R_ValueType_ImplicitValue: + {AssertAlways(!"unable to convert value type to RDI equivalent");}break; } - return RDI_EvalTypeGroup_Other; + return result; } internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type) { switch (value_type) { - case D2R_ValueType_Address: return addr_size; - case D2R_ValueType_U8: return 1; - case D2R_ValueType_U16: return 2; - case D2R_ValueType_U32: return 4; - case D2R_ValueType_U64: return 8; - case D2R_ValueType_U128: return 16; - case D2R_ValueType_U256: return 32; - case D2R_ValueType_U512: return 64; - case D2R_ValueType_S8: return 1; - case D2R_ValueType_S16: return 2; - case D2R_ValueType_S32: return 4; - case D2R_ValueType_S64: return 8; - case D2R_ValueType_S128: return 16; - case D2R_ValueType_S256: return 32; - case D2R_ValueType_S512: return 64; - case D2R_ValueType_F32: return 4; - case D2R_ValueType_F64: return 8; - default: return 0; + case D2R_ValueType_Address: return addr_size; + case D2R_ValueType_U8: return 1; + case D2R_ValueType_U16: return 2; + case D2R_ValueType_U32: return 4; + case D2R_ValueType_U64: return 8; + case D2R_ValueType_U128: return 16; + case D2R_ValueType_U256: return 32; + case D2R_ValueType_U512: return 64; + case D2R_ValueType_S8: return 1; + case D2R_ValueType_S16: return 2; + case D2R_ValueType_S32: return 4; + case D2R_ValueType_S64: return 8; + case D2R_ValueType_S128: return 16; + case D2R_ValueType_S256: return 32; + case D2R_ValueType_S512: return 64; + case D2R_ValueType_F32: return 4; + case D2R_ValueType_F64: return 8; + default: return 0; } } @@ -794,8 +797,8 @@ d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs) return Max(lhs, rhs); } // (unsigned vs signed) || (signed vs unsigned) - else if (D2R_ValueType_IsUnsigned(lhs) && D2R_ValueType_IsSigned(rhs) || - D2R_ValueType_IsSigned(lhs) && D2R_ValueType_IsUnsigned(rhs)) { + else if ((D2R_ValueType_IsUnsigned(lhs) && D2R_ValueType_IsSigned(rhs)) || + (D2R_ValueType_IsSigned(lhs) && D2R_ValueType_IsUnsigned(rhs))) { U64 lhs_size = d2r_size_from_value_type(0, lhs); U64 rhs_size = d2r_size_from_value_type(0, rhs); if (lhs_size < rhs_size) { @@ -910,7 +913,7 @@ d2r_bytecode_from_expression(Arena *arena, U64 inst_idx = 0; for EachNode(inst, DW_ExprInst, expr.first) { RDIM_EvalBytecodeOp *last_op = bc.last_op; - + U64 pop_count = dw_pop_count_from_expr_op(inst->opcode); if (pop_count > stack->count) { // TODO: report error @@ -918,468 +921,468 @@ d2r_bytecode_from_expression(Arena *arena, is_ok = 0; break; } - + switch (inst->opcode) { - case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: - case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: - case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: - case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: - case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: - case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: - case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: - case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: - case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: - case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: - case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { - U64 lit = inst->opcode - DW_ExprOp_Lit0; - rdim_bytecode_push_uconst(arena, &bc, lit); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U8); - } break; - case DW_ExprOp_Const1U: { - rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u8); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U8); - } break; - case DW_ExprOp_Const2U: { - rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u16); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U16); - } break; - case DW_ExprOp_Const4U: { - rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u32); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U32); - } break; - case DW_ExprOp_Const8U: { - rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u32); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U64); - } break; - case DW_ExprOp_Const1S: { - rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s8); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S8); - } break; - case DW_ExprOp_Const2S: { - rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s16); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S16); - } break; - case DW_ExprOp_Const4S: { - rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s32); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S32); - } break; - case DW_ExprOp_Const8S: { - rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s64); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S64); - } break; - case DW_ExprOp_ConstU: { - rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u64); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U64); - } break; - case DW_ExprOp_ConstS: { - rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s64); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S64); - } break; - case DW_ExprOp_Addr: { - if (inst->operands[0].u64 >= image_base) { - U64 voff = inst->operands[0].u64 - image_base; - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); - } else { - is_ok = 0; - } - } break; - case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: - case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: - case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: - case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: - case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: - case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: - case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: - case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: - case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: - case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: - case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { - U64 reg_code_dw = inst->opcode - DW_ExprOp_Reg0; - U64 reg_size = dw_reg_size_from_code(arch, reg_code_dw); - U64 reg_pos = dw_reg_pos_from_code(arch, reg_code_dw); - - RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); - U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); - d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(reg_size)); - } break; - case DW_ExprOp_RegX: { - U64 reg_size = dw_reg_size_from_code(arch, inst->operands[0].u64); - U64 reg_pos = dw_reg_pos_from_code(arch, inst->operands[0].u64); - RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, inst->operands[0].u64); - U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); - d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(reg_size)); - } break; - case DW_ExprOp_ImplicitValue: { - if (inst->operands[0].block.size <= sizeof(U64)) { - U64 implicit_value; - MemoryCopyStr8(&implicit_value, inst->operands[0].block); - rdim_bytecode_push_uconst(arena, &bc, implicit_value); - d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(inst->operands[0].block.size * 8)); - } else { - // TODO: currenlty no way to encode string in RDIM_EvalBytecodeOp - NotImplemented; - } - } break; - case DW_ExprOp_Piece: { - U64 partial_value_size32 = safe_cast_u32(inst->operands[0].u64); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValue, partial_value_size32); - } break; - case DW_ExprOp_BitPiece: { - U32 piece_bit_size32 = safe_cast_u32(inst->operands[0].u64); - U32 piece_bit_off32 = safe_cast_u32(inst->operands[1].u64); - U64 partial_value = Compose64Bit(piece_bit_size32, piece_bit_off32); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValueBit, partial_value); - } break; - case DW_ExprOp_Pick: { - U64 idx = 0; - D2R_ValueTypeNode *n; - for (n = stack->top; n != 0 || idx == inst->operands[0].u64; n = n->next, idx += 1) { } - if (idx == inst->operands[0].u64) { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, inst->operands[0].u64); - d2r_value_type_stack_push(scratch.arena, stack, n->type); - } else { - // TODO: report error - AssertAlways(!"out of bounds pick"); - } - } break; - case DW_ExprOp_Over: { - if (stack->top && stack->top->next) { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 1); - d2r_value_type_stack_push(scratch.arena, stack, stack->top->next->type); - } else { - // TODO: report error - AssertAlways(!"out of bounds over"); - } - } break; - case DW_ExprOp_PlusUConst: { - D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - D2R_ValueType common_type = d2r_pick_common_value_type(lhs, D2R_ValueType_U64); - rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u64); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, d2r_value_type_to_rdi(common_type)); - d2r_value_type_stack_push(scratch.arena, stack, common_type); - } break; - case DW_ExprOp_Skip: { - B32 skip_fwd = inst->operands[0].s16 >= 0; - U16 delta = abs_s64(inst->operands[0].s16); - U16 cursor = 0; - U64 inst_count = 0; - for (DW_ExprInst *i = skip_fwd ? inst : inst->prev; i != 0 && cursor < delta; i = skip_fwd ? inst->next : inst->prev) { - cursor += inst->size; - inst_count += 1; - } - - // TODO: report error (skip does not land on first byte of an instruction) - AssertAlways(cursor == delta); - // TODO: report overflow - AssertAlways(inst_count <= min_S16); - AssertAlways(inst_idx <= max_U32); - - U64 imm = Compose64Bit(inst_idx, skip_fwd ? (S16)inst_count : -(S16)inst_count); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Skip, imm); - } break; - case DW_ExprOp_Bra: { - NotImplemented; - } break; - case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: - case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: - case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: - case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: - case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: - case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: - case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: - case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: - case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: - case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: - case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { - U64 reg_code_dw = inst->opcode - DW_ExprOp_BReg0; - S64 reg_off = inst->operands[0].s64; - - RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, reg_code_rdi); - if (reg_off > 0) { - rdim_bytecode_push_sconst(arena, &bc, reg_off); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); - } - - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); - } break; - case DW_ExprOp_BRegX: { - U64 reg_code_dw = inst->operands[0].u64; - S64 reg_off = inst->operands[1].s64; - - RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); - if (reg_off > 0) { - rdim_bytecode_push_sconst(arena, &bc, reg_off); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); - } - - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); - } break; - case DW_ExprOp_FBReg: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, inst->operands[0].s64); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); - } break; - case DW_ExprOp_Deref: { - D2R_ValueType address_type = d2r_value_type_stack_pop(stack); - if (address_type != D2R_ValueType_Address && !D2R_ValueType_IsInt(address_type)) { - // TODO: report error - Assert(!"value must be of integral type"); - break; - } - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, address_size); - d2r_value_type_stack_push(scratch.arena, stack, address_type); - } break; - case DW_ExprOp_DerefSize: { - D2R_ValueType address_type = d2r_value_type_stack_pop(stack); - if (!D2R_ValueType_IsInt(address_type) && address_type != D2R_ValueType_Address ) { - // TODO: report error - Assert(!"value must be of integral type"); - break; - } - U8 deref_size_in_bytes = inst->operands[0].u64; - if (0 < deref_size_in_bytes && deref_size_in_bytes <= address_size) { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, deref_size_in_bytes); - } else { - // TODO: error handling - AssertAlways(!"ill formed expression"); - } - d2r_value_type_stack_push(scratch.arena, stack, address_type); - } break; - case DW_ExprOp_XDeref: { - // TODO: error handling - AssertAlways(!"multiple address spaces are not supported"); - } break; - // TODO: error handling - case DW_ExprOp_XDerefSize: { AssertAlways(!"no suitable conversion"); } break; - case DW_ExprOp_Call2: - case DW_ExprOp_Call4: - case DW_ExprOp_CallRef: { - // TODO: error handling - AssertAlways(!"calls are not supported"); - } break; - case DW_ExprOp_ImplicitPointer: - case DW_ExprOp_GNU_ImplicitPointer: { - // TODO: - AssertAlways(!"sample"); - } break; - case DW_ExprOp_Convert: - case DW_ExprOp_GNU_Convert: { - D2R_ValueType out = D2R_ValueType_Generic; - if (inst->operands[0].u64 == 0) { - // - // 2.5.1 - // Instead of a base type, elements can have a generic type, - // which is an integral type that has the size of an address - // on the target machine and unspecified signedness. - // - out = D2R_ValueType_Generic; - } else { - // find ref tag - DW_TagNode *tag_node = dw_tag_node_from_info_off(cu, inst->operands[0].u64); - DW_Tag tag = tag_node->tag; - if (tag.kind == DW_TagKind_BaseType) { - // extract encoding attribute - DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); - - // DW_ATE -> RDI_EvalTypeGroup - switch (encoding) { - case DW_ATE_Null: { - out = D2R_ValueType_Generic; - } break; - case DW_ATE_Address: { - out = D2R_ValueType_Address; - } break; - case DW_ATE_Boolean: { - out = D2R_ValueType_S8; - } break; - case DW_ATE_SignedChar: - case DW_ATE_Signed: { - U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); - out = d2r_signed_value_type_from_bit_size(byte_size * 8); - } break; - case DW_ATE_UnsignedChar: - case DW_ATE_Unsigned: { - U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); - out = d2r_unsigned_value_type_from_bit_size(byte_size * 8); - } break; - case DW_ATE_Float: { - U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); - out = d2r_float_type_from_bit_size(byte_size * 8); - } break; - default: InvalidPath; break; - } - } else { - AssertAlways(!"unexpected tag"); // TODO: error handling - } - } - - D2R_ValueType in = d2r_value_type_stack_pop(stack); - d2r_value_type_stack_push(scratch.arena, stack, out); - rdim_bytecode_push_convert(arena, &bc, d2r_value_type_to_rdi(in), d2r_value_type_to_rdi(out)); - } break; - // TODO: - case DW_ExprOp_GNU_ParameterRef: { AssertAlways(!"sample"); } break; - // TODO: - case DW_ExprOp_DerefType: - case DW_ExprOp_GNU_DerefType: { AssertAlways(!"sample"); } break; - // TODO: - case DW_ExprOp_ConstType: - case DW_ExprOp_GNU_ConstType: { AssertAlways(!"sample"); } break; - // TODO: - case DW_ExprOp_RegvalType: { AssertAlways(!"sample"); } break; - case DW_ExprOp_EntryValue: - case DW_ExprOp_GNU_EntryValue: { - D2R_ValueType call_site_result_type = 0; - RDIM_EvalBytecode call_site_bc = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, inst->operands[0].block, cu, &call_site_result_type); - - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_CallSiteValue, safe_cast_u32(call_site_bc.encoded_size)); - rdim_bytecode_concat_in_place(&bc, &call_site_bc); - - d2r_value_type_stack_push(scratch.arena, stack, call_site_result_type); - } break; - case DW_ExprOp_Addrx: { - U64 addr = dw_addr_from_list_unit(addr_lu, inst->operands[0].u64); - if (addr != max_U64) { - if (addr >= image_base) { - U64 voff = addr - image_base; + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { + U64 lit = inst->opcode - DW_ExprOp_Lit0; + rdim_bytecode_push_uconst(arena, &bc, lit); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U8); + } break; + case DW_ExprOp_Const1U: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u8); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U8); + } break; + case DW_ExprOp_Const2U: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u16); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U16); + } break; + case DW_ExprOp_Const4U: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u32); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U32); + } break; + case DW_ExprOp_Const8U: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u32); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U64); + } break; + case DW_ExprOp_Const1S: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s8); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S8); + } break; + case DW_ExprOp_Const2S: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s16); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S16); + } break; + case DW_ExprOp_Const4S: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s32); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S32); + } break; + case DW_ExprOp_Const8S: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s64); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S64); + } break; + case DW_ExprOp_ConstU: { + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u64); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_U64); + } break; + case DW_ExprOp_ConstS: { + rdim_bytecode_push_sconst(arena, &bc, inst->operands[0].s64); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_S64); + } break; + case DW_ExprOp_Addr: { + if (inst->operands[0].u64 >= image_base) { + U64 voff = inst->operands[0].u64 - image_base; rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); } else { - // TODO: error handling - AssertAlways(!"unable to relocate address"); + is_ok = 0; } - } else { + } break; + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { + U64 reg_code_dw = inst->opcode - DW_ExprOp_Reg0; + U64 reg_size = dw_reg_size_from_code(arch, reg_code_dw); + U64 reg_pos = dw_reg_pos_from_code(arch, reg_code_dw); + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); + U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); + d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(reg_size)); + } break; + case DW_ExprOp_RegX: { + U64 reg_size = dw_reg_size_from_code(arch, inst->operands[0].u64); + U64 reg_pos = dw_reg_pos_from_code(arch, inst->operands[0].u64); + RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, inst->operands[0].u64); + U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); + d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(reg_size)); + } break; + case DW_ExprOp_ImplicitValue: { + if (inst->operands[0].block.size <= sizeof(U64)) { + U64 implicit_value; + MemoryCopyStr8(&implicit_value, inst->operands[0].block); + rdim_bytecode_push_uconst(arena, &bc, implicit_value); + d2r_value_type_stack_push(scratch.arena, stack, d2r_unsigned_value_type_from_bit_size(inst->operands[0].block.size * 8)); + } else { + // TODO: currenlty no way to encode string in RDIM_EvalBytecodeOp + NotImplemented; + } + } break; + case DW_ExprOp_Piece: { + U64 partial_value_size32 = safe_cast_u32(inst->operands[0].u64); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValue, partial_value_size32); + } break; + case DW_ExprOp_BitPiece: { + U32 piece_bit_size32 = safe_cast_u32(inst->operands[0].u64); + U32 piece_bit_off32 = safe_cast_u32(inst->operands[1].u64); + U64 partial_value = Compose64Bit(piece_bit_size32, piece_bit_off32); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValueBit, partial_value); + } break; + case DW_ExprOp_Pick: { + U64 idx = 0; + D2R_ValueTypeNode *n; + for (n = stack->top; n != 0 || idx == inst->operands[0].u64; n = n->next, idx += 1) { } + if (idx == inst->operands[0].u64) { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, inst->operands[0].u64); + d2r_value_type_stack_push(scratch.arena, stack, n->type); + } else { + // TODO: report error + AssertAlways(!"out of bounds pick"); + } + } break; + case DW_ExprOp_Over: { + if (stack->top && stack->top->next) { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 1); + d2r_value_type_stack_push(scratch.arena, stack, stack->top->next->type); + } else { + // TODO: report error + AssertAlways(!"out of bounds over"); + } + } break; + case DW_ExprOp_PlusUConst: { + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + D2R_ValueType common_type = d2r_pick_common_value_type(lhs, D2R_ValueType_U64); + rdim_bytecode_push_uconst(arena, &bc, inst->operands[0].u64); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, d2r_value_type_to_rdi(common_type)); + d2r_value_type_stack_push(scratch.arena, stack, common_type); + } break; + case DW_ExprOp_Skip: { + B32 skip_fwd = inst->operands[0].s16 >= 0; + U16 delta = abs_s64(inst->operands[0].s16); + U16 cursor = 0; + U64 inst_count = 0; + for (DW_ExprInst *i = skip_fwd ? inst : inst->prev; i != 0 && cursor < delta; i = skip_fwd ? inst->next : inst->prev) { + cursor += inst->size; + inst_count += 1; + } + + // TODO: report error (skip does not land on first byte of an instruction) + AssertAlways(cursor == delta); + // TODO: report overflow + AssertAlways(inst_count <= min_S16); + AssertAlways(inst_idx <= max_U32); + + U64 imm = Compose64Bit(inst_idx, skip_fwd ? (S16)inst_count : -(S16)inst_count); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Skip, imm); + } break; + case DW_ExprOp_Bra: { + NotImplemented; + } break; + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { + U64 reg_code_dw = inst->opcode - DW_ExprOp_BReg0; + S64 reg_off = inst->operands[0].s64; + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, reg_code_rdi); + if (reg_off > 0) { + rdim_bytecode_push_sconst(arena, &bc, reg_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); + } + + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + case DW_ExprOp_BRegX: { + U64 reg_code_dw = inst->operands[0].u64; + S64 reg_off = inst->operands[1].s64; + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_code_from_dw_reg(arch, reg_code_dw); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); + if (reg_off > 0) { + rdim_bytecode_push_sconst(arena, &bc, reg_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); + } + + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + case DW_ExprOp_FBReg: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, inst->operands[0].s64); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + case DW_ExprOp_Deref: { + D2R_ValueType address_type = d2r_value_type_stack_pop(stack); + if (address_type != D2R_ValueType_Address && !D2R_ValueType_IsInt(address_type)) { + // TODO: report error + Assert(!"value must be of integral type"); + break; + } + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, address_size); + d2r_value_type_stack_push(scratch.arena, stack, address_type); + } break; + case DW_ExprOp_DerefSize: { + D2R_ValueType address_type = d2r_value_type_stack_pop(stack); + if (!D2R_ValueType_IsInt(address_type) && address_type != D2R_ValueType_Address ) { + // TODO: report error + Assert(!"value must be of integral type"); + break; + } + U8 deref_size_in_bytes = inst->operands[0].u64; + if (0 < deref_size_in_bytes && deref_size_in_bytes <= address_size) { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, deref_size_in_bytes); + } else { + // TODO: error handling + AssertAlways(!"ill formed expression"); + } + d2r_value_type_stack_push(scratch.arena, stack, address_type); + } break; + case DW_ExprOp_XDeref: { // TODO: error handling - AssertAlways(!"out of bounds index"); - } - } break; - case DW_ExprOp_CallFrameCfa: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, 0); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); - } break; - case DW_ExprOp_FormTlsAddress: { + AssertAlways(!"multiple address spaces are not supported"); + } break; + // TODO: error handling + case DW_ExprOp_XDerefSize: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_Call2: + case DW_ExprOp_Call4: + case DW_ExprOp_CallRef: { + // TODO: error handling + AssertAlways(!"calls are not supported"); + } break; + case DW_ExprOp_ImplicitPointer: + case DW_ExprOp_GNU_ImplicitPointer: { + // TODO: + AssertAlways(!"sample"); + } break; + case DW_ExprOp_Convert: + case DW_ExprOp_GNU_Convert: { + D2R_ValueType out = D2R_ValueType_Generic; + if (inst->operands[0].u64 == 0) { + // + // 2.5.1 + // Instead of a base type, elements can have a generic type, + // which is an integral type that has the size of an address + // on the target machine and unspecified signedness. + // + out = D2R_ValueType_Generic; + } else { + // find ref tag + DW_TagNode *tag_node = dw_tag_node_from_info_off(cu, inst->operands[0].u64); + DW_Tag tag = tag_node->tag; + if (tag.kind == DW_TagKind_BaseType) { + // extract encoding attribute + DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); + + // DW_ATE -> RDI_EvalTypeGroup + switch (encoding) { + case DW_ATE_Null: { + out = D2R_ValueType_Generic; + } break; + case DW_ATE_Address: { + out = D2R_ValueType_Address; + } break; + case DW_ATE_Boolean: { + out = D2R_ValueType_S8; + } break; + case DW_ATE_SignedChar: + case DW_ATE_Signed: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_signed_value_type_from_bit_size(byte_size * 8); + } break; + case DW_ATE_UnsignedChar: + case DW_ATE_Unsigned: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_unsigned_value_type_from_bit_size(byte_size * 8); + } break; + case DW_ATE_Float: { + U64 byte_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + out = d2r_float_type_from_bit_size(byte_size * 8); + } break; + default: InvalidPath; break; + } + } else { + AssertAlways(!"unexpected tag"); // TODO: error handling + } + } + + D2R_ValueType in = d2r_value_type_stack_pop(stack); + d2r_value_type_stack_push(scratch.arena, stack, out); + rdim_bytecode_push_convert(arena, &bc, d2r_value_type_to_rdi(in), d2r_value_type_to_rdi(out)); + } break; // TODO: - AssertAlways(!"RDI_EvalOp_TLSOff accepts immediate"); - } break; - case DW_ExprOp_PushObjectAddress: { - AssertAlways(!"sample"); - } break; - case DW_ExprOp_Nop: {} break; - case DW_ExprOp_Eq: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_EqEq); } break; - case DW_ExprOp_Ge: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_GrEq); } break; - case DW_ExprOp_Gt: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_Grtr); } break; - case DW_ExprOp_Le: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_LsEq); } break; - case DW_ExprOp_Lt: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_Less); } break; - case DW_ExprOp_Ne: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_NtEq); } break; - case DW_ExprOp_Div: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Div); } break; - case DW_ExprOp_Minus: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Sub); } break; - case DW_ExprOp_Mul: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Mul); } break; - case DW_ExprOp_Plus: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Add); } break; - case DW_ExprOp_Xor: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitXor); } break; - case DW_ExprOp_And: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitAnd); } break; - case DW_ExprOp_Or: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitOr); } break; - case DW_ExprOp_Shl: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_LShift); } break; - case DW_ExprOp_Shr: { - D2R_ValueType rhs = d2r_value_type_stack_pop(stack); - D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - if (D2R_ValueType_IsInt(rhs) && D2R_ValueType_IsInt(lhs)) { + case DW_ExprOp_GNU_ParameterRef: { AssertAlways(!"sample"); } break; + // TODO: + case DW_ExprOp_DerefType: + case DW_ExprOp_GNU_DerefType: { AssertAlways(!"sample"); } break; + // TODO: + case DW_ExprOp_ConstType: + case DW_ExprOp_GNU_ConstType: { AssertAlways(!"sample"); } break; + // TODO: + case DW_ExprOp_RegvalType: { AssertAlways(!"sample"); } break; + case DW_ExprOp_EntryValue: + case DW_ExprOp_GNU_EntryValue: { + D2R_ValueType call_site_result_type = 0; + RDIM_EvalBytecode call_site_bc = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, inst->operands[0].block, cu, &call_site_result_type); + + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_CallSiteValue, safe_cast_u32(call_site_bc.encoded_size)); + rdim_bytecode_concat_in_place(&bc, &call_site_bc); + + d2r_value_type_stack_push(scratch.arena, stack, call_site_result_type); + } break; + case DW_ExprOp_Addrx: { + U64 addr = dw_addr_from_list_unit(addr_lu, inst->operands[0].u64); + if (addr != max_U64) { + if (addr >= image_base) { + U64 voff = addr - image_base; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } else { + // TODO: error handling + AssertAlways(!"unable to relocate address"); + } + } else { + // TODO: error handling + AssertAlways(!"out of bounds index"); + } + } break; + case DW_ExprOp_CallFrameCfa: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, 0); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + case DW_ExprOp_FormTlsAddress: { + // TODO: + AssertAlways(!"RDI_EvalOp_TLSOff accepts immediate"); + } break; + case DW_ExprOp_PushObjectAddress: { + AssertAlways(!"sample"); + } break; + case DW_ExprOp_Nop: {} break; + case DW_ExprOp_Eq: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_EqEq); } break; + case DW_ExprOp_Ge: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_GrEq); } break; + case DW_ExprOp_Gt: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_Grtr); } break; + case DW_ExprOp_Le: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_LsEq); } break; + case DW_ExprOp_Lt: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_Less); } break; + case DW_ExprOp_Ne: { d2r_push_relational_op(arena, stack, &bc, RDI_EvalOp_NtEq); } break; + case DW_ExprOp_Div: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Div); } break; + case DW_ExprOp_Minus: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Sub); } break; + case DW_ExprOp_Mul: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Mul); } break; + case DW_ExprOp_Plus: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_Add); } break; + case DW_ExprOp_Xor: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitXor); } break; + case DW_ExprOp_And: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitAnd); } break; + case DW_ExprOp_Or: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_BitOr); } break; + case DW_ExprOp_Shl: { d2r_push_arithmetic_op(arena, stack, &bc, RDI_EvalOp_LShift); } break; + case DW_ExprOp_Shr: { + D2R_ValueType rhs = d2r_value_type_stack_pop(stack); + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + if (D2R_ValueType_IsInt(rhs) && D2R_ValueType_IsInt(lhs)) { + D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); + D2R_ValueType result_type = d2r_unsigned_value_type_from_bit_size(d2r_size_from_value_type((address_size), common_type) * 8); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, d2r_value_type_to_rdi(result_type)); + d2r_value_type_stack_push(scratch.arena, stack, result_type); + } else { + // TODO: report error + AssertAlways(!"operands must be of integral type"); + } + } break; + case DW_ExprOp_Shra: { + D2R_ValueType rhs = d2r_value_type_stack_pop(stack); + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + if (D2R_ValueType_IsInt(lhs) && D2R_ValueType_IsInt(rhs)) { + D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); + D2R_ValueType result_type = d2r_signed_value_type_from_bit_size(d2r_size_from_value_type((address_size), common_type) * 8); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, d2r_value_type_to_rdi(result_type)); + d2r_value_type_stack_push(scratch.arena, stack, result_type); + } else { + // TODO: report error + AssertAlways(!"operands must be of integral type"); + } + } break; + case DW_ExprOp_Mod: { + D2R_ValueType rhs = d2r_value_type_stack_pop(stack); + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + if (!D2R_ValueType_IsInt(rhs) || !D2R_ValueType_IsInt(lhs)) { + // TODO: report error + AssertAlways(!"operands must be of integral type"); + is_ok = 0; + break; + } D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); - D2R_ValueType result_type = d2r_unsigned_value_type_from_bit_size(d2r_size_from_value_type((address_size), common_type) * 8); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, d2r_value_type_to_rdi(result_type)); - d2r_value_type_stack_push(scratch.arena, stack, result_type); - } else { - // TODO: report error - AssertAlways(!"operands must be of integral type"); - } - } break; - case DW_ExprOp_Shra: { - D2R_ValueType rhs = d2r_value_type_stack_pop(stack); - D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - if (D2R_ValueType_IsInt(lhs) && D2R_ValueType_IsInt(rhs)) { - D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); - D2R_ValueType result_type = d2r_signed_value_type_from_bit_size(d2r_size_from_value_type((address_size), common_type) * 8); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, d2r_value_type_to_rdi(result_type)); - d2r_value_type_stack_push(scratch.arena, stack, result_type); - } else { - // TODO: report error - AssertAlways(!"operands must be of integral type"); - } - } break; - case DW_ExprOp_Mod: { - D2R_ValueType rhs = d2r_value_type_stack_pop(stack); - D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - if (!D2R_ValueType_IsInt(rhs) || !D2R_ValueType_IsInt(lhs)) { - // TODO: report error - AssertAlways(!"operands must be of integral type"); - is_ok = 0; - break; - } - D2R_ValueType common_type = d2r_pick_common_value_type(lhs, rhs); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mod, d2r_value_type_to_rdi(common_type)); - d2r_value_type_stack_push(scratch.arena, stack, common_type); - } break; - case DW_ExprOp_Abs: { - if (!D2R_ValueType_IsInt(d2r_value_type_stack_peek(stack)) && !D2R_ValueType_IsFloat(d2r_value_type_stack_peek(stack))) { - // TODO: report error - AssertAlways(!"operand must be of integral type or float"); - is_ok = 0; - break; - } - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Abs, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); - } break; - case DW_ExprOp_Neg: { - if (!D2R_ValueType_IsInt(d2r_value_type_stack_peek(stack))) { - // TODO: report error - AssertAlways(!"operand must be of integral type"); - is_ok = 0; - break; - } - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Neg, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); - } break; - case DW_ExprOp_Not: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitNot, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); - } break; - case DW_ExprOp_Dup: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 0); - d2r_value_type_stack_push(scratch.arena, stack, d2r_value_type_stack_peek(stack)); - } break; - case DW_ExprOp_Rot: { AssertAlways(!"no suitable conversion"); } break; - case DW_ExprOp_Swap: { AssertAlways(!"no suitable conversion"); } break; - case DW_ExprOp_Drop: { AssertAlways(!"no suitable conversion"); } break; - case DW_ExprOp_StackValue: { - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Stop, 0); - if (stack->top->type == D2R_ValueType_Address) { - stack->top->type = d2r_unsigned_value_type_from_bit_size(address_size * 8); - } - } break; - case DW_ExprOp_GNU_PushTlsAddress: { - D2R_ValueType lhs = d2r_value_type_stack_pop(stack); - if (!D2R_ValueType_IsInt(lhs)) { - // TODO: report error - AssertAlways(!"lhs must be of integral type"); - } - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_TLSOff, 0); - rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, d2r_value_type_to_rdi(lhs)); - d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); - } break; - - default: InvalidPath; break; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mod, d2r_value_type_to_rdi(common_type)); + d2r_value_type_stack_push(scratch.arena, stack, common_type); + } break; + case DW_ExprOp_Abs: { + if (!D2R_ValueType_IsInt(d2r_value_type_stack_peek(stack)) && !D2R_ValueType_IsFloat(d2r_value_type_stack_peek(stack))) { + // TODO: report error + AssertAlways(!"operand must be of integral type or float"); + is_ok = 0; + break; + } + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Abs, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); + } break; + case DW_ExprOp_Neg: { + if (!D2R_ValueType_IsInt(d2r_value_type_stack_peek(stack))) { + // TODO: report error + AssertAlways(!"operand must be of integral type"); + is_ok = 0; + break; + } + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Neg, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); + } break; + case DW_ExprOp_Not: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitNot, d2r_value_type_to_rdi(d2r_value_type_stack_peek(stack))); + } break; + case DW_ExprOp_Dup: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 0); + d2r_value_type_stack_push(scratch.arena, stack, d2r_value_type_stack_peek(stack)); + } break; + case DW_ExprOp_Rot: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_Swap: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_Drop: { AssertAlways(!"no suitable conversion"); } break; + case DW_ExprOp_StackValue: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Stop, 0); + if (stack->top->type == D2R_ValueType_Address) { + stack->top->type = d2r_unsigned_value_type_from_bit_size(address_size * 8); + } + } break; + case DW_ExprOp_GNU_PushTlsAddress: { + D2R_ValueType lhs = d2r_value_type_stack_pop(stack); + if (!D2R_ValueType_IsInt(lhs)) { + // TODO: report error + AssertAlways(!"lhs must be of integral type"); + } + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_TLSOff, 0); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, d2r_value_type_to_rdi(lhs)); + d2r_value_type_stack_push(scratch.arena, stack, D2R_ValueType_Address); + } break; + + default: InvalidPath; break; } if (!is_ok) { break; } - + // store converted instruction if (last_op != bc.last_op) { RDIM_EvalBytecodeOp *first_converted_op = last_op ? last_op->next : bc.first_op; converted_insts[inst_idx] = first_converted_op; } - + inst_idx += 1; } - + if (is_ok) { // fixup bytecode for EachNode(op, RDIM_EvalBytecodeOp, bc.first_op) { @@ -1389,7 +1392,7 @@ d2r_bytecode_from_expression(Arena *arena, S16 skip_count_signed = (S16)Extract32(op->p, 1); U16 skip_count = abs_s64(skip_count_signed); B32 skip_fwd = skip_count_signed > 0; - + // setup being/end links RDIM_EvalBytecodeOp *begin = 0, *end = 0; if (skip_fwd) { @@ -1409,19 +1412,19 @@ d2r_bytecode_from_expression(Arena *arena, AssertAlways(!"out of bounds skip"); } } - + // compute skip delta U64 skip_delta = 0; for (RDIM_EvalBytecodeOp *n = begin; n != end; n = n->next) { skip_delta += n->p_size; } - + // rewrite skip operand with byte delta AssertAlways(skip_delta <= max_S16); op->p = skip_fwd ? (S16)skip_delta : -(S16)skip_delta; } } - + if (result_type_out) { *result_type_out = d2r_value_type_stack_peek(stack); } @@ -1445,7 +1448,7 @@ d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Inp RDIM_LocationInfo *loc_info = push_array(arena, RDIM_LocationInfo, 1); loc_info->kind = result_type == D2R_ValueType_Address ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; loc_info->bytecode = bytecode; - + loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); } return loc; @@ -1541,7 +1544,7 @@ d2r_var_locset_from_tag(Arena *arena, loc_info->kind = RDI_LocationKind_ValBytecodeStream; loc_info->bytecode = bc; RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); - + // push location cases for EachNode(range_n, RDIM_Rng1U64Node, curr_scope->voff_ranges.first) { rdim_push_location_case(arena, scopes, &locset, loc, range_n->v); @@ -1715,19 +1718,19 @@ d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter) goto exit; } } - + while (iter->stack) { // go to sibling iter->stack->node = iter->stack->node->sibling; if (iter->stack->node) { break; } - + // no more siblings, go up D2R_TagFrame *f = iter->stack; SLLStackPop(iter->stack); SLLStackPush(iter->free_list, f); } - -exit:; + + exit:; // update iterator iter->visit_children = 1; iter->tag_node = iter->stack ? iter->stack->node : 0; @@ -1785,13 +1788,13 @@ d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *inpu // find type type = d2r_type_from_offset(type_table, ref.info_off); - + // was type converted? if (type == 0) { // issue type conversion DW_TagNode *ref_node = dw_tag_node_from_info_off(cu, ref.info_off); d2r_convert_types(arena, type_table, input, cu, cu_lang, arch_addr_size, ref_node); - + // if we do not have a converted type at this point then debug info is malformed type = d2r_type_from_offset(type_table, ref.info_off); Assert(type); @@ -1817,7 +1820,7 @@ d2r_convert_types(Arena *arena, for (D2R_TagIterator *it = d2r_tag_iterator_init(scratch.arena, root); it->tag_node != 0; d2r_tag_iterator_next(scratch.arena, it)) { DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; - + // skip converted tags if (d2r_is_tag_converted(tag_node)) { d2r_tag_iterator_skip_children(it); @@ -1825,376 +1828,376 @@ d2r_convert_types(Arena *arena, } // mark the tag as converted here, because during conversion we may recurse on the same tag d2r_flag_converted_tag(tag_node); - + switch (tag.kind) { - case DW_TagKind_ClassType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_IncompleteClass; - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - Assert(!tag_node->first_child); + case DW_TagKind_ClassType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_IncompleteClass; + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Class; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + type->direct_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + } + } break; + case DW_TagKind_StructureType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteStruct; + + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Struct; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + } + } break; + case DW_TagKind_UnionType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteUnion; + + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Union; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + } + } break; + case DW_TagKind_EnumerationType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteEnum; + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Enum; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + type->direct_type = enum_base_type; + } + } break; + case DW_TagKind_SubroutineType: { + RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + + // collect parameters + RDIM_TypeList param_list = {0}; + for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind == DW_TagKind_FormalParameter) { + RDIM_Type *param_type = d2r_type_from_attrib(type_table, input, cu, n->tag, DW_AttribKind_Type); + rdim_type_list_push(scratch.arena, ¶m_list, param_type); + } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { + rdim_type_list_push(scratch.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); + } else { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } + } + + // init proceudre type + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Function; + type->byte_size = arch_addr_size; + type->direct_type = ret_type; + type->count = param_list.count; + type->param_types = rdim_array_from_type_list(arena, param_list); + d2r_tag_iterator_skip_children(it); - } else { + } break; + case DW_TagKind_Typedef: { RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Class; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - type->direct_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - } - } break; - case DW_TagKind_StructureType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteStruct; - - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Struct; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - } - } break; - case DW_TagKind_UnionType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteUnion; - - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Union; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - } - } break; - case DW_TagKind_EnumerationType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_IncompleteEnum; - // TODO: error handling - Assert(!tag_node->first_child); - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->direct_type = direct_type; + for (RDIM_Type *n = direct_type; n != 0; n = n->direct_type) { + if (n->byte_size) { + type->byte_size = n->byte_size; + break; + } + } + } break; + case DW_TagKind_BaseType: { + DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); + U64 byte_size = dw_byte_size_from_tag(input, cu, tag); + + // convert base type encoding to RDI version + RDI_TypeKind kind = RDI_TypeKind_NULL; + switch (encoding) { + case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; + case DW_ATE_Address: kind = RDI_TypeKind_Void; break; + case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; + case DW_ATE_ComplexFloat: { + switch (byte_size) { + case 4: kind = RDI_TypeKind_ComplexF32; break; + case 8: kind = RDI_TypeKind_ComplexF64; break; + case 10: kind = RDI_TypeKind_ComplexF80; break; + case 16: kind = RDI_TypeKind_ComplexF128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Float: { + switch (byte_size) { + case 2: kind = RDI_TypeKind_F16; break; + case 4: kind = RDI_TypeKind_F32; break; + case 6: kind = RDI_TypeKind_F48; break; + case 8: kind = RDI_TypeKind_F64; break; + case 16: kind = RDI_TypeKind_F128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Signed: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_S8; break; + case 2: kind = RDI_TypeKind_S16; break; + case 4: kind = RDI_TypeKind_S32; break; + case 8: kind = RDI_TypeKind_S64; break; + case 16: kind = RDI_TypeKind_S128; break; + case 32: kind = RDI_TypeKind_S256; break; + case 64: kind = RDI_TypeKind_S512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_SignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_Char8; break; + case 2: kind = RDI_TypeKind_Char16; break; + case 4: kind = RDI_TypeKind_Char32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Unsigned: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_U8; break; + case 2: kind = RDI_TypeKind_U16; break; + case 4: kind = RDI_TypeKind_U32; break; + case 8: kind = RDI_TypeKind_U64; break; + case 16: kind = RDI_TypeKind_U128; break; + case 32: kind = RDI_TypeKind_U256; break; + case 64: kind = RDI_TypeKind_U512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_UnsignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_UChar8; break; + case 2: kind = RDI_TypeKind_UChar16; break; + case 4: kind = RDI_TypeKind_UChar32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_ImaginaryFloat: { + NotImplemented; + } break; + case DW_ATE_PackedDecimal: { + NotImplemented; + } break; + case DW_ATE_NumericString: { + NotImplemented; + } break; + case DW_ATE_Edited: { + NotImplemented; + } break; + case DW_ATE_SignedFixed: { + NotImplemented; + } break; + case DW_ATE_UnsignedFixed: { + NotImplemented; + } break; + case DW_ATE_DecimalFloat: { + NotImplemented; + } break; + case DW_ATE_Utf: { + NotImplemented; + } break; + case DW_ATE_Ucs: { + NotImplemented; + } break; + case DW_ATE_Ascii: { + NotImplemented; + } break; + default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + } + + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->kind = RDI_TypeKind_Enum; - type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); - type->direct_type = enum_base_type; - } - } break; - case DW_TagKind_SubroutineType: { - RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - - // collect parameters - RDIM_TypeList param_list = {0}; - for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind == DW_TagKind_FormalParameter) { - RDIM_Type *param_type = d2r_type_from_attrib(type_table, input, cu, n->tag, DW_AttribKind_Type); - rdim_type_list_push(scratch.arena, ¶m_list, param_type); - } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { - rdim_type_list_push(scratch.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); - } else { - // TODO: error handling - AssertAlways(!"unexpected tag"); + type->direct_type = type_table->builtin_types[kind]; + type->byte_size = byte_size; + } break; + case DW_TagKind_PointerType: { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); + + U64 byte_size = arch_addr_size; + if (cu->version == DW_Version_5 || cu->relaxed) { + dw_try_byte_size_from_tag(input, cu, tag, &byte_size); } - } - - // init proceudre type - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Function; - type->byte_size = arch_addr_size; - type->direct_type = ret_type; - type->count = param_list.count; - type->param_types = rdim_array_from_type_list(arena, param_list); - - d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_Typedef: { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->direct_type = direct_type; - for (RDIM_Type *n = direct_type; n != 0; n = n->direct_type) { - if (n->byte_size) { - type->byte_size = n->byte_size; - break; + + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Ptr; + type->byte_size = byte_size; + type->direct_type = direct_type; + } break; + case DW_TagKind_RestrictType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Restrict; + type->direct_type = direct_type; + } break; + case DW_TagKind_VolatileType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Volatile; + type->direct_type = direct_type; + } break; + case DW_TagKind_ConstType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Const; + type->direct_type = direct_type; + } break; + case DW_TagKind_ArrayType: { + // * DWARF vs RDI Array Type Graph * + // + // For example lets take following decl: + // + // int (*foo[2])[3]; + // + // This compiles to in DWARF: + // + // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] + // \ + // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] + // \ + // -> (B1) DW_TAG_BaseType (int) + // + // RDI expects: + // + // foo -> Array[2] -> Pointer -> Array[3] -> int + // + // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and + // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. + // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from + // B to A. + struct SubrangeNode { struct SubrangeNode *next; U64 count; }; + struct SubrangeNode *subrange_stack = 0; + for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind != DW_TagKind_SubrangeType) { + // TODO: error handling + AssertAlways(!"unexpected tag"); + continue; + } + + // resolve lower bound + U64 lower_bound = 0; + if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_LowerBound)) { + lower_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_LowerBound); + } else { + lower_bound = dw_pick_default_lower_bound(cu_lang); + } + + // resolve upper bound + U64 upper_bound = 0; + if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_Count)) { + U64 count = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_Count); + upper_bound = lower_bound + count; + } else if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_UpperBound)) { + upper_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_UpperBound); + // turn upper bound into exclusive range + upper_bound += 1; + } else { + // zero sized array + } + + struct SubrangeNode *s = push_array(scratch.arena, struct SubrangeNode, 1); + s->count = upper_bound - lower_bound; + SLLStackPush(subrange_stack, s); } - } - } break; - case DW_TagKind_BaseType: { - DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); - U64 byte_size = dw_byte_size_from_tag(input, cu, tag); - - // convert base type encoding to RDI version - RDI_TypeKind kind = RDI_TypeKind_NULL; - switch (encoding) { - case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; - case DW_ATE_Address: kind = RDI_TypeKind_Void; break; - case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; - case DW_ATE_ComplexFloat: { - switch (byte_size) { - case 4: kind = RDI_TypeKind_ComplexF32; break; - case 8: kind = RDI_TypeKind_ComplexF64; break; - case 10: kind = RDI_TypeKind_ComplexF80; break; - case 16: kind = RDI_TypeKind_ComplexF128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling + + RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = array_base_type; + U64 size_cursor = array_base_type->byte_size; + for EachNode(s, struct SubrangeNode, subrange_stack) { + size_cursor *= s->count; + + RDIM_Type *t; + if (s->next) { t = d2r_create_type(arena, type_table); } + else { t = d2r_create_type_from_offset(arena, type_table, tag.info_off); } + + t->kind = RDI_TypeKind_Array; + t->direct_type = direct_type; + t->byte_size = size_cursor; + t->count = s->count; + + direct_type = t; } + + d2r_tag_iterator_skip_children(it); } break; - case DW_ATE_Float: { - switch (byte_size) { - case 2: kind = RDI_TypeKind_F16; break; - case 4: kind = RDI_TypeKind_F32; break; - case 6: kind = RDI_TypeKind_F48; break; - case 8: kind = RDI_TypeKind_F64; break; - case 16: kind = RDI_TypeKind_F128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Signed: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_S8; break; - case 2: kind = RDI_TypeKind_S16; break; - case 4: kind = RDI_TypeKind_S32; break; - case 8: kind = RDI_TypeKind_S64; break; - case 16: kind = RDI_TypeKind_S128; break; - case 32: kind = RDI_TypeKind_S256; break; - case 64: kind = RDI_TypeKind_S512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_SignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_Char8; break; - case 2: kind = RDI_TypeKind_Char16; break; - case 4: kind = RDI_TypeKind_Char32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Unsigned: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_U8; break; - case 2: kind = RDI_TypeKind_U16; break; - case 4: kind = RDI_TypeKind_U32; break; - case 8: kind = RDI_TypeKind_U64; break; - case 16: kind = RDI_TypeKind_U128; break; - case 32: kind = RDI_TypeKind_U256; break; - case 64: kind = RDI_TypeKind_U512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_UnsignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_UChar8; break; - case 2: kind = RDI_TypeKind_UChar16; break; - case 4: kind = RDI_TypeKind_UChar32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_ImaginaryFloat: { - NotImplemented; - } break; - case DW_ATE_PackedDecimal: { - NotImplemented; - } break; - case DW_ATE_NumericString: { - NotImplemented; - } break; - case DW_ATE_Edited: { - NotImplemented; - } break; - case DW_ATE_SignedFixed: { - NotImplemented; - } break; - case DW_ATE_UnsignedFixed: { - NotImplemented; - } break; - case DW_ATE_DecimalFloat: { - NotImplemented; - } break; - case DW_ATE_Utf: { - NotImplemented; - } break; - case DW_ATE_Ucs: { - NotImplemented; - } break; - case DW_ATE_Ascii: { - NotImplemented; - } break; - default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling - } - - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - type->direct_type = type_table->builtin_types[kind]; - type->byte_size = byte_size; - } break; - case DW_TagKind_PointerType: { - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); - - U64 byte_size = arch_addr_size; - if (cu->version == DW_Version_5 || cu->relaxed) { - dw_try_byte_size_from_tag(input, cu, tag, &byte_size); - } - - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Ptr; - type->byte_size = byte_size; - type->direct_type = direct_type; - } break; - case DW_TagKind_RestrictType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Restrict; - type->direct_type = direct_type; - } break; - case DW_TagKind_VolatileType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Volatile; - type->direct_type = direct_type; - } break; - case DW_TagKind_ConstType: { - // TODO: - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - - RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Const; - type->direct_type = direct_type; - } break; - case DW_TagKind_ArrayType: { - // * DWARF vs RDI Array Type Graph * - // - // For example lets take following decl: - // - // int (*foo[2])[3]; - // - // This compiles to in DWARF: - // - // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] - // \ - // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] - // \ - // -> (B1) DW_TAG_BaseType (int) - // - // RDI expects: - // - // foo -> Array[2] -> Pointer -> Array[3] -> int - // - // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and - // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. - // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from - // B to A. - struct SubrangeNode { struct SubrangeNode *next; U64 count; }; - struct SubrangeNode *subrange_stack = 0; - for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind != DW_TagKind_SubrangeType) { - // TODO: error handling - AssertAlways(!"unexpected tag"); - continue; - } - - // resolve lower bound - U64 lower_bound = 0; - if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_LowerBound)) { - lower_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_LowerBound); - } else { - lower_bound = dw_pick_default_lower_bound(cu_lang); - } - - // resolve upper bound - U64 upper_bound = 0; - if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_Count)) { - U64 count = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_Count); - upper_bound = lower_bound + count; - } else if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_UpperBound)) { - upper_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_UpperBound); - // turn upper bound into exclusive range - upper_bound += 1; - } else { - // zero sized array - } - - struct SubrangeNode *s = push_array(scratch.arena, struct SubrangeNode, 1); - s->count = upper_bound - lower_bound; - SLLStackPush(subrange_stack, s); - } - - RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_Type *direct_type = array_base_type; - U64 size_cursor = array_base_type->byte_size; - for EachNode(s, struct SubrangeNode, subrange_stack) { - size_cursor *= s->count; - - RDIM_Type *t; - if (s->next) { t = d2r_create_type(arena, type_table); } - else { t = d2r_create_type_from_offset(arena, type_table, tag.info_off); } - - t->kind = RDI_TypeKind_Array; - t->direct_type = direct_type; - t->byte_size = size_cursor; - t->count = s->count; - - direct_type = t; - } - - d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_SubrangeType: { - // TODO: error handling - AssertAlways(!"unexpected tag"); - } break; - case DW_TagKind_Inheritance: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind != DW_TagKind_StructureType && parent_tag.kind != DW_TagKind_ClassType) { + case DW_TagKind_SubrangeType: { // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - - RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); - member->kind = RDI_MemberKind_Base; - member->type = type; - member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); - } break; + AssertAlways(!"unexpected tag"); + } break; + case DW_TagKind_Inheritance: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind != DW_TagKind_StructureType && parent_tag.kind != DW_TagKind_ClassType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = type; + member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); + } break; } } scratch_end(scratch); @@ -2214,85 +2217,85 @@ d2r_convert_udts(Arena *arena, DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; switch (tag.kind) { - case DW_TagKind_ClassType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_StructureType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_UnionType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_EnumerationType: { - B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - d2r_tag_iterator_skip_children(it); - } else { - RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - type->udt = udt; - } - } break; - case DW_TagKind_Member: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - B32 is_parent_udt = parent_tag.kind == DW_TagKind_StructureType || - parent_tag.kind == DW_TagKind_ClassType || - parent_tag.kind == DW_TagKind_UnionType; - if (is_parent_udt) { - DW_Attrib *data_member_location = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_DataMemberLocation); - DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); - if (data_member_location_class == DW_AttribClass_LocList) { - AssertAlways(!"UDT member with multiple locations are not supported"); + case DW_TagKind_ClassType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; } - - RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTMember *udt_member = rdim_udt_push_member(arena, &udts, parent_type->udt); - udt_member->kind = RDI_MemberKind_DataField; - udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - udt_member->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - udt_member->off = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation); - } else { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - } break; - case DW_TagKind_Enumerator: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_EnumerationType) { - RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &udts, parent_type->udt); - udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - udt_member->val = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ConstValue); - } else { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - } break; + } break; + case DW_TagKind_StructureType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_UnionType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_EnumerationType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_Member: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + B32 is_parent_udt = parent_tag.kind == DW_TagKind_StructureType || + parent_tag.kind == DW_TagKind_ClassType || + parent_tag.kind == DW_TagKind_UnionType; + if (is_parent_udt) { + DW_Attrib *data_member_location = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_DataMemberLocation); + DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); + if (data_member_location_class == DW_AttribClass_LocList) { + AssertAlways(!"UDT member with multiple locations are not supported"); + } + + RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTMember *udt_member = rdim_udt_push_member(arena, &udts, parent_type->udt); + udt_member->kind = RDI_MemberKind_DataField; + udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + udt_member->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + udt_member->off = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation); + } else { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + } break; + case DW_TagKind_Enumerator: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_EnumerationType) { + RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &udts, parent_type->udt); + udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + udt_member->val = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ConstValue); + } else { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + } break; } } scratch_end(scratch); @@ -2315,39 +2318,112 @@ d2r_convert_symbols(Arena *arena, DW_TagNode *tag_node = it->tag_node; DW_Tag tag = tag_node->tag; switch (tag.kind) { - case DW_TagKind_Null: { InvalidPath; } break; - case DW_TagKind_ClassType: - case DW_TagKind_StructureType: - case DW_TagKind_UnionType: { - // visit children to collect methods and variables - } break; - case DW_TagKind_EnumerationType: - case DW_TagKind_SubroutineType: - case DW_TagKind_Typedef: - case DW_TagKind_BaseType: - case DW_TagKind_PointerType: - case DW_TagKind_RestrictType: - case DW_TagKind_VolatileType: - case DW_TagKind_ConstType: - case DW_TagKind_ArrayType: - case DW_TagKind_SubrangeType: - case DW_TagKind_Inheritance: - case DW_TagKind_Enumerator: - case DW_TagKind_Member: { - d2r_tag_iterator_skip_children(it); - } break; - case DW_TagKind_SubProgram: { - DW_InlKind inl = DW_Inl_NotInlined; - if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Inline)) { inl = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Inline); } - - switch (inl) { - case DW_Inl_NotInlined: { + case DW_TagKind_Null: { InvalidPath; } break; + case DW_TagKind_ClassType: + case DW_TagKind_StructureType: + case DW_TagKind_UnionType: { + // visit children to collect methods and variables + } break; + case DW_TagKind_EnumerationType: + case DW_TagKind_SubroutineType: + case DW_TagKind_Typedef: + case DW_TagKind_BaseType: + case DW_TagKind_PointerType: + case DW_TagKind_RestrictType: + case DW_TagKind_VolatileType: + case DW_TagKind_ConstType: + case DW_TagKind_ArrayType: + case DW_TagKind_SubrangeType: + case DW_TagKind_Inheritance: + case DW_TagKind_Enumerator: + case DW_TagKind_Member: { + d2r_tag_iterator_skip_children(it); + } break; + case DW_TagKind_SubProgram: { + DW_InlKind inl = DW_Inl_NotInlined; + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Inline)) { inl = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Inline); } + + switch (inl) { + case DW_Inl_NotInlined: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *container_type = 0; + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { + container_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); + } + + // get frame base expression + String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_FrameBase); + + // get proc container symbol + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP); + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + root_scope->symbol = proc; + + // fill out proc + proc->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); + proc->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + proc->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); + proc->type = proc_type; + proc->container_symbol = 0; + proc->container_type = container_type; + proc->root_scope = root_scope; + proc->location_cases = d2r_locset_from_attrib(arena, &scopes, root_scope, &locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); + + // sub program with user-defined parent tag is a method + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_ClassType || parent_tag.kind == DW_TagKind_StructureType) { + RDI_MemberKind member_kind = RDI_MemberKind_NULL; + DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Virtuality); + switch (virtuality) { + case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; + case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; + case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal + //default: InvalidPath; break; + } + + RDIM_Type *type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = member_kind; + member->type = type; + member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + } else if (parent_tag.kind != DW_TagKind_CompileUnit) { + //AssertAlways(!"unexpected tag"); + } + + it->stack->scope = root_scope; + } break; + case DW_Inl_DeclaredNotInlined: + case DW_Inl_DeclaredInlined: + case DW_Inl_Inlined: { + d2r_tag_iterator_skip_children(it); + } break; + default: InvalidPath; break; + } + } break; + case DW_TagKind_InlinedSubroutine: { U64 param_count = 0; RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); - + // get return type RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - + // fill out proc type RDIM_Type *proc_type = d2r_create_type(arena, type_table); proc_type->kind = RDI_TypeKind_Function; @@ -2355,199 +2431,126 @@ d2r_convert_symbols(Arena *arena, proc_type->direct_type = ret_type; proc_type->count = param_count; proc_type->param_types = params; - + // get container type - RDIM_Type *container_type = 0; + RDIM_Type *owner = 0; if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { - container_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); + owner = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); } - - // get frame base expression - String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_FrameBase); - - // get proc container symbol - RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP); - + + // fill out inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); + inline_site->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + inline_site->type = proc_type; + inline_site->owner = owner; + inline_site->line_table = 0; + // make scope Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - root_scope->symbol = proc; - - // fill out proc - proc->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); - proc->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - proc->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); - proc->type = proc_type; - proc->container_symbol = 0; - proc->container_type = container_type; - proc->root_scope = root_scope; - proc->location_cases = d2r_locset_from_attrib(arena, &scopes, root_scope, &locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); - - // sub program with user-defined parent tag is a method + root_scope->inline_site = inline_site; + } break; + case DW_TagKind_Variable: { + String8 name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + RDIM_Type *type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_ClassType || parent_tag.kind == DW_TagKind_StructureType) { - RDI_MemberKind member_kind = RDI_MemberKind_NULL; - DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Virtuality); - switch (virtuality) { - case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; - case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; - case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal - //default: InvalidPath; break; - } - - RDIM_Type *type = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); - member->kind = member_kind; - member->type = type; - member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - } else if (parent_tag.kind != DW_TagKind_CompileUnit) { - //AssertAlways(!"unexpected tag"); - } - - it->stack->scope = root_scope; - } break; - case DW_Inl_DeclaredNotInlined: - case DW_Inl_DeclaredInlined: - case DW_Inl_Inlined: { - d2r_tag_iterator_skip_children(it); - } break; - default: InvalidPath; break; - } - } break; - case DW_TagKind_InlinedSubroutine: { - U64 param_count = 0; - RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); - - // get return type - RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - - // fill out proc type - RDIM_Type *proc_type = d2r_create_type(arena, type_table); - proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; - proc_type->direct_type = ret_type; - proc_type->count = param_count; - proc_type->param_types = params; - - // get container type - RDIM_Type *owner = 0; - if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { - owner = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); - } - - // fill out inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); - inline_site->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - inline_site->type = proc_type; - inline_site->owner = owner; - inline_site->line_table = 0; - - // make scope - Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - root_scope->inline_site = inline_site; - } break; - case DW_TagKind_Variable: { - String8 name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - RDIM_Type *type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || - parent_tag.kind == DW_TagKind_InlinedSubroutine || - parent_tag.kind == DW_TagKind_LexicalBlock) { - RDIM_Scope *scope = it->stack->next->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &scopes, scope); - local->kind = RDI_LocalKind_Variable; - local->name = name; - local->type = type; - local->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); - } else { - - // NOTE: due to a bug in clang in stb_sprint.h local variables - // are declared in global scope without a name - if (name.size == 0) { break; } - - U64 voff = max_U64; - B32 is_thread_var = 0; - { - DW_Attrib *loc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_Location); - DW_AttribClass loc_class = dw_value_class_from_attrib(cu, loc_attrib); - if (loc_class == DW_AttribClass_ExprLoc) { - Temp temp = temp_begin(scratch.arena); - - String8 expr = dw_exprloc_from_attrib(input, cu, loc_attrib); - D2R_ValueType expr_type = 0; - RDIM_EvalBytecode bc = d2r_bytecode_from_expression(temp.arena, input, image_base, arch_addr_size, arch, cu->addr_lu, expr, cu, &expr_type); - - // evaluate bytecode to virutal offset if possible - if (expr_type == D2R_ValueType_Address) { - B32 is_static = rdim_is_eval_bytecode_static(bc); - if (is_static) { - voff = rdim_virt_off_from_eval_bytecode(bc, image_base); + if (parent_tag.kind == DW_TagKind_SubProgram || + parent_tag.kind == DW_TagKind_InlinedSubroutine || + parent_tag.kind == DW_TagKind_LexicalBlock) { + RDIM_Scope *scope = it->stack->next->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &scopes, scope); + local->kind = RDI_LocalKind_Variable; + local->name = name; + local->type = type; + local->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + } else { + + // NOTE: due to a bug in clang in stb_sprint.h local variables + // are declared in global scope without a name + if (name.size == 0) { break; } + + U64 voff = max_U64; + B32 is_thread_var = 0; + { + DW_Attrib *loc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_Location); + DW_AttribClass loc_class = dw_value_class_from_attrib(cu, loc_attrib); + if (loc_class == DW_AttribClass_ExprLoc) { + Temp temp = temp_begin(scratch.arena); + + String8 expr = dw_exprloc_from_attrib(input, cu, loc_attrib); + D2R_ValueType expr_type = 0; + RDIM_EvalBytecode bc = d2r_bytecode_from_expression(temp.arena, input, image_base, arch_addr_size, arch, cu->addr_lu, expr, cu, &expr_type); + + // evaluate bytecode to virutal offset if possible + if (expr_type == D2R_ValueType_Address) { + B32 is_static = rdim_is_eval_bytecode_static(bc); + if (is_static) { + voff = rdim_virt_off_from_eval_bytecode(bc, image_base); + } } + + // is this a thread variable? + is_thread_var = rdim_is_bytecode_tls_dependent(bc); + + temp_end(temp); } - - // is this a thread variable? - is_thread_var = rdim_is_bytecode_tls_dependent(bc); - - temp_end(temp); } + + RDIM_SymbolChunkList *var_chunks; U64 var_chunks_cap; + if (is_thread_var) { var_chunks = &tvars; var_chunks_cap = TVAR_CHUNK_CAP; } + else { var_chunks = &gvars; var_chunks_cap = GVAR_CHUNK_CAP; } + + RDIM_Symbol *var = rdim_symbol_chunk_list_push(arena, var_chunks, var_chunks_cap); + var->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); + var->name = name; + var->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); + var->type = type; + var->offset = voff; + var->container_symbol = 0; + var->container_type = 0; // TODO: NotImplemented; } - - RDIM_SymbolChunkList *var_chunks; U64 var_chunks_cap; - if (is_thread_var) { var_chunks = &tvars; var_chunks_cap = TVAR_CHUNK_CAP; } - else { var_chunks = &gvars; var_chunks_cap = GVAR_CHUNK_CAP; } - - RDIM_Symbol *var = rdim_symbol_chunk_list_push(arena, var_chunks, var_chunks_cap); - var->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); - var->name = name; - var->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); - var->type = type; - var->offset = voff; - var->container_symbol = 0; - var->container_type = 0; // TODO: NotImplemented; - } - } break; - case DW_TagKind_FormalParameter: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || parent_tag.kind == DW_TagKind_InlinedSubroutine) { - RDIM_Scope *scope = it->stack->next->scope; - RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); - param->kind = RDI_LocalKind_Parameter; - param->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); - param->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); - param->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); - } else { - // TODO: error handling - AssertAlways(!"this is a local variable"); - } - } break; - case DW_TagKind_LexicalBlock: { - DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); - if (parent_tag.kind == DW_TagKind_SubProgram || - parent_tag.kind == DW_TagKind_InlinedSubroutine || - parent_tag.kind == DW_TagKind_LexicalBlock) { - Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); - d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); - } - } break; - case DW_TagKind_CallSite: { - // TODO - } break; - case DW_TagKind_CallSiteParameter: { - // TODO - } break; - case DW_TagKind_Label: - case DW_TagKind_CompileUnit: - case DW_TagKind_UnspecifiedParameters: - case DW_TagKind_Namespace: - case DW_TagKind_ImportedDeclaration: - case DW_TagKind_PtrToMemberType: - case DW_TagKind_TemplateTypeParameter: - case DW_TagKind_ReferenceType: { - // TODO: - } break; - default: NotImplemented; break; + } break; + case DW_TagKind_FormalParameter: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || parent_tag.kind == DW_TagKind_InlinedSubroutine) { + RDIM_Scope *scope = it->stack->next->scope; + RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); + param->kind = RDI_LocalKind_Parameter; + param->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + param->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + param->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + } else { + // TODO: error handling + AssertAlways(!"this is a local variable"); + } + } break; + case DW_TagKind_LexicalBlock: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || + parent_tag.kind == DW_TagKind_InlinedSubroutine || + parent_tag.kind == DW_TagKind_LexicalBlock) { + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + } + } break; + case DW_TagKind_CallSite: { + // TODO + } break; + case DW_TagKind_CallSiteParameter: { + // TODO + } break; + case DW_TagKind_Label: + case DW_TagKind_CompileUnit: + case DW_TagKind_UnspecifiedParameters: + case DW_TagKind_Namespace: + case DW_TagKind_ImportedDeclaration: + case DW_TagKind_PtrToMemberType: + case DW_TagKind_TemplateTypeParameter: + case DW_TagKind_ReferenceType: { + // TODO: + } break; + default: NotImplemented; break; } } scratch_end(scratch); @@ -2559,68 +2562,68 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) Temp scratch = scratch_begin(&arena, 1); if (lane_idx() == 0) { //////////////////////////////// - + ProfBegin("compute exe hash"); U64 exe_hash = rdi_hash(params->exe_data.str, params->exe_data.size); ProfEnd(); - + //////////////////////////////// - + Arch arch = Arch_Null; U64 image_base = 0; DW_Input input = {0}; - + switch(params->exe_kind) { - default:{}break; - case ExecutableImageKind_CoffPe: { - PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); - String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); - COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(raw_sections, 0, sizeof(COFF_SectionHeader) * pe.section_count); - String8 string_table = str8_substr(params->exe_data, pe.string_table_range); - arch = pe.arch; - image_base = pe.image_base; - binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); - input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); - } break; - case ExecutableImageKind_Elf32: - case ExecutableImageKind_Elf64: { - ELF_Bin bin = elf_bin_from_data(scratch.arena, params->dbg_data); - arch = arch_from_elf_machine(bin.hdr.e_machine); - image_base = elf_base_addr_from_bin(&bin); - binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); - input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); - } break; + default:{}break; + case ExecutableImageKind_CoffPe: { + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); + String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); + COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(raw_sections, 0, sizeof(COFF_SectionHeader) * pe.section_count); + String8 string_table = str8_substr(params->exe_data, pe.string_table_range); + arch = pe.arch; + image_base = pe.image_base; + binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); + input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); + } break; + case ExecutableImageKind_Elf32: + case ExecutableImageKind_Elf64: { + ELF_Bin bin = elf_bin_from_data(scratch.arena, params->dbg_data); + arch = arch_from_elf_machine(bin.hdr.e_machine); + image_base = elf_base_addr_from_bin(&bin); + binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); + input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); + } break; } - + //////////////////////////////// - + top_level_info = rdim_make_top_level_info(params->exe_name, arch, exe_hash, binary_sections); - + //////////////////////////////// - + U64 arch_addr_size = rdi_addr_size_from_arch(top_level_info.arch); - + //////////////////////////////// - + RDIM_Scope *global_scope = rdim_scope_chunk_list_push(arena, &scopes, SCOPE_CHUNK_CAP); - + //////////////////////////////// - + ProfBegin("Parse Unit Contrib Map"); D2R_CompUnitContribMap cu_contrib_map = {0}; if (input.sec[DW_Section_ARanges].data.size) { cu_contrib_map = d2r_cu_contrib_map_from_aranges(arena, &input, image_base); } ProfEnd(); - + ProfBegin("Parse Comop Unit Ranges"); DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); Rng1U64List cu_range_list = dw_unit_ranges_from_data(scratch.arena, input.sec[DW_Section_Info].data); Rng1U64Array cu_ranges = rng1u64_array_from_list(scratch.arena, &cu_range_list); ProfEnd(); - + //////////////////////////////// - + ProfBegin("Parse Compile Unit Headers"); // TODO(rjf): parse should always be relaxed. any verification checks we do // should just be logged via log_info(...), and then the caller of this @@ -2631,9 +2634,9 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); } ProfEnd(); - + //////////////////////////////// - + ProfBegin("Parse Line Tables"); DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); for EachIndex(cu_idx, cu_ranges.count) { @@ -2644,15 +2647,15 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) cu_line_tables[cu_idx] = dw_parsed_line_table_from_data(scratch.arena, cu_stmt_list, &input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu); } ProfEnd(); - + //////////////////////////////// - + ProfBegin("Convert Line Tables"); HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); for EachIndex(cu_idx, cu_ranges.count) { cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); - + DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; @@ -2671,78 +2674,78 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } src_file_map[file_idx] = src_file; } - + for EachNode(line_seq, DW_LineSeqNode, line_table->first_seq) { if (line_seq->count == 0) { continue; } - + U64 *voffs = push_array(arena, U64, line_seq->count); U32 *line_nums = push_array(arena, U32, line_seq->count); U16 *col_nums = 0; U64 line_idx = 0; - + DW_LineNode *file_line_n = line_seq->first; U64 file_line_count = 0; - + for EachNode(line_n, DW_LineNode, file_line_n) { if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { U64 file_index = file_line_n->v.file_index; U64 *file_voffs = &voffs[line_idx]; U32 *file_line_nums = &line_nums[line_idx]; U16 *file_col_nums = 0; - + U64 lines_written = 0; U64 prev_ln = max_U64; DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; for (; file_line_n != sentinel; file_line_n = file_line_n->next) { if (file_line_n->v.line != prev_ln) { if (file_line_n->v.address == 0) { continue; } - + voffs[line_idx] = file_line_n->v.address - image_base; line_nums[line_idx] = file_line_n->v.line; - + ++lines_written; ++line_idx; - + prev_ln = file_line_n->v.line; } } - + RDIM_SrcFile *src_file = src_file_map[file_index]; RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, lines_written); rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); - + file_line_count = 1; } else { file_line_count += 1; } } - + // handle last line if (file_line_n) { U64 file_index = file_line_n->v.file_index; U64 *file_voffs = &voffs[line_idx]; U32 *file_line_nums = &line_nums[line_idx]; U16 *file_col_nums = 0; - + for (; file_line_n != 0; file_line_n = file_line_n->next, line_idx += 1) { // TODO: error handling AssertAlways(file_line_n->v.address >= image_base); voffs[line_idx] = file_line_n->v.address - image_base; line_nums[line_idx] = file_line_n->v.line; } - + RDIM_SrcFile *src_file = src_file_map[file_index]; RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, file_line_count); rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); } - + //Assert(line_idx == line_seq->count); } } ProfEnd(); - + //////////////////////////////// - + RDIM_Type *builtin_types[RDI_TypeKind_Count] = {0}; for (RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; type_kind <= RDI_TypeKind_LastBuiltIn; type_kind += 1) { RDIM_Type *type = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); @@ -2753,53 +2756,53 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } builtin_types[RDI_TypeKind_Void]->byte_size = arch_addr_size; builtin_types[RDI_TypeKind_Handle]->byte_size = arch_addr_size; - + builtin_types[RDI_TypeKind_Variadic] = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); builtin_types[RDI_TypeKind_Variadic]->kind = RDI_TypeKind_Variadic; - + //////////////////////////////// - + ProfBegin("Convert Units"); for EachIndex(cu_idx, cu_ranges.count) { Temp comp_temp = temp_begin(scratch.arena); - + DW_CompUnit *cu = &cu_arr[cu_idx]; - + // parse and build tag tree DW_TagTree tag_tree = dw_tag_tree_from_cu(comp_temp.arena, &input, cu); - + // skip DWO { if (cu->dwo_id) { goto next_cu; } - + String8 dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_DwoName); if (dwo_name.size) { goto next_cu; } - + String8 gnu_dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_GNU_DwoName); if (gnu_dwo_name.size) { goto next_cu; } } - + // build (info offset -> tag) hash table to resolve tags with abstract origin cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); - + // extract compile unit info String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); - + // init type table D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); type_table->ht = hash_table_init(comp_temp.arena, 0x4000); type_table->types = &types; type_table->type_chunk_cap = TYPE_CHUNK_CAP; type_table->builtin_types = builtin_types; - + // convert debug info d2r_convert_types(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); d2r_convert_udts(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); d2r_convert_symbols(arena, type_table, global_scope, &input, cu, cu_lang, arch_addr_size, image_base, arch, tag_tree.root); - + RDIM_Rng1U64ChunkList cu_voff_ranges = {0}; if (cu_idx < cu_contrib_map.count) { cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); @@ -2809,7 +2812,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) rdim_rng1u64_chunk_list_push(arena, &cu_voff_ranges, 512, (RDIM_Rng1U64){ .min = n->v.min, .max = n->v.max }); } } - + // convert compile unit { RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); @@ -2823,15 +2826,15 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) unit->line_table = cu_line_tables_rdi[cu_idx]; unit->voff_ranges = cu_voff_ranges; } - + next_cu:; temp_end(comp_temp); } ProfEnd(); } - + lane_sync(); - + RDIM_BakeParams bake_params = {0}; bake_params.top_level_info = top_level_info; bake_params.binary_sections = binary_sections; @@ -2846,7 +2849,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) bake_params.procedures = procs; bake_params.scopes = scopes; bake_params.inline_sites = inline_sites; - + scratch_end(scratch); return bake_params; } From 213dc6a6a78ccb60a8eff4a712b62d54a0926b4e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 11:38:58 -0700 Subject: [PATCH 047/133] fix busted ctrl memory stream, when bad memory & null terminated (#647); do not refresh repeatedly due to loading, if any raddbg window is not focused --- src/ctrl/ctrl_core.c | 6 +++--- src/raddbg/raddbg_core.c | 13 +++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 5dbaaacd..49499bd6 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6000,14 +6000,14 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) } //- rjf: do read - U64 range_size = 0; + U64 range_size = dim_1u64(vaddr_range_clamped); Arena *range_arena = 0; void *range_base = 0; U64 zero_terminated_size = 0; U64 pre_read_mem_gen = ctrl_mem_gen(); B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); + if(range_size != 0) { - range_size = dim_1u64(vaddr_range_clamped); U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); @@ -6053,7 +6053,7 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); } zero_terminated_size = range_size; - if(zero_terminated) + if(zero_terminated && range_base != 0) { for(U64 idx = 0; idx < bytes_read; idx += 1) { diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 57911805..73dfcfb1 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -11435,6 +11435,15 @@ rd_frame(void) // if(rd_state->frame_depth == 1) { + B32 any_window_is_focused = 0; + for(RD_WindowState *w = rd_state->first_window_state; w != &rd_nil_window_state; w = w->order_next) + { + if(os_window_is_focused(w->os)) + { + any_window_is_focused = 1; + break; + } + } F32 slow_rate = 1 - pow_f32(2, (-10.f * rd_state->frame_dt)); F32 fast_rate = 1 - pow_f32(2, (-40.f * rd_state->frame_dt)); for EachIndex(slot_idx, rd_state->view_state_slots_count) @@ -11449,7 +11458,7 @@ rd_frame(void) vs->scroll_pos.x.off += scroll_x_diff*rd_state->scrolling_animation_rate; vs->scroll_pos.y.off += scroll_y_diff*rd_state->scrolling_animation_rate; vs->loading_t += loading_t_diff * slow_rate; - if(abs_f32(loading_t_diff) > 0.01f || + if((any_window_is_focused && abs_f32(loading_t_diff) > 0.01f) || abs_f32(scroll_x_diff) > 0.01f || abs_f32(scroll_y_diff) > 0.01f) { @@ -11466,7 +11475,7 @@ rd_frame(void) RD_Cfg *vcfg = rd_cfg_from_id(vs->cfg_id); if(rd_cfg_child_from_string(vcfg, str8_lit("selected")) != &rd_nil_cfg) { - if(vs->loading_t_target > 0.5f) + if(vs->loading_t_target > 0.5f && any_window_is_focused) { rd_request_frame(); } From af4f18ed988158ac31f7ee20ef016a6a5481dd7f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 13:52:59 -0700 Subject: [PATCH 048/133] sketch out more flexible texture 2d format codes --- src/os/core/win32/os_core_win32.c | 1 + src/render/render_core.c | 40 +++++++++++++++++++++ src/render/render_core.h | 58 +++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 13602237..9e829e1f 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1156,6 +1156,7 @@ internal void os_mutex_release(Mutex mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); + DeleteCriticalSection(&entity->mutex); os_w32_entity_release(entity); } diff --git a/src/render/render_core.c b/src/render/render_core.c index 3e5723c4..09ab175f 100644 --- a/src/render/render_core.c +++ b/src/render/render_core.c @@ -9,6 +9,46 @@ //////////////////////////////// //~ rjf: Helpers +internal U64 +r_bytes_per_pixel_from_tex2dfmt(R_Tex2DFmt fmt) +{ + U64 num_bits = 0; + for EachIndex(channel_idx, 4) + { + R_ChannelSizeKind size_kind = r_size_kind_from_tex2dfmt_channel(fmt, channel_idx); + switch(size_kind) + { + default:{}break; + case R_ChannelSizeKind_2: {num_bits += 2;}break; + case R_ChannelSizeKind_8: {num_bits += 8;}break; + case R_ChannelSizeKind_10:{num_bits += 10;}break; + case R_ChannelSizeKind_11:{num_bits += 11;}break; + case R_ChannelSizeKind_16:{num_bits += 16;}break; + case R_ChannelSizeKind_24:{num_bits += 24;}break; + case R_ChannelSizeKind_32:{num_bits += 32;}break; + } + } + U64 num_bits_rounded = num_bits+7; + num_bits_rounded -= num_bits_rounded%8; + U64 num_bytes = num_bits_rounded/8; + return num_bytes; +} + +internal Mat4x4F32 +r_sample_channel_map_from_tex2dfmt(R_Tex2DFmt fmt) +{ + Mat4x4F32 result = + { + { + {1, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 1}, + } + }; + return result; +} + internal Mat4x4F32 r_sample_channel_map_from_tex2dformat(R_Tex2DFormat fmt) { diff --git a/src/render/render_core.h b/src/render/render_core.h index c23c0503..e9182497 100644 --- a/src/render/render_core.h +++ b/src/render/render_core.h @@ -14,6 +14,62 @@ //////////////////////////////// //~ rjf: Enums +typedef U8 R_ChannelCode; // 3 bits +typedef enum R_ChannelCodeEnum +{ + R_ChannelCode_Null, + R_ChannelCode_R, + R_ChannelCode_G, + R_ChannelCode_B, + R_ChannelCode_A, +} +R_ChannelCodeEnum; + +typedef U8 R_ChannelSizeKind; // 3 bits +typedef enum R_ChannelSizeKindEnum +{ + R_ChannelSizeKind_Null, + R_ChannelSizeKind_2, + R_ChannelSizeKind_8, + R_ChannelSizeKind_10, + R_ChannelSizeKind_11, + R_ChannelSizeKind_16, + R_ChannelSizeKind_24, + R_ChannelSizeKind_32, +} +R_ChannelSizeKindEnum; + +typedef U8 R_ChannelTypeKind; // 3 bits +typedef enum R_ChannelTypeKindEnum +{ + R_ChannelTypeKind_Null, + R_ChannelTypeKind_UInt, + R_ChannelTypeKind_SInt, + R_ChannelTypeKind_UNorm, + R_ChannelTypeKind_SNorm, + R_ChannelTypeKind_Float, +} +R_ChannelTypeKindEnum; + +typedef U64 R_Tex2DFmt; +// +// set of channels, each channel including {code, size, type kind}, 3 bits each: +// [0, 3) -> channel code +// [3, 6) -> channel size +// [6, 9) -> channel type kind +// +// 9 bits per channel, * number of channels, e.g. 4 channels -> 36 bits + +#define R_Channel(channel_idx, code_name, size_kind_name, type_kind_name) ((((U64)(R_ChannelCode_##code_name & 0x7)) | ((U64)(R_ChannelSizeKind_##size_kind_name & 0x7) << 3) | ((U64)(R_ChannelTypeKind_##type_kind_name & 0x7) << 6)) << ((channel_idx)*9)) +#define r_code_from_tex2dfmt_channel(fmt, channel_idx) ((R_ChannelCode)(((fmt) & (0x7<<((channel_idx)*9))) >> ((channel_idx)*9))) +#define r_size_kind_from_tex2dfmt_channel(fmt, channel_idx) ((R_ChannelSizeKind)(((fmt) & (0x38<<((channel_idx)*9))) >> ((channel_idx)*9 + 3))) +#define r_type_kind_from_tex2dfmt_channel(fmt, channel_idx) ((R_ChannelTypeKind)(((fmt) & (0x1c0<<((channel_idx)*9))) >> ((channel_idx)*9 + 6))) + +#define R_Tex2DFmt_R8 (R_Channel(0, R, 8, UInt)) +#define R_Tex2DFmt_RG8 (R_Channel(0, R, 8, UInt) | R_Channel(1, G, 8, UInt)) +#define R_Tex2DFmt_RGB8 (R_Channel(0, R, 8, UInt) | R_Channel(1, G, 8, UInt) | R_Channel(2, B, 8, UInt)) +#define R_Tex2DFmt_RGBA8 (R_Channel(0, R, 8, UInt) | R_Channel(1, G, 8, UInt) | R_Channel(2, B, 8, UInt) | R_Channel(3, A, 8, UInt)) + typedef U32 R_GeoVertexFlags; enum { @@ -197,6 +253,8 @@ struct R_PassList //////////////////////////////// //~ rjf: Helpers +internal U64 r_bytes_per_pixel_from_tex2dfmt(R_Tex2DFmt fmt); +internal Mat4x4F32 r_sample_channel_map_from_tex2dfmt(R_Tex2DFmt fmt); internal Mat4x4F32 r_sample_channel_map_from_tex2dformat(R_Tex2DFormat fmt); //////////////////////////////// From d2216019b9460afa80cb712b6340746040d5e655 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 14:23:34 -0700 Subject: [PATCH 049/133] prefer primary module, or modules with space matching the primary module's, when doing top-level debug info name matching in eval --- src/eval/eval_ir.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 164b5849..8241b0d3 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -1920,7 +1920,11 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I { module = &e_base_ctx->modules[idx]; dbgi_idx = (U32)idx; - break; + if(module == e_base_ctx->primary_module || + e_space_match(module->space, e_base_ctx->primary_module->space)) + { + break; + } } } From 835a57f91887a0a97ad7db40904d0f8fd9975ed7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 14:31:57 -0700 Subject: [PATCH 050/133] extend dbgi matching system with preferred dbgi key, to disambiguate results - fill with primary module dbgi in eval, to always prefer selected thread context when applicable --- src/ctrl/ctrl_core.c | 1 + src/dbg_info/dbg_info.c | 20 +++++++++++++------- src/dbg_info/dbg_info.h | 2 +- src/eval/eval_core.h | 3 ++- src/eval/eval_ir.c | 4 ++-- src/eval/eval_parse.c | 2 +- src/raddbg/raddbg_core.c | 5 +++-- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 49499bd6..8432c710 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -4385,6 +4385,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C //- rjf: fill evaluation module info eval_modules[eval_module_idx].arch = arch; + eval_modules[eval_module_idx].dbgi_key = dbgi_key; eval_modules[eval_module_idx].rdi = rdi; eval_modules[eval_module_idx].vaddr_range = mod->vaddr_range; eval_modules[eval_module_idx].space = e_space_make(CTRL_EvalSpaceKind_Entity); diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index a259646e..7333103e 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -1431,11 +1431,13 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) //- rjf: unpack key U64 index = 0; - String8 name = {0}; + String8 name = {0}; + DI_Key preferred_key = {0}; { U64 key_read_off = 0; - key_read_off += str8_deserial_read_struct(key, key_read_off, &index); - key_read_off += str8_deserial_read_struct(key, key_read_off, &name.size); + key_read_off += str8_deserial_read_struct(key, key_read_off, &index); + key_read_off += str8_deserial_read_struct(key, key_read_off, &preferred_key); + key_read_off += str8_deserial_read_struct(key, key_read_off, &name.size); name.str = push_array_no_zero(scratch.arena, U8, name.size); key_read_off += str8_deserial_read(key, key_read_off, name.str, name.size, 1); } @@ -1501,8 +1503,11 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { if(lane_matches[idx].idx != 0) { - match = lane_matches[idx]; - break; + match = lane_matches[idx]; + if(di_key_match(di_key_zero(), preferred_key) || di_key_match(match.key, preferred_key)) + { + break; + } } } @@ -1523,7 +1528,7 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) } internal DI_Match -di_match_from_string(String8 string, U64 index, U64 endt_us) +di_match_from_string(String8 string, U64 index, DI_Key preferred_dbgi_key, U64 endt_us) { DI_Match result = {0}; Access *access = access_open(); @@ -1531,7 +1536,8 @@ di_match_from_string(String8 string, U64 index, U64 endt_us) { String8List key_parts = {0}; str8_list_push(scratch.arena, &key_parts, str8_struct(&index)); - str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); + str8_list_push(scratch.arena, &key_parts, str8_struct(&preferred_dbgi_key)); + str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); str8_list_push(scratch.arena, &key_parts, string); String8 key = str8_list_join(scratch.arena, &key_parts, 0); AC_Artifact artifact = ac_artifact_from_key(access, key, di_match_artifact_create, 0, endt_us, .flags = AC_Flag_Wide, .gen = di_load_gen()); diff --git a/src/dbg_info/dbg_info.h b/src/dbg_info/dbg_info.h index 5e2dbbb3..36aca803 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -358,6 +358,6 @@ internal DI_SearchItemArray di_search_item_array_from_target_query(Access *acces //~ rjf: Match Artifact Cache Hooks / Lookups internal AC_Artifact di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); -internal DI_Match di_match_from_string(String8 string, U64 index, U64 endt_us); +internal DI_Match di_match_from_string(String8 string, U64 index, DI_Key preferred_dbgi_key, U64 endt_us); #endif // DBG_INFO_H diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index e1baf525..e658fdff 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -570,6 +570,7 @@ struct E_ConsTypeSlot typedef struct E_Module E_Module; struct E_Module { + DI_Key dbgi_key; RDI_Parsed *rdi; Rng1U64 vaddr_range; Arch arch; @@ -1111,7 +1112,7 @@ read_only global E_String2ExprMap e_string2expr_map_nil = {0}; read_only global E_Expr e_expr_nil = {&e_expr_nil, &e_expr_nil, &e_expr_nil, &e_expr_nil, &e_expr_nil}; read_only global E_IRNode e_irnode_nil = {&e_irnode_nil, &e_irnode_nil, &e_irnode_nil}; read_only global E_Eval e_eval_nil = {{0}, {0}, {0}, &e_expr_nil, {&e_irnode_nil}}; -read_only global E_Module e_module_nil = {&rdi_parsed_nil}; +read_only global E_Module e_module_nil = {{0}, &rdi_parsed_nil}; read_only global E_CacheBundle e_cache_bundle_nil = {0, {0}, {0}, {0}, {{0}, 0, &e_expr_nil, &e_expr_nil}, {&e_irnode_nil}}; thread_static E_BaseCtx *e_base_ctx = 0; thread_static E_IRCtx *e_ir_ctx = 0; diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 8241b0d3..42fca2f9 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -1871,7 +1871,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I Access *access = access_open(); // rjf: find match - DI_Match match = di_match_from_string(string, 0, 0); + DI_Match match = di_match_from_string(string, 0, e_base_ctx->primary_module->dbgi_key, 0); if(match.idx == 0) { String8List namespaceified_strings = {0}; @@ -1900,7 +1900,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } for(String8Node *n = namespaceified_strings.first; n != 0; n = n->next) { - match = di_match_from_string(n->string, 0, 0); + match = di_match_from_string(n->string, 0, e_base_ctx->primary_module->dbgi_key, 0); if(match.idx != 0) { break; diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index 269b41be..4b59a1ac 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -585,7 +585,7 @@ e_leaf_type_key_from_name(String8 name) E_TypeKey key = e_leaf_builtin_type_key_from_name(name); if(!e_type_key_match(e_type_key_zero(), key)) { - DI_Match match = di_match_from_string(name, 0, 0); + DI_Match match = di_match_from_string(name, 0, e_base_ctx->primary_module->dbgi_key, 0); if(match.section_kind == RDI_SectionKind_TypeNodes) { Access *access = access_open(); diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 73dfcfb1..973cfeb4 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -10311,7 +10311,7 @@ rd_code_color_slot_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 // rjf: try to map using asynchronous matching system if(!mapped && kind == TXT_TokenKind_Identifier) { - DI_Match match = di_match_from_string(string, 0, 0); + DI_Match match = di_match_from_string(string, 0, e_base_ctx->primary_module->dbgi_key, 0); RDI_SectionKind section_kind = match.section_kind; mapped = 1; switch(section_kind) @@ -11887,6 +11887,7 @@ rd_frame(void) CTRL_Entity *m = all_modules.v[eval_module_idx]; DI_Key dbgi_key = ctrl_dbgi_key_from_module(m); eval_modules[eval_module_idx].arch = m->arch; + eval_modules[eval_module_idx].dbgi_key = dbgi_key; eval_modules[eval_module_idx].rdi = di_rdi_from_key(rd_state->frame_access, dbgi_key, 0, 0); eval_modules[eval_module_idx].vaddr_range = m->vaddr_range; eval_modules[eval_module_idx].space = rd_eval_space_from_ctrl_entity(ctrl_entity_ancestor_from_kind(m, CTRL_EntityKind_Process), RD_EvalSpaceKind_CtrlEntity); @@ -14769,7 +14770,7 @@ rd_frame(void) DI_Key voff_dbgi_key = {0}; if(!name_resolved) { - DI_Match match = di_match_from_string(name, 0, 0); + DI_Match match = di_match_from_string(name, 0, e_base_ctx->primary_module->dbgi_key, 0); if(match.section_kind == RDI_SectionKind_Procedures) { Access *access = access_open(); From 284524e0c4bc1ce0280aa9b4d68dd3cce51cfa7f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 14:35:41 -0700 Subject: [PATCH 051/133] fix incorrect ctx check in win32 demon --- src/demon/win32/demon_core_win32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index 5c93e2d2..ea1f3118 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -2882,7 +2882,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { single_step_thread_ctx = 0; } - if(ctx != 0) + if(single_step_thread_ctx != 0) { U64 rflags = single_step_thread_ctx->EFlags|0x2; U64 new_rflags = rflags & ~0x100; From 6f4e78d06c86308d915ea2df43d1656442ddd0fc Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 14:55:51 -0700 Subject: [PATCH 052/133] do not try to release failed-creation textures --- src/render/d3d11/render_d3d11.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/render/d3d11/render_d3d11.c b/src/render/d3d11/render_d3d11.c index 444199cf..c1170ead 100644 --- a/src/render/d3d11/render_d3d11.c +++ b/src/render/d3d11/render_d3d11.c @@ -831,8 +831,14 @@ r_end_frame(void) tex = next) { next = tex->next; - tex->view->lpVtbl->Release(tex->view); - tex->texture->lpVtbl->Release(tex->texture); + if(tex->view != 0) + { + tex->view->lpVtbl->Release(tex->view); + } + if(tex->texture != 0) + { + tex->texture->lpVtbl->Release(tex->texture); + } tex->view = 0; tex->texture = 0; tex->generation += 1; @@ -843,8 +849,12 @@ r_end_frame(void) buf = next) { next = buf->next; - buf->buffer->lpVtbl->Release(buf->buffer); + if(buf->buffer != 0) + { + buf->buffer->lpVtbl->Release(buf->buffer); + } buf->generation += 1; + buf->buffer = 0; SLLStackPush(r_d3d11_state->first_free_buffer, buf); } arena_clear(r_d3d11_state->buffer_flush_arena); From 2a7177861b60e9a7be60399988f97b3cb76237f3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 17:06:00 -0700 Subject: [PATCH 053/133] remove extra watch row column cases - simplify most cases down to expr / eval. use extra 'note' for watch window cells to annotate type info - this sacrifices the full type evaluation cell, and instead uses a small extra bit of text to denote the type for quick reading. but this full type cell is not needed in most cases, and it can always be reobtained with an explicit `typeof` evaluation. --- src/eval/eval_ir.c | 8 ++ src/raddbg/raddbg_core.c | 39 ++++++++- src/raddbg/raddbg_eval.c | 10 --- src/raddbg/raddbg_views.c | 163 ++++++++++-------------------------- src/raddbg/raddbg_views.h | 2 +- src/raddbg/raddbg_widgets.c | 13 ++- src/raddbg/raddbg_widgets.h | 2 + 7 files changed, 102 insertions(+), 135 deletions(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 42fca2f9..f38c2557 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -1815,6 +1815,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), local->type_idx, module_idx); // rjf: extract local's location block + B32 got_location_block = 0; U64 ip_voff = e_base_ctx->thread_ip_voff; for(U32 loc_block_idx = local->location_first; loc_block_idx < local->location_opl; @@ -1825,8 +1826,15 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I { mapped_location_block_module = module; mapped_location_block = block; + got_location_block = 1; } } + + // rjf: no location block -> error + if(!got_location_block) + { + e_msgf(arena, &result.msgs, E_MsgKind_MissingInfo, expr->range, "Could not find location info for `%S`.", string__redirected); + } } }break; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 973cfeb4..2c907bda 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -5041,6 +5041,39 @@ rd_view_ui(Rng2F32 rect) { cell_params.flags &= ~RD_CellFlag_NoBackground; } + + // rjf: apply type note + if(!(cell_info.flags & RD_WatchCellFlag_NoEval) && + cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && + row_info->callstack_thread == &ctrl_entity_nil && + e_type_kind_from_key(cell->eval.irtree.type_key) != E_TypeKind_Function) + UI_FontSize(ui_top_font_size()*0.8f) + { + if(cell_width_px >= ui_top_font_size()*8.f) + { + E_TypeKey type_key = cell->eval.irtree.type_key; + String8 note_string = {0}; + if(cell->eval.irtree.mode == E_Mode_Null && (row->block->eval.irtree.mode != E_Mode_Null || row->block->parent == &ev_nil_block)) + { + note_string = str8f(scratch.arena, "type (size: %I64u)", e_type_byte_size_from_key(type_key)); + } + else if(cell->eval.irtree.mode == E_Mode_Null) + { + note_string = str8f(scratch.arena, "type (size: %I64u, offset: %I64u)", + e_type_byte_size_from_key(type_key), + cell->eval.value.u64); + } + else + { + note_string = e_type_string_from_key(scratch.arena, type_key); + } + DR_FStrList note_fstrs = rd_fstrs_from_code_string(scratch.arena, 1, 0, ui_color_from_name(str8_lit("text")), note_string); + F32 note_fstrs_width_px = dr_dim_from_fstrs(0, ¬e_fstrs).x + 10; + note_fstrs_width_px = Min(note_fstrs_width_px, cell_width_px*0.5f); + cell_params.note_fstrs = note_fstrs; + cell_params.note_width = ui_px(note_fstrs_width_px, 1); + } + } } // rjf: build @@ -6448,15 +6481,15 @@ rd_window_frame(void) RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); if(rdi->raw_data_size != 0) { - ui_labelf("Symbols successfully loaded from %S", dbg_info_entity->string); + ui_labelf("Debug information successfully loaded from %S", dbg_info_entity->string); } else if(dbg_info_entity->string.size != 0) { - ui_labelf("Symbols not found at %S", dbg_info_entity->string); + ui_labelf("Debug information not found at %S", dbg_info_entity->string); } else if(dbg_info_entity->string.size == 0) { - ui_labelf("Symbol information not found in module file"); + ui_labelf("Debug information location not found in module file"); } access_close(access); } diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 4de6e60d..82c501ce 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -208,9 +208,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(registers) CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); Arch arch = thread->arch; U64 reg_count = regs_reg_code_count_from_arch(arch); - U64 alias_count = regs_alias_code_count_from_arch(arch); String8 *reg_strings = regs_reg_code_string_table_from_arch(arch); - String8 *alias_strings = regs_alias_code_string_table_from_arch(arch); String8List exprs_list = {0}; for(U64 idx = 1; idx < reg_count; idx += 1) { @@ -220,14 +218,6 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(registers) str8_list_push(scratch.arena, &exprs_list, reg_strings[idx]); } } - for(U64 idx = 1; idx < alias_count; idx += 1) - { - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, alias_strings[idx]); - if(matches.count == matches.needle_part_count) - { - str8_list_push(scratch.arena, &exprs_list, alias_strings[idx]); - } - } String8Array *accel = push_array(arena, String8Array, 1); *accel = str8_array_from_list(arena, &exprs_list); E_TypeExpandInfo info = {accel, accel->count}; diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index beb48052..db9294a7 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -848,20 +848,15 @@ rd_id_from_watch_cell(RD_WatchCell *cell) return result; } -internal RD_WatchCell * -rd_watch_cell_list_push(Arena *arena, RD_WatchCellList *list) -{ - RD_WatchCell *cell = push_array(arena, RD_WatchCell, 1); - cell->index = list->count; - SLLQueuePush(list->first, list->last, cell); - list->count += 1; - return cell; -} - internal RD_WatchCell * rd_watch_cell_list_push_new_(Arena *arena, RD_WatchCellList *list, RD_WatchCell *params) { - RD_WatchCell *cell = rd_watch_cell_list_push(arena, list); + RD_WatchCell *cell = push_array(arena, RD_WatchCell, 1); + { + cell->index = list->count; + SLLQueuePush(list->first, list->last, cell); + list->count += 1; + } U64 index = cell->index; MemoryCopyStruct(cell, params); cell->index = index; @@ -869,6 +864,7 @@ rd_watch_cell_list_push_new_(Arena *arena, RD_WatchCellList *list, RD_WatchCell { cell->pct = cell->default_pct; } + list->pct_sum += cell->pct; cell->next = 0; return cell; } @@ -1153,29 +1149,15 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) //////////////////////////// //- rjf: @watch_row_build_cells files / folders // - else if(row->eval.space.kind == E_SpaceKind_FileSystem) + else if(row->eval.space.kind == E_SpaceKind_FileSystem && + e_type_kind_from_key(row->eval.irtree.type_key) == E_TypeKind_Set) { E_Type *type = e_type_from_key(row->eval.irtree.type_key); - if(type->kind == E_TypeKind_Set) + String8 file_path = e_string_from_id(row->eval.value.u64); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented|RD_WatchCellFlag_Button|RD_WatchCellFlag_IsNonCode, .pct = 1.f); + if(str8_match(type->name, str8_lit("file"), 0)) { - String8 file_path = e_string_from_id(row->eval.value.u64); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented|RD_WatchCellFlag_Button|RD_WatchCellFlag_IsNonCode, .pct = 1.f); - if(str8_match(type->name, str8_lit("file"), 0)) - { - info.can_expand = 0; - } - } - else - { - info.cell_style_key = str8_lit("expr_and_eval"); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; - F32 next_pct = 0; -#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .default_pct = 0.35f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.65f, .pct = take_pct()); -#undef take_pct + info.can_expand = 0; } } @@ -1399,33 +1381,6 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_Indented, .pct = 1.f); } - //////////////////////////// - //- rjf: @watch_row_build_cells meta-evaluation catch-all: expression / value - // - else if(row->eval.space.kind == RD_EvalSpaceKind_MetaCfg || - row->eval.space.kind == RD_EvalSpaceKind_MetaCmd || - row->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || - row->eval.space.kind == E_SpaceKind_File) - { - E_TypeKey substantive_row_eval_type = e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_Meta); - if(e_type_kind_from_key(substantive_row_eval_type) == E_TypeKind_Array && - e_type_kind_from_key(e_type_key_direct(substantive_row_eval_type)) == E_TypeKind_U8) - { - info.can_expand = 0; - } - info.cell_style_key = str8_lit("expr_and_eval"); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; - F32 next_pct = 0; -#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, - .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .default_pct = 0.35f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, - .default_pct = 0.65f, .pct = take_pct()); -#undef take_pct - } - //////////////////////////// //- rjf: @watch_row_build_cells procedures (expr & eval, mostly expr) // @@ -1466,71 +1421,24 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) #undef take_pct } - //////////////////////////// - //- rjf: @watch_row_build_cells error rows - // - else if(row->eval.irtree.mode == E_Mode_Null && row->eval.msgs.max_kind > E_MsgKind_Null) - { - info.cell_style_key = str8_lit("expr_and_error"); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; - F32 next_pct = 0; -#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, - .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, - .default_pct = 0.60f, - .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.40f, .pct = take_pct()); -#undef take_pct - } - - //////////////////////////// - //- rjf: @watch_row_build_cells root-level type rows - // - else if(row->eval.irtree.mode == E_Mode_Null && (row->block->eval.irtree.mode != E_Mode_Null || row->block->parent == &ev_nil_block)) - { - info.cell_style_key = str8_lit("root_type"); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; - F32 next_pct = 0; -#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, - .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, - .default_pct = 0.50f, - .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "typeof($)"), .default_pct = 0.35f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "sizeof($)"), .default_pct = 0.15f, .pct = take_pct()); -#undef take_pct - } - - //////////////////////////// - //- rjf: @watch_row_build_cells sub-type rows - // - else if(row->eval.irtree.mode == E_Mode_Null) - { - info.cell_style_key = str8_lit("sub_type"); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; - F32 next_pct = 0; -#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, - .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, - .default_pct = 0.35f, - .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "typeof($)"), .default_pct = 0.35f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "sizeof($)"), .default_pct = 0.15f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "(uint64)(&$)"), .default_pct = 0.15f, .pct = take_pct()); -#undef take_pct - } - //////////////////////////// //- rjf: @watch_row_build_cells catchall (normal rows) // else { + // rjf: disable expansion on meta string evaluations + if(row->eval.space.kind == RD_EvalSpaceKind_MetaCfg || + row->eval.space.kind == RD_EvalSpaceKind_MetaCmd || + row->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || + row->eval.space.kind == E_SpaceKind_File) + { + E_TypeKey substantive_row_eval_type = e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_Meta); + if(e_type_kind_from_key(substantive_row_eval_type) == E_TypeKind_Array && + e_type_kind_from_key(e_type_key_direct(substantive_row_eval_type)) == E_TypeKind_U8) + { + info.can_expand = 0; + } + } info.cell_style_key = str8_lit("normal"); RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); @@ -1541,11 +1449,26 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .default_pct = 0.35f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.40f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "typeof($)"), .default_pct = 0.25f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.65f, .pct = take_pct()); #undef take_pct } + //////////////////////////// + //- rjf: normalize all cell widths + // + if(abs_f32(info.cells.pct_sum - 1.f) > 0.01f) + { + F32 sum = info.cells.pct_sum; + if(sum <= 0) + { + sum = 1.f; + } + for(RD_WatchCell *c = info.cells.first; c != 0; c = c->next) + { + c->pct /= sum; + } + } + scratch_end(scratch); } return info; diff --git a/src/raddbg/raddbg_views.h b/src/raddbg/raddbg_views.h index f13b2ecc..b4f40702 100644 --- a/src/raddbg/raddbg_views.h +++ b/src/raddbg/raddbg_views.h @@ -114,6 +114,7 @@ struct RD_WatchCellList RD_WatchCell *first; RD_WatchCell *last; U64 count; + F32 pct_sum; }; typedef struct RD_WatchRowInfo RD_WatchRowInfo; @@ -206,7 +207,6 @@ internal RD_CodeViewBuildResult rd_code_view_build(Arena *arena, RD_CodeViewStat //- rjf: cell list building internal U64 rd_id_from_watch_cell(RD_WatchCell *cell); -internal RD_WatchCell *rd_watch_cell_list_push(Arena *arena, RD_WatchCellList *list); internal RD_WatchCell *rd_watch_cell_list_push_new_(Arena *arena, RD_WatchCellList *list, RD_WatchCell *params); #define rd_watch_cell_list_push_new(arena, list, kind_, eval_, ...) rd_watch_cell_list_push_new_((arena), (list), &(RD_WatchCell){.kind = (kind_), .eval = (eval_), __VA_ARGS__}) diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index e61c9d4c..36cbe7f6 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -602,7 +602,7 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e if(rdi->raw_data_size == 0) { dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Symbols not found)"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .size = extras_size, .color = secondary_color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Debug information not loaded)"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .size = extras_size, .color = secondary_color); } access_close(access); } @@ -3372,8 +3372,10 @@ rd_cell(RD_CellParams *params, String8 string) B32 build_bindings = !!(params->flags & RD_CellFlag_Bindings) && !is_focus_active; B32 build_lhs_name_desc = (params->meta_fstrs.node_count != 0 || params->description.size != 0); B32 build_line_edit = (params->pre_edit_value.size != 0 || params->value_fstrs.node_count != 0); + B32 build_note = (params->note_fstrs.node_count != 0 && !is_focus_active); DR_FStrList lhs_name_fstrs = params->meta_fstrs; DR_FStrList value_name_fstrs = params->value_fstrs; + DR_FStrList note_fstrs = params->note_fstrs; ////////////////////////////// //- rjf: determine autocompletion string @@ -3801,6 +3803,15 @@ rd_cell(RD_CellParams *params, String8 string) } } + ////////////////////////////// + //- rjf: build notes + // + if(build_note) UI_Parent(box) UI_PrefWidth(params->note_width) + { + UI_Box *note_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fstrs(note_box, ¬e_fstrs); + } + ////////////////////////////// //- rjf: do non-textual edits (delete, copy, cut) // diff --git a/src/raddbg/raddbg_widgets.h b/src/raddbg/raddbg_widgets.h index 88678f99..5d5a509e 100644 --- a/src/raddbg/raddbg_widgets.h +++ b/src/raddbg/raddbg_widgets.h @@ -51,6 +51,8 @@ struct RD_CellParams String8 pre_edit_value; DR_FStrList meta_fstrs; DR_FStrList value_fstrs; + DR_FStrList note_fstrs; + UI_Size note_width; String8 search_needle; String8 description; From b02a815a27e1135a0c9a63b2b6069e79294179bd Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 6 Oct 2025 17:34:19 -0700 Subject: [PATCH 054/133] flush dwm on resize; use WS_EX_NOREDIRECTIONBITMAP window flag to avoid dwm bug --- src/os/gfx/win32/os_gfx_win32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index 5b8ab880..68ff15a6 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -369,6 +369,7 @@ os_w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) BeginPaint(hwnd, &ps); update(); EndPaint(hwnd, &ps); + DwmFlush(); }break; case WM_CLOSE: @@ -1056,7 +1057,7 @@ os_window_open(Rng2F32 rect, OS_WindowFlags flags, String8 title) Temp scratch = scratch_begin(0, 0); String16 title16 = str16_from_8(scratch.arena, title); os_w32_new_window_custom_border = custom_border; - hwnd = CreateWindowExW(WS_EX_APPWINDOW, + hwnd = CreateWindowExW(WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP, L"graphical-window", (WCHAR*)title16.str, WS_OVERLAPPEDWINDOW | WS_SIZEBOX, From d20cce536a26286426c938810f78f64f69a5ab02 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 10:20:19 -0700 Subject: [PATCH 055/133] rdim bake parameter joining, source rdi bake parameters from *all* inputs, and not mutually-exclusive dwarf vs. pdb cases --- project.4coder | 4 +- src/lib_rdi_make/rdi_make.c | 85 ++++++++++++++++++++++++- src/lib_rdi_make/rdi_make.h | 5 ++ src/radbin/radbin.c | 96 ++++++++++++++++------------- src/rdi_from_dwarf/rdi_from_dwarf.c | 31 +++++++--- 5 files changed, 167 insertions(+), 54 deletions(-) diff --git a/project.4coder b/project.4coder index 9dc98bf1..1bb5aad9 100644 --- a/project.4coder +++ b/project.4coder @@ -46,8 +46,8 @@ load_paths = commands = { //- rjf: [raddbg] - .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index d4416425..ead2004e 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -955,7 +955,7 @@ rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp RDIM_SLLQueuePush(bytecode->first_op, bytecode->last_op, node); bytecode->op_count += 1; bytecode->encoded_size += 1 + p_size; - + return node; } @@ -1171,6 +1171,89 @@ rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RD return rdim_push_location_case(arena, scopes, &local->location_cases, location, voff_range); } +//////////////////////////////// +//~ rjf: [Building] Bake Parameter Joining + +RDI_PROC void +rdim_bake_params_concat_in_place(RDIM_BakeParams *dst, RDIM_BakeParams *src) +{ + // rjf: join top-level info (deduplicate - throw away conflicts) + { + if(dst->top_level_info.arch == RDI_Arch_NULL) + { + dst->top_level_info.arch = src->top_level_info.arch; + } + if(dst->top_level_info.exe_name.size == 0) + { + dst->top_level_info.exe_name = src->top_level_info.exe_name; + } + if(dst->top_level_info.exe_hash == 0) + { + dst->top_level_info.exe_hash = src->top_level_info.exe_hash; + } + if(dst->top_level_info.voff_max == 0) + { + dst->top_level_info.voff_max = src->top_level_info.voff_max; + } + if(dst->top_level_info.producer_name.size == 0) + { + dst->top_level_info.producer_name = src->top_level_info.producer_name; + } + } + + // rjf: join binary sections (deduplicate) + { + RDIM_Temp scratch = rdim_scratch_begin(0, 0); + RDI_U64 slots_count = 256; + RDIM_BinarySectionNode **slots = rdim_push_array(scratch.arena, RDIM_BinarySectionNode *, slots_count); + for(RDIM_BinarySectionNode *n = dst->binary_sections.first; n != 0; n = n->next) + { + RDIM_BinarySectionNode *hash_node = rdim_push_array(scratch.arena, RDIM_BinarySectionNode, 1); + RDI_U64 hash = rdi_hash(n->v.name.str, n->v.name.size); + RDI_U64 slot_idx = hash%slots_count; + RDIM_SLLStackPush(slots[slot_idx], hash_node); + hash_node->v = n->v; + } + for(RDIM_BinarySectionNode *n = src->binary_sections.first, *next = 0; n != 0; n = next) + { + next = n->next; + RDI_U64 hash = rdi_hash(n->v.name.str, n->v.name.size); + RDI_U64 slot_idx = hash%slots_count; + RDI_S32 is_duplicate = 0; + for(RDIM_BinarySectionNode *hash_n = slots[slot_idx]; hash_n != 0; hash_n = hash_n->next) + { + if(rdim_str8_match(hash_n->v.name, n->v.name, 0)) + { + is_duplicate = 1; + break; + } + } + if(!is_duplicate) + { + RDIM_SLLQueuePush(dst->binary_sections.first, dst->binary_sections.last, n); + dst->binary_sections.count += 1; + } + } + rdim_scratch_end(scratch); + } + + // rjf: join non-top-level chunk lists + { + rdim_unit_chunk_list_concat_in_place(&dst->units, &src->units); + rdim_type_chunk_list_concat_in_place(&dst->types, &src->types); + rdim_udt_chunk_list_concat_in_place(&dst->udts, &src->udts); + rdim_src_file_chunk_list_concat_in_place(&dst->src_files, &src->src_files); + rdim_line_table_chunk_list_concat_in_place(&dst->line_tables, &src->line_tables); + rdim_location_chunk_list_concat_in_place(&dst->locations, &src->locations); + rdim_symbol_chunk_list_concat_in_place(&dst->global_variables, &src->global_variables); + rdim_symbol_chunk_list_concat_in_place(&dst->thread_variables, &src->thread_variables); + rdim_symbol_chunk_list_concat_in_place(&dst->constants, &src->constants); + rdim_symbol_chunk_list_concat_in_place(&dst->procedures, &src->procedures); + rdim_scope_chunk_list_concat_in_place(&dst->scopes, &src->scopes); + rdim_inline_site_chunk_list_concat_in_place(&dst->inline_sites, &src->inline_sites); + } +} + //////////////////////////////// //~ rjf: [Baking Helpers] Deduplicated String Baking Map diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 470bb647..034b9599 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1671,6 +1671,11 @@ RDI_PROC void rdim_scope_push_voff_range(RDIM_Arena *arena, RDIM_ScopeChunkList RDI_PROC RDIM_Local *rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *scope); RDI_PROC RDIM_LocationCase *rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *location, RDIM_Rng1U64 voff_range); +//////////////////////////////// +//~ rjf: [Building] Bake Parameter Joining + +RDI_PROC void rdim_bake_params_concat_in_place(RDIM_BakeParams *dst, RDIM_BakeParams *src); + //////////////////////////////// //~ rjf: [Baking Helpers] Deduplicated String Baking Map diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index dfa3fec2..bb30b271 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -604,17 +604,17 @@ rb_thread_entry_point(void *p) //- rjf: convert inputs to RDI info B32 convert_done = 0; - RDIM_BakeParams bake_params = {0}; + RDIM_BakeParams pdb_bake_params = {0}; + RDIM_BakeParams dwarf_bake_params = {0}; { //- rjf: PE inputs w/ DWARF, or ELF inputs => DWARF -> RDI conversion - if(!convert_done && - ((input_files_from_format_table[RB_FileFormat_PE].count != 0 && + if(((input_files_from_format_table[RB_FileFormat_PE].count != 0 && input_files_from_format_table[RB_FileFormat_PE].first->v->format_flags & RB_FileFormatFlag_HasDWARF) || (input_files_from_format_table[RB_FileFormat_ELF32].count != 0 || input_files_from_format_table[RB_FileFormat_ELF64].count != 0))) { convert_done = 1; - log_infof("PEs w/ DWARF, or ELFs specified; producing RDI by converting DWARF data\n"); + log_infof("PEs w/ DWARF, or ELFs specified; converting DWARF data to RDI\n"); // rjf: convert D2R_ConvertParams convert_params = {0}; @@ -695,21 +695,14 @@ rb_thread_entry_point(void *p) convert_params.subset_flags = subset_flags; convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); } - ProfScope("convert") bake_params = d2r_convert(arena, &convert_params); - - // rjf: no output path? -> pick one based on debug - if(output_path.size == 0) - { - output_path = push_str8f(arena, "%S.rdi", str8_chop_last_dot(convert_params.dbg_name)); - } + ProfScope("convert") dwarf_bake_params = d2r_convert(arena, &convert_params); } //- rjf: PDB inputs => PDB -> RDI conversion - if(!convert_done && - input_files_from_format_table[RB_FileFormat_PDB].count != 0) + if(input_files_from_format_table[RB_FileFormat_PDB].count != 0) { convert_done = 1; - log_infof("PDBs specified; producing RDI by converting PDB data\n"); + log_infof("PDBs specified; converting PDB data to RDI\n"); // rjf: get EXE/PDB file data RB_File *exe_file = rb_file_list_first(&input_files_from_format_table[RB_FileFormat_PE]); @@ -729,21 +722,40 @@ rb_thread_entry_point(void *p) convert_params.subset_flags = subset_flags; convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); } - ProfScope("convert") bake_params = p2r_convert(arena, &convert_params); - - // rjf: no output path? -> pick one based on PDB - if(output_path.size == 0) switch(output_kind) + ProfScope("convert") pdb_bake_params = p2r_convert(arena, &convert_params); + } + } + lane_sync(); + + //- rjf: join conversion artifacts + RDIM_BakeParams *bake_params = 0; + if(lane_idx() == 0) + { + bake_params = push_array(arena, RDIM_BakeParams, 1); + rdim_bake_params_concat_in_place(bake_params, &pdb_bake_params); + rdim_bake_params_concat_in_place(bake_params, &dwarf_bake_params); + } + lane_sync_u64(&bake_params, 0); + + //- rjf: no output path? -> pick one based on input files + if(output_path.size == 0) + { + String8 output_path__noext = {0}; + if(output_path__noext.size == 0) { output_path__noext = str8_chop_last_dot(rb_file_list_first(&input_files_from_format_table[RB_FileFormat_PDB])->path); } + if(output_path__noext.size == 0) { output_path__noext = str8_chop_last_dot(rb_file_list_first(&input_files_from_format_table[RB_FileFormat_PE])->path); } + if(output_path__noext.size == 0) { output_path__noext = str8_chop_last_dot(rb_file_list_first(&input_files_from_format_table[RB_FileFormat_ELF64])->path); } + if(output_path__noext.size == 0) { output_path__noext = str8_chop_last_dot(rb_file_list_first(&input_files_from_format_table[RB_FileFormat_ELF32])->path); } + switch(output_kind) + { + default:{}break; + case OutputKind_RDI: { - default:{}break; - case OutputKind_RDI: - { - output_path = push_str8f(arena, "%S.rdi", str8_chop_last_dot(convert_params.input_pdb_name)); - }break; - case OutputKind_Breakpad: - { - output_path = push_str8f(arena, "%S.psym", str8_chop_last_dot(convert_params.input_pdb_name)); - }break; - } + output_path = push_str8f(arena, "%S.rdi", output_path__noext); + }break; + case OutputKind_Breakpad: + { + output_path = push_str8f(arena, "%S.psym", output_path__noext); + }break; } } @@ -757,7 +769,7 @@ rb_thread_entry_point(void *p) RDIM_BakeResults bake_results = {0}; if(convert_done) ProfScope("bake") { - bake_results = rdim_bake(arena, &bake_params); + bake_results = rdim_bake(arena, bake_params); } //- rjf: convert done => generate output @@ -799,8 +811,8 @@ rb_thread_entry_point(void *p) if(lane_idx() == 0) { p2b_shared = push_array(arena, P2B_Shared, 1); - p2b_shared->lane_chunk_file_dumps = push_array(arena, String8List, lane_count()*bake_params.src_files.chunk_count); - p2b_shared->lane_chunk_func_dumps = push_array(arena, String8List, lane_count()*bake_params.procedures.chunk_count); + p2b_shared->lane_chunk_file_dumps = push_array(arena, String8List, lane_count()*bake_params->src_files.chunk_count); + p2b_shared->lane_chunk_func_dumps = push_array(arena, String8List, lane_count()*bake_params->procedures.chunk_count); } lane_sync(); @@ -808,7 +820,7 @@ rb_thread_entry_point(void *p) if(lane_idx() == 0) { // rjf: pick name to identify module - String8 module_name_string = bake_params.top_level_info.exe_name; + String8 module_name_string = bake_params->top_level_info.exe_name; if(module_name_string.size == 0 && input_files.first != 0) { module_name_string = input_files.first->v->path; @@ -816,9 +828,9 @@ rb_thread_entry_point(void *p) // rjf: pick string for unique code String8 unique_identifier_string = {0}; - if(unique_identifier_string.size == 0 && bake_params.top_level_info.exe_hash != 0) + if(unique_identifier_string.size == 0 && bake_params->top_level_info.exe_hash != 0) { - unique_identifier_string = str8f(arena, "%I64x", bake_params.top_level_info.exe_hash); + unique_identifier_string = str8f(arena, "%I64x", bake_params->top_level_info.exe_hash); } if(unique_identifier_string.size == 0 && input_files.first != 0 && input_files.first->v->format == RB_FileFormat_PDB) { @@ -856,14 +868,14 @@ rb_thread_entry_point(void *p) ProfScope("dump FILE records") { U64 chunk_idx = 0; - for EachNode(n, RDIM_SrcFileChunkNode, bake_params.src_files.first) + for EachNode(n, RDIM_SrcFileChunkNode, bake_params->src_files.first) { Rng1U64 range = lane_range(n->count); for EachInRange(idx, range) { U64 file_idx = rdim_idx_from_src_file(&n->v[idx]); String8 src_path = n->v[idx].path; - str8_list_pushf(arena, &p2b_shared->lane_chunk_file_dumps[lane_idx()*bake_params.src_files.chunk_count + chunk_idx], "FILE %I64u %S\n", file_idx, src_path); + str8_list_pushf(arena, &p2b_shared->lane_chunk_file_dumps[lane_idx()*bake_params->src_files.chunk_count + chunk_idx], "FILE %I64u %S\n", file_idx, src_path); } chunk_idx += 1; } @@ -873,9 +885,9 @@ rb_thread_entry_point(void *p) ProfScope("dump FUNC records") { U64 chunk_idx = 0; - for EachNode(n, RDIM_SymbolChunkNode, bake_params.procedures.first) + for EachNode(n, RDIM_SymbolChunkNode, bake_params->procedures.first) { - String8List *out = &p2b_shared->lane_chunk_func_dumps[lane_idx()*bake_params.procedures.chunk_count + chunk_idx]; + String8List *out = &p2b_shared->lane_chunk_func_dumps[lane_idx()*bake_params->procedures.chunk_count + chunk_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(idx, range) { @@ -942,18 +954,18 @@ rb_thread_entry_point(void *p) lane_sync(); if(lane_idx() == 0) { - for EachIndex(chunk_idx, bake_params.src_files.chunk_count) + for EachIndex(chunk_idx, bake_params->src_files.chunk_count) { for EachIndex(ln_idx, lane_count()) { - str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_file_dumps[ln_idx*bake_params.src_files.chunk_count + chunk_idx]); + str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_file_dumps[ln_idx*bake_params->src_files.chunk_count + chunk_idx]); } } - for EachIndex(chunk_idx, bake_params.procedures.chunk_count) + for EachIndex(chunk_idx, bake_params->procedures.chunk_count) { for EachIndex(ln_idx, lane_count()) { - str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_func_dumps[ln_idx*bake_params.procedures.chunk_count + chunk_idx]); + str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_func_dumps[ln_idx*bake_params->procedures.chunk_count + chunk_idx]); } } } diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 81a3d30a..8c7b1053 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -1697,7 +1697,10 @@ d2r_tag_iterator_init(Arena *arena, DW_TagNode *root) iter->free_list = 0; iter->stack = push_array(arena, D2R_TagFrame, 1); iter->stack->node = push_array(arena, DW_TagNode, 1); - *iter->stack->node = *root; + if(root != 0) + { + *iter->stack->node = *root; + } iter->stack->node->sibling = 0; iter->visit_children = 1; iter->tag_node = root; @@ -1797,7 +1800,10 @@ d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *inpu // if we do not have a converted type at this point then debug info is malformed type = d2r_type_from_offset(type_table, ref.info_off); - Assert(type); + if(type == 0) + { + type = type_table->builtin_types[RDI_TypeKind_NULL]; + } } } else { Assert(!"unexpected attrib class"); @@ -2054,7 +2060,8 @@ d2r_convert_types(Arena *arena, Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + // TODO(rjf): this is not an invalid case; it shows up in `mule_main` pointer types + // Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); U64 byte_size = arch_addr_size; @@ -2192,11 +2199,14 @@ d2r_convert_types(Arena *arena, } RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); - RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); - member->kind = RDI_MemberKind_Base; - member->type = type; - member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); + if(parent->udt != 0) + { + RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = type; + member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); + } } break; } } @@ -2550,7 +2560,10 @@ d2r_convert_symbols(Arena *arena, case DW_TagKind_ReferenceType: { // TODO: } break; - default: NotImplemented; break; + default: + { + // NotImplemented; + }break; } } scratch_end(scratch); From fe8608ee1c3552178de7a0e8e115d77a921034eb Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 10:37:15 -0700 Subject: [PATCH 056/133] more verbose logging in radbin --- src/radbin/radbin.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index bb30b271..966dcde4 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -291,6 +291,7 @@ rb_thread_entry_point(void *p) if(file_format == RB_FileFormat_PE) ProfScope("PE file => generate task for PDB") { Temp scratch = scratch_begin(&arena, 1); + String8 file_path = n->string; PE_BinInfo pe_bin_info = pe_bin_info_from_data(scratch.arena, file_data); String8 raw_debug_dir = str8_substr(file_data, pe_bin_info.data_dir_franges[PE_DataDirectoryIndex_DEBUG]); PE_DebugInfoList debug_dir = pe_debug_info_list_from_raw_debug_dir(scratch.arena, file_data, raw_debug_dir); @@ -298,6 +299,7 @@ rb_thread_entry_point(void *p) { if(n->v.path.size != 0) { + log_infof("Found reference to separate debug info file in %S (%S) at %S\n", file_path, rb_file_format_display_name_table[file_format], n->v.path); str8_list_push(arena, &input_file_path_tasks, n->v.path); } } @@ -315,6 +317,7 @@ rb_thread_entry_point(void *p) ELF_GnuDebugLink debug_link = elf_gnu_debug_link_from_bin(file_data, &bin); if(debug_link.path.size != 0) { + log_infof("Found reference to separate debug info file in %S (%S) at %S\n", n->string, rb_file_format_display_name_table[file_format], debug_link.path); str8_list_push(arena, &input_file_path_tasks, debug_link.path); } scratch_end(scratch); @@ -333,6 +336,7 @@ rb_thread_entry_point(void *p) COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str; if(dw_is_dwarf_present_coff_section_table(string_table, section_count, section_table)) { + log_infof("DWARF data detected in %S (%S)\n", n->string, rb_file_format_display_name_table[file_format]); file_format_flags |= RB_FileFormatFlag_HasDWARF; } scratch_end(scratch); @@ -348,6 +352,7 @@ rb_thread_entry_point(void *p) ELF_Bin elf_bin = elf_bin_from_data(scratch.arena, file_data); if(dw_is_dwarf_present_from_elf_bin(file_data, &elf_bin)) { + log_infof("DWARF data detected in %S (%S)\n", n->string, rb_file_format_display_name_table[file_format]); file_format_flags |= RB_FileFormatFlag_HasDWARF; } scratch_end(scratch); From fadef8a886f28c6826c827ec2c91c565f3077591 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 11:03:18 -0700 Subject: [PATCH 057/133] log source of dwarf info more specifically --- src/radbin/radbin.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 966dcde4..9788b5f7 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -613,13 +613,16 @@ rb_thread_entry_point(void *p) RDIM_BakeParams dwarf_bake_params = {0}; { //- rjf: PE inputs w/ DWARF, or ELF inputs => DWARF -> RDI conversion - if(((input_files_from_format_table[RB_FileFormat_PE].count != 0 && - input_files_from_format_table[RB_FileFormat_PE].first->v->format_flags & RB_FileFormatFlag_HasDWARF) || - (input_files_from_format_table[RB_FileFormat_ELF32].count != 0 || - input_files_from_format_table[RB_FileFormat_ELF64].count != 0))) + B32 pe_w_dwarf = (input_files_from_format_table[RB_FileFormat_PE].count != 0 && + input_files_from_format_table[RB_FileFormat_PE].first->v->format_flags & RB_FileFormatFlag_HasDWARF); + B32 elf_w_dwarf = (input_files_from_format_table[RB_FileFormat_ELF32].count != 0 || + input_files_from_format_table[RB_FileFormat_ELF64].count != 0); + if(pe_w_dwarf || elf_w_dwarf) { convert_done = 1; - log_infof("PEs w/ DWARF, or ELFs specified; converting DWARF data to RDI\n"); + if(0){} + else if(pe_w_dwarf) { log_infof("PEs w/ DWARF specified; converting DWARF data to RDI\n"); } + else if(elf_w_dwarf) { log_infof("ELFs specified; converting DWARF data to RDI\n"); } // rjf: convert D2R_ConvertParams convert_params = {0}; From 2acf77ad9ee98f5522b6b4a9da0767b013e23b55 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 11:34:30 -0700 Subject: [PATCH 058/133] fix impossible disasm loading condition; do not go wide on dbgi matching unless we have significant-enough dbgis --- project.4coder | 4 ++-- src/artifact_cache/artifact_cache.c | 8 ++++++++ src/content/content.c | 2 +- src/ctrl/ctrl_core.c | 5 ++--- src/dbg_info/dbg_info.c | 19 +++++++++++++++---- src/dbg_info/dbg_info.h | 2 ++ src/os/core/linux/os_core_linux.c | 17 +++++++++++++---- src/os/core/win32/os_core_win32.c | 18 ++++++++++++++---- src/raddbg/raddbg_views.c | 4 ++-- 9 files changed, 59 insertions(+), 20 deletions(-) diff --git a/project.4coder b/project.4coder index 1bb5aad9..9dc98bf1 100644 --- a/project.4coder +++ b/project.4coder @@ -46,8 +46,8 @@ load_paths = commands = { //- rjf: [raddbg] - // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 4b78d1db..0172004b 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -459,10 +459,18 @@ ac_async_tick(void) if(req_idx >= task->thin_count) { break; } AC_Request *r = &task->thin[req_idx]; + // rjf: push thin lane ctx + U64 thin_lane_ctx_broadcast_memory = 0; + LaneCtx thin_lane_ctx = {0, 1, {0}, &thin_lane_ctx_broadcast_memory}; + LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx); + // rjf: compute val B32 retry = 0; AC_Artifact val = r->create(r->key, r->cancel_signal, &retry); + // rjf: restore wide lane ctx + lane_ctx(lane_ctx_restore); + // rjf: retry? -> resubmit request if(retry) { diff --git a/src/content/content.c b/src/content/content.c index 86062fea..09e4928a 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -202,7 +202,7 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) } // rjf: release duplicate data if node already exists - if(node != 0) + if(node != 0 && data_arena != 0 && *data_arena != 0) { arena_release(*data_arena); } diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 8432c710..cc702204 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6046,14 +6046,13 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { arena_release(range_arena); range_base = 0; - range_size = 0; range_arena = 0; } else if(bytes_read < range_size) { MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); } - zero_terminated_size = range_size; + zero_terminated_size = bytes_read; if(zero_terminated && range_base != 0) { for(U64 idx = 0; idx < bytes_read; idx += 1) @@ -6080,7 +6079,7 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) //- rjf: read successful -> submit to hash store U128 hash = {0}; - if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen) + if(range_size != 0 && pre_read_mem_gen == post_read_mem_gen) { hash = c_submit_data(content_key, &range_arena, str8((U8*)range_base, zero_terminated_size)); } diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 7333103e..377106e7 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -367,7 +367,8 @@ di_close(DI_Key key) //- rjf: release node's resources if needed if(node_released) - { + { + ins_atomic_u64_dec_eval(&di_shared->load_count); os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); os_file_map_close(file_map); os_file_close(file); @@ -387,6 +388,13 @@ di_load_gen(void) U64 result = ins_atomic_u64_eval(&di_shared->load_gen); return result; } + +internal U64 +di_load_count(void) +{ + U64 result = ins_atomic_u64_eval(&di_shared->load_count); + return result; +} internal DI_KeyArray di_push_all_loaded_keys(Arena *arena) @@ -942,7 +950,8 @@ di_async_tick(void) MemoryCopyStruct(&node->rdi, &rdi_parsed); node->completion_count += 1; node->working_count -= 1; - ins_atomic_u64_inc_eval(&di_shared->load_gen); + ins_atomic_u64_inc_eval(&di_shared->load_gen); + ins_atomic_u64_inc_eval(&di_shared->load_count); } else { @@ -1539,8 +1548,10 @@ di_match_from_string(String8 string, U64 index, DI_Key preferred_dbgi_key, U64 e str8_list_push(scratch.arena, &key_parts, str8_struct(&preferred_dbgi_key)); str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); str8_list_push(scratch.arena, &key_parts, string); - String8 key = str8_list_join(scratch.arena, &key_parts, 0); - AC_Artifact artifact = ac_artifact_from_key(access, key, di_match_artifact_create, 0, endt_us, .flags = AC_Flag_Wide, .gen = di_load_gen()); + String8 key = str8_list_join(scratch.arena, &key_parts, 0); + U64 dbgi_count = di_load_count(); + B32 wide = (dbgi_count > 256); + AC_Artifact artifact = ac_artifact_from_key(access, key, di_match_artifact_create, 0, endt_us, .flags = wide ? AC_Flag_Wide : 0, .gen = di_load_gen()); result.key.u64[0] = artifact.u64[0]; result.key.u64[1] = artifact.u64[1]; result.section_kind = artifact.u64[2]; diff --git a/src/dbg_info/dbg_info.h b/src/dbg_info/dbg_info.h index 36aca803..9d00cf7f 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -246,6 +246,7 @@ struct DI_Shared { Arena *arena; U64 load_gen; + U64 load_count; // rjf: key -> path cache U64 key2path_slots_count; @@ -328,6 +329,7 @@ internal void di_close(DI_Key key); //~ rjf: Debug Info Lookups internal U64 di_load_gen(void); +internal U64 di_load_count(void); internal DI_KeyArray di_push_all_loaded_keys(Arena *arena); internal RDI_Parsed *di_rdi_from_key(Access *access, DI_Key key, B32 high_priority, U64 endt_us); diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index df98d409..9b137287 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -1142,7 +1142,10 @@ internal Barrier os_barrier_alloc(U64 count) { OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Barrier); - pthread_barrier_init(&entity->barrier, 0, count); + if(entity != 0) + { + pthread_barrier_init(&entity->barrier, 0, count); + } Barrier result = {IntFromPtr(entity)}; return result; } @@ -1151,15 +1154,21 @@ internal void os_barrier_release(Barrier barrier) { OS_LNX_Entity *entity = (OS_LNX_Entity*)PtrFromInt(barrier.u64[0]); - pthread_barrier_destroy(&entity->barrier); - os_lnx_entity_release(entity); + if(entity != 0) + { + pthread_barrier_destroy(&entity->barrier); + os_lnx_entity_release(entity); + } } internal void os_barrier_wait(Barrier barrier) { OS_LNX_Entity *entity = (OS_LNX_Entity*)PtrFromInt(barrier.u64[0]); - pthread_barrier_wait(&entity->barrier); + if(entity != 0) + { + pthread_barrier_wait(&entity->barrier); + } } //////////////////////////////// diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 9e829e1f..6e681f0e 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1342,7 +1342,11 @@ internal Barrier os_barrier_alloc(U64 count) { OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Barrier); - BOOL init_good = InitializeSynchronizationBarrier(&entity->sb, count, -1); + if(entity != 0) + { + BOOL init_good = InitializeSynchronizationBarrier(&entity->sb, count, -1); + (void)init_good; + } Barrier result = {IntFromPtr(entity)}; return result; } @@ -1351,15 +1355,21 @@ internal void os_barrier_release(Barrier barrier) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(barrier.u64[0]); - DeleteSynchronizationBarrier(&entity->sb); - os_w32_entity_release(entity); + if(entity != 0) + { + DeleteSynchronizationBarrier(&entity->sb); + os_w32_entity_release(entity); + } } internal void os_barrier_wait(Barrier barrier) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(barrier.u64[0]); - EnterSynchronizationBarrier(&entity->sb, 0); + if(entity != 0) + { + EnterSynchronizationBarrier(&entity->sb, 0); + } } //////////////////////////////// diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index db9294a7..d726d556 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2482,8 +2482,8 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) U128 dasm_text_hash = {0}; TXT_TextInfo dasm_text_info = txt_text_info_from_key_lang(access, rd_regs()->text_key, rd_regs()->lang_kind, &dasm_text_hash); String8 dasm_text_data = c_data_from_hash(access, dasm_text_hash); - B32 has_disasm = (dasm_info.lines.count != 0 && dasm_text_info.lines_count != 0); - B32 is_loading = (!has_disasm && dim_1u64(range) != 0 && eval.msgs.max_kind == E_MsgKind_Null && (space.kind != RD_EvalSpaceKind_CtrlEntity || space_entity != &ctrl_entity_nil)); + B32 is_loading = (dasm_text_info.lines_count == 0 && dim_1u64(range) != 0 && eval.msgs.max_kind == E_MsgKind_Null && (space.kind != RD_EvalSpaceKind_CtrlEntity || space_entity != &ctrl_entity_nil)); + B32 has_disasm = (dasm_text_info.lines_count != 0 && dasm_info.lines.count != 0); ////////////////////////////// //- rjf: is loading -> equip view with loading information From 0f0e36d40b13ea0d156bf394cf52a99a568172e8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 11:45:09 -0700 Subject: [PATCH 059/133] disambiguate rip identifier in disasm base address calculation --- src/raddbg/raddbg_views.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index d726d556..80c42766 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2381,7 +2381,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) { auto_selected = 1; auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); - eval = e_eval_from_stringf("(rip.u64 & (~(0x4000 - 1)))"); + eval = e_eval_from_stringf("(reg:rip.u64 & (~(0x4000 - 1)))"); } } From f60ccb60f1bba49f21020b2e679a0a689f336c79 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 12:09:14 -0700 Subject: [PATCH 060/133] do not attach last successful filter to view state, since does not apply in all cases - fix artifact staleness default marker (if we do not get an artifact at all, then it is stale) --- src/artifact_cache/artifact_cache.c | 2 +- src/raddbg/raddbg_core.h | 4 ---- src/raddbg/raddbg_eval.c | 8 +++----- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 0172004b..535c28d5 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -72,7 +72,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); //- rjf: cache * key -> existing artifact - B32 artifact_is_stale = 0; + B32 artifact_is_stale = 1; B32 got_artifact = 0; B32 need_request = 0; AC_Artifact artifact = {0}; diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 485593e0..ad58381e 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -230,10 +230,6 @@ struct RD_ViewState U8 query_buffer[KB(1)]; U64 query_string_size; - // rjf: last successful query string state - U8 last_successful_query_buffer[KB(1)]; - U64 last_successful_query_string_size; - // rjf: contents are focused (disables query focus) B32 contents_are_focused; }; diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 82c501ce..59611487 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1650,20 +1650,18 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) if(section != RDI_SectionKind_NULL) { U64 endt_us = rd_state->frame_eval_memread_endt_us; - U128 fuzzy_search_key = {d_hash_from_string(str8_struct(&rd_regs()->view)), (U64)section}; B32 stale = 0; accel->section = section; accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us, &stale); - RD_ViewState *vs = rd_view_state_from_cfg(rd_cfg_from_id(rd_regs()->view)); + RD_Cfg *last_successful_query_cfg = rd_immediate_cfg_from_keyf("last_successful_query_%I64x", rd_regs()->view); if(stale) { - String8 last_query = str8(vs->last_successful_query_buffer, vs->last_successful_query_string_size); + String8 last_query = last_successful_query_cfg->first->string; accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, last_query, endt_us, 0); } else { - vs->last_successful_query_string_size = Min(sizeof(vs->last_successful_query_buffer), filter.size); - MemoryCopy(vs->last_successful_query_buffer, filter.str, vs->last_successful_query_string_size); + rd_cfg_new_replace(last_successful_query_cfg, filter); } } From ab841035c03968f1cb471bd0656cb575bc781edd Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 14:20:36 -0700 Subject: [PATCH 061/133] preserve operand size info for shift operations, use along with typegroup to do correct sign preservation on shifts --- src/eval/eval_interpret.c | 149 +++++++++++++++++++++++--------------- src/eval/eval_ir.c | 42 ++++++----- src/eval/eval_ir.h | 4 +- src/eval/eval_types.c | 7 +- src/lib_rdi/rdi.c | 4 +- src/rdi/rdi.mdesk | 4 +- 6 files changed, 127 insertions(+), 83 deletions(-) diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index e667a429..12ce59a3 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -150,6 +150,10 @@ e_interpret(String8 bytecode) ptr = next_ptr; } + // rjf: unpack imm -> type group & arithmetic width + RDI_EvalTypeGroup type_group = (RDI_EvalTypeGroup)imm.u512.u8[0]; + U64 op_arithmetic_size = (U64)imm.u512.u8[1]; + // rjf: pop E_Value *svals = 0; { @@ -297,7 +301,7 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Abs: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.f32 = svals[0].f32; if(svals[0].f32 < 0) @@ -305,7 +309,7 @@ e_interpret(String8 bytecode) nval.f32 = -svals[0].f32; } } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.f64 = svals[0].f64; if(svals[0].f64 < 0) @@ -325,11 +329,11 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Neg: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.f32 = -svals[0].f32; } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.f64 = -svals[0].f64; } @@ -341,11 +345,11 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Add: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.f32 = svals[0].f32 + svals[1].f32; } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.f64 = svals[0].f64 + svals[1].f64; } @@ -357,11 +361,11 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Sub: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.f32 = svals[0].f32 - svals[1].f32; } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.f64 = svals[0].f64 - svals[1].f64; } @@ -373,11 +377,11 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Mul: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.f32 = svals[0].f32*svals[1].f32; } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.f64 = svals[0].f64*svals[1].f64; } @@ -389,7 +393,7 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Div: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { if(svals[1].f32 != 0.f) { @@ -401,7 +405,7 @@ e_interpret(String8 bytecode) goto done; } } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { if(svals[1].f64 != 0.) { @@ -413,8 +417,8 @@ e_interpret(String8 bytecode) goto done; } } - else if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + else if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { if(svals[1].u64 != 0) { @@ -435,8 +439,8 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Mod: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { if(svals[1].u64 != 0) { @@ -452,10 +456,27 @@ e_interpret(String8 bytecode) case RDI_EvalOp_LShift: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U) { - nval.u64 = svals[0].u64 << svals[1].u64; + switch(op_arithmetic_size) + { + default:{}break; + case 1:{nval.u8 = svals[0].u8 << svals[1].u8;}break; + case 2:{nval.u16 = svals[0].u16 << svals[1].u16;}break; + case 4:{nval.u32 = svals[0].u32 << svals[1].u32;}break; + case 8:{nval.u64 = svals[0].u64 << svals[1].u64;}break; + } + } + else if(type_group == RDI_EvalTypeGroup_S) + { + switch(op_arithmetic_size) + { + default:{}break; + case 1:{nval.s8 = svals[0].s8 << svals[1].s8;}break; + case 2:{nval.s16 = svals[0].s16 << svals[1].s16;}break; + case 4:{nval.s32 = svals[0].s32 << svals[1].s32;}break; + case 8:{nval.s64 = svals[0].s64 << svals[1].s64;}break; + } } else { @@ -466,13 +487,27 @@ e_interpret(String8 bytecode) case RDI_EvalOp_RShift: { - if(imm.u64 == RDI_EvalTypeGroup_U) + if(type_group == RDI_EvalTypeGroup_U) { - nval.u64 = svals[0].u64 >> svals[1].u64; + switch(op_arithmetic_size) + { + default:{}break; + case 1:{nval.u8 = svals[0].u8 >> svals[1].u8;}break; + case 2:{nval.u16 = svals[0].u16 >> svals[1].u16;}break; + case 4:{nval.u32 = svals[0].u32 >> svals[1].u32;}break; + case 8:{nval.u64 = svals[0].u64 >> svals[1].u64;}break; + } } - else if(imm.u64 == RDI_EvalTypeGroup_S) + else if(type_group == RDI_EvalTypeGroup_S) { - nval.u64 = svals[0].s64 >> svals[1].u64; + switch(op_arithmetic_size) + { + default:{}break; + case 1:{nval.s8 = svals[0].s8 >> svals[1].s8;}break; + case 2:{nval.s16 = svals[0].s16 >> svals[1].s16;}break; + case 4:{nval.s32 = svals[0].s32 >> svals[1].s32;}break; + case 8:{nval.s64 = svals[0].s64 >> svals[1].s64;}break; + } } else { @@ -483,8 +518,8 @@ e_interpret(String8 bytecode) case RDI_EvalOp_BitAnd: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { nval.u64 = svals[0].u64&svals[1].u64; } @@ -497,8 +532,8 @@ e_interpret(String8 bytecode) case RDI_EvalOp_BitOr: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { nval.u64 = svals[0].u64|svals[1].u64; } @@ -511,8 +546,8 @@ e_interpret(String8 bytecode) case RDI_EvalOp_BitXor: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { nval.u64 = svals[0].u64^svals[1].u64; } @@ -525,8 +560,8 @@ e_interpret(String8 bytecode) case RDI_EvalOp_BitNot: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { nval.u64 = ~svals[0].u64; } @@ -539,8 +574,8 @@ e_interpret(String8 bytecode) case RDI_EvalOp_LogAnd: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].u64 && svals[1].u64); } @@ -553,8 +588,8 @@ e_interpret(String8 bytecode) case RDI_EvalOp_LogOr: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].u64 || svals[1].u64); } @@ -567,8 +602,8 @@ e_interpret(String8 bytecode) case RDI_EvalOp_LogNot: { - if(imm.u64 == RDI_EvalTypeGroup_U || - imm.u64 == RDI_EvalTypeGroup_S) + if(type_group == RDI_EvalTypeGroup_U || + type_group == RDI_EvalTypeGroup_S) { nval.u64 = (!svals[0].u64); } @@ -593,19 +628,19 @@ e_interpret(String8 bytecode) case RDI_EvalOp_LsEq: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.u64 = (svals[0].f32 <= svals[1].f32); } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.u64 = (svals[0].f64 <= svals[1].f64); } - else if(imm.u64 == RDI_EvalTypeGroup_U) + else if(type_group == RDI_EvalTypeGroup_U) { nval.u64 = (svals[0].u64 <= svals[1].u64); } - else if(imm.u64 == RDI_EvalTypeGroup_S) + else if(type_group == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].s64 <= svals[1].s64); } @@ -618,19 +653,19 @@ e_interpret(String8 bytecode) case RDI_EvalOp_GrEq: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.u64 = (svals[0].f32 >= svals[1].f32); } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.u64 = (svals[0].f64 >= svals[1].f64); } - else if(imm.u64 == RDI_EvalTypeGroup_U) + else if(type_group == RDI_EvalTypeGroup_U) { nval.u64 = (svals[0].u64 >= svals[1].u64); } - else if(imm.u64 == RDI_EvalTypeGroup_S) + else if(type_group == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].s64 >= svals[1].s64); } @@ -643,19 +678,19 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Less: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.u64 = (svals[0].f32 < svals[1].f32); } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.u64 = (svals[0].f64 < svals[1].f64); } - else if(imm.u64 == RDI_EvalTypeGroup_U) + else if(type_group == RDI_EvalTypeGroup_U) { nval.u64 = (svals[0].u64 < svals[1].u64); } - else if(imm.u64 == RDI_EvalTypeGroup_S) + else if(type_group == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].s64 < svals[1].s64); } @@ -668,19 +703,19 @@ e_interpret(String8 bytecode) case RDI_EvalOp_Grtr: { - if(imm.u64 == RDI_EvalTypeGroup_F32) + if(type_group == RDI_EvalTypeGroup_F32) { nval.u64 = (svals[0].f32 > svals[1].f32); } - else if(imm.u64 == RDI_EvalTypeGroup_F64) + else if(type_group == RDI_EvalTypeGroup_F64) { nval.u64 = (svals[0].f64 > svals[1].f64); } - else if(imm.u64 == RDI_EvalTypeGroup_U) + else if(type_group == RDI_EvalTypeGroup_U) { nval.u64 = (svals[0].u64 > svals[1].u64); } - else if(imm.u64 == RDI_EvalTypeGroup_S) + else if(type_group == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].s64 > svals[1].s64); } @@ -841,22 +876,22 @@ e_interpret(String8 bytecode) case 8:{nval.u64 = bswap_u64(svals[0].u64);}break; } }break; - + case RDI_EvalOp_CallSiteValue: { NotImplemented; }break; - + case RDI_EvalOp_PartialValue: { NotImplemented; }break; - + case RDI_EvalOp_PartialValueBit: { NotImplemented; }break; - + case RDI_EvalOp_Swap: { // TODO: add support for pushing multiple values onto the stack diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index f38c2557..359a5b0d 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -163,19 +163,20 @@ e_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode } internal E_IRNode * -e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *l, E_IRNode *r) +e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, U64 operand_size, E_IRNode *l, E_IRNode *r) { E_IRNode *n = e_push_irnode(arena, op); - n->value.u64 = group; + n->value.u512.u8[0] = (U8)group; + n->value.u512.u8[1] = (U8)operand_size; e_irnode_push_child(n, l); e_irnode_push_child(n, r); return n; } internal E_IRNode * -e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, E_IRNode *l, E_IRNode *r) +e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, U64 operand_size, E_IRNode *l, E_IRNode *r) { - E_IRNode *n = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_U, l, r); + E_IRNode *n = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_U, operand_size, l, r); return n; } @@ -314,8 +315,8 @@ e_irtree_resolve_to_value(Arena *arena, E_Mode from_mode, E_IRNode *tree, E_Type { valid_bits_mask |= (1ull<off)); - result = e_irtree_binary_op_u(arena, RDI_EvalOp_BitAnd, result, e_irtree_const_u(arena, valid_bits_mask)); + result = e_irtree_binary_op_u(arena, RDI_EvalOp_RShift, type->byte_size, result, e_irtree_const_u(arena, type->off)); + result = e_irtree_binary_op_u(arena, RDI_EvalOp_BitAnd, type->byte_size, result, e_irtree_const_u(arena, valid_bits_mask)); } } return result; @@ -475,7 +476,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default) if(r_value != 0 && !r_is_constant_value) { E_IRNode *const_tree = e_irtree_const_u(arena, r_value); - new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, new_tree, const_tree); + new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, e_type_byte_size_from_key(new_tree_type), new_tree, const_tree); } else if(r_is_constant_value) { @@ -544,7 +545,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default) if(direct_type_size > 1) { E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); - offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree); + offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, 8, offset_tree, const_tree); } // rjf: ops to push stack value, push offset, + read from stack value @@ -562,7 +563,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default) if(direct_type_size > 1) { E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); - offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree); + offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, 8, offset_tree, const_tree); } // rjf: ops to compute the base offset (resolve to value if addr-of-pointer) @@ -573,7 +574,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default) } // rjf: ops to compute the final address - new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, offset_tree, base_tree); + new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, 8, offset_tree, base_tree); if(mode != E_Mode_Null) { mode = E_Mode_Offset; @@ -1136,6 +1137,9 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative); E_TypeKind l_type_kind = e_type_kind_from_key(l_type); E_TypeKind r_type_kind = e_type_kind_from_key(r_type); + U64 l_type_size = e_type_byte_size_from_key(l_type); + U64 r_type_size = e_type_byte_size_from_key(r_type); + U64 op_operand_size = Max(l_type_size, r_type_size); // rjf: resolve complex types to simple arithmetic tyeps if(l_type_kind == E_TypeKind_Bitfield) @@ -1254,7 +1258,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); l_value_tree = e_irtree_convert_hi(arena, l_value_tree, l_type, l_type); r_value_tree = e_irtree_convert_hi(arena, r_value_tree, l_type, r_type); - E_IRNode *new_tree = e_irtree_binary_op(arena, op, l_type_group, l_value_tree, r_value_tree); + E_IRNode *new_tree = e_irtree_binary_op(arena, op, l_type_group, op_operand_size, l_value_tree, r_value_tree); result.root = new_tree; result.type_key = final_type_key; result.mode = E_Mode_Value; @@ -1267,10 +1271,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I // rjf: map l/r to ptr/int E_IRTreeAndType *ptr_tree = &l_tree; E_IRTreeAndType *int_tree = &r_tree; + U64 ptr_size = l_type_size; B32 ptr_is_decay = l_is_decay; if(ptr_arithmetic_mul_rptr) { ptr_tree = &r_tree; + ptr_size = r_type_size; int_tree = &l_tree; ptr_is_decay = r_is_decay; } @@ -1291,14 +1297,14 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I if(direct_type_size > 1) { E_IRNode *const_root = e_irtree_const_u(arena, direct_type_size); - int_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, int_root, const_root); + int_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, ptr_size, int_root, const_root); } E_TypeKey ptr_type = ptr_tree->type_key; if(ptr_is_decay) { ptr_type = e_type_key_cons_ptr(e_base_ctx->primary_module->arch, direct_type, 1, 0); } - E_IRNode *new_root = e_irtree_binary_op_u(arena, op, ptr_root, int_root); + E_IRNode *new_root = e_irtree_binary_op_u(arena, op, ptr_size, ptr_root, int_root); result.root = new_root; result.type_key = ptr_type; result.mode = E_Mode_Value; @@ -1323,12 +1329,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I { r_root = e_irtree_resolve_to_value(arena, r_tree.mode, r_root, r_type); } - E_IRNode *op_tree = e_irtree_binary_op_u(arena, op, l_root, r_root); + E_IRNode *op_tree = e_irtree_binary_op_u(arena, op, l_type_size, l_root, r_root); E_IRNode *new_tree = op_tree; if(direct_type_size > 1) { E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); - new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Div, new_tree, const_tree); + new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Div, l_type_size, new_tree, const_tree); } result.root = new_tree; result.type_key = e_type_key_basic(E_TypeKind_U64); @@ -1342,11 +1348,13 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I B32 ptr_is_decay = l_is_decay; E_IRTreeAndType *ptr_tree = &l_tree; E_IRTreeAndType *arr_tree = &r_tree; + U64 ptr_size = l_type_size; if(l_type_kind == E_TypeKind_Array && l_tree.mode == E_Mode_Value) { ptr_is_decay = r_is_decay; ptr_tree = &r_tree; arr_tree = &l_tree; + ptr_size = r_type_size; } // rjf: resolve pointer to value, sized same as array @@ -1361,7 +1369,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_IRNode *mem_root = e_irtree_mem_read_type(arena, ptr_root, arr_tree->type_key); // rjf: generate - result.root = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_Other, mem_root, arr_root); + result.root = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_Other, ptr_size, mem_root, arr_root); result.type_key = e_type_key_basic(E_TypeKind_Bool); result.mode = E_Mode_Value; }break; @@ -2701,7 +2709,7 @@ e_bytecode_from_oplist(Arena *arena, E_OpList *oplist) // rjf: fill bytecode ptr[0] = opcode; - MemoryCopy(ptr + 1, &op->value.u64, extra_byte_count); + MemoryCopy(ptr + 1, &op->value.u512.u8[0], extra_byte_count); // rjf: advance ptr = next_ptr; diff --git a/src/eval/eval_ir.h b/src/eval/eval_ir.h index 4b463442..96e4194f 100644 --- a/src/eval/eval_ir.h +++ b/src/eval/eval_ir.h @@ -138,8 +138,8 @@ internal void e_irnode_push_child(E_IRNode *parent, E_IRNode *child); internal E_IRNode *e_irtree_const_u(Arena *arena, U64 v); internal E_IRNode *e_irtree_leaf_u128(Arena *arena, U128 u128); internal E_IRNode *e_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *c); -internal E_IRNode *e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *l, E_IRNode *r); -internal E_IRNode *e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, E_IRNode *l, E_IRNode *r); +internal E_IRNode *e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, U64 operand_size, E_IRNode *l, E_IRNode *r); +internal E_IRNode *e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, U64 operand_size, E_IRNode *l, E_IRNode *r); internal E_IRNode *e_irtree_conditional(Arena *arena, E_IRNode *c, E_IRNode *l, E_IRNode *r); internal E_IRNode *e_irtree_bytecode_no_copy(Arena *arena, String8 bytecode); internal E_IRNode *e_irtree_string_literal(Arena *arena, String8 string); diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index f4ddca7f..fb580740 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -2661,6 +2661,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(slice) if(ext->base_ptr_member != 0) { Temp scratch = scratch_begin(&arena, 1); + U64 addr_size = e_type_byte_size_from_key(ext->base_ptr_member->type_key); // rjf: compute ir tree for struct base E_IRNode *struct_base_tree = &e_irnode_nil; @@ -2681,7 +2682,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(slice) base_ptr_tree = struct_base_tree; if(ext->base_ptr_member->off != 0) { - base_ptr_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, struct_base_tree, e_irtree_const_u(arena, ext->base_ptr_member->off)); + base_ptr_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, addr_size, struct_base_tree, e_irtree_const_u(arena, ext->base_ptr_member->off)); } base_ptr_tree = e_irtree_mem_read_type(arena, base_ptr_tree, ext->base_ptr_member->type_key); } @@ -2692,8 +2693,8 @@ E_TYPE_ACCESS_FUNCTION_DEF(slice) { E_IRTreeAndType idx_irtree = e_push_irtree_and_type_from_expr(arena, 0, &e_default_identifier_resolution_rule, 0, 1, expr->first->next); E_IRNode *idx_root = e_irtree_resolve_to_value(arena, idx_irtree.mode, idx_irtree.root, idx_irtree.type_key); - E_IRNode *off_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, idx_root, e_irtree_const_u(arena, e_type_byte_size_from_key(e_type_key_unwrap(ext->base_ptr_member->type_key, E_TypeUnwrapFlag_All)))); - idxed_base_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, base_ptr_tree, off_root); + E_IRNode *off_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, addr_size, idx_root, e_irtree_const_u(arena, e_type_byte_size_from_key(e_type_key_unwrap(ext->base_ptr_member->type_key, E_TypeUnwrapFlag_All)))); + idxed_base_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, addr_size, base_ptr_tree, off_root); } // rjf: form final result diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index 943411a9..d60dc325 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -85,8 +85,8 @@ RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(1, 2, 1), diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 6bbcfb95..f68f611d 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -1323,8 +1323,8 @@ RDI_EvalOpTable: {Mul 22 1 2 1} {Div 23 1 2 1} {Mod 24 1 2 1} - {LShift 25 1 2 1} - {RShift 26 1 2 1} + {LShift 25 2 2 1} + {RShift 26 2 2 1} {BitAnd 27 1 2 1} {BitOr 28 1 2 1} {BitXor 29 1 2 1} From ec978d8d4639b1a5e3dfdafce3c6b0a2c543c91e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 14:41:51 -0700 Subject: [PATCH 062/133] do not use complex register union types for common registers; just use primitive integer types instead --- src/eval/eval_ir.c | 22 +++- src/raddbg/raddbg_views.c | 10 +- src/regs/generated/regs.meta.c | 192 ++++++++++++++++----------------- src/regs/regs.mdesk | 192 ++++++++++++++++----------------- 4 files changed, 217 insertions(+), 199 deletions(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 359a5b0d..2187a178 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -2044,7 +2044,16 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Offset; mapped_bytecode_space = e_base_ctx->thread_reg_space; - mapped_type_key = e_type_key_reg(e_base_ctx->primary_module->arch, reg_num); + REGS_UsageKind reg_usage_kind = regs_reg_code_usage_kind_table_from_arch(e_base_ctx->primary_module->arch)[reg_num]; + if(0){} + else if(reg_usage_kind == REGS_UsageKind_Normal && reg_rng.byte_size == 1) {mapped_type_key = e_type_key_basic(E_TypeKind_U8);} + else if(reg_usage_kind == REGS_UsageKind_Normal && reg_rng.byte_size == 2) {mapped_type_key = e_type_key_basic(E_TypeKind_U16);} + else if(reg_usage_kind == REGS_UsageKind_Normal && reg_rng.byte_size == 4) {mapped_type_key = e_type_key_basic(E_TypeKind_U32);} + else if(reg_usage_kind == REGS_UsageKind_Normal && reg_rng.byte_size == 8) {mapped_type_key = e_type_key_basic(E_TypeKind_U64);} + else + { + mapped_type_key = e_type_key_reg(e_base_ctx->primary_module->arch, reg_num); + } } }break; @@ -2063,7 +2072,16 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Offset; mapped_bytecode_space = e_base_ctx->thread_reg_space; - mapped_type_key = e_type_key_reg_alias(e_base_ctx->primary_module->arch, alias_num); + REGS_UsageKind reg_usage_kind = regs_alias_code_usage_kind_table_from_arch(e_base_ctx->primary_module->arch)[alias_num]; + if(0){} + else if(reg_usage_kind == REGS_UsageKind_Normal && alias_slice.byte_size == 1) {mapped_type_key = e_type_key_basic(E_TypeKind_U8);} + else if(reg_usage_kind == REGS_UsageKind_Normal && alias_slice.byte_size == 2) {mapped_type_key = e_type_key_basic(E_TypeKind_U16);} + else if(reg_usage_kind == REGS_UsageKind_Normal && alias_slice.byte_size == 4) {mapped_type_key = e_type_key_basic(E_TypeKind_U32);} + else if(reg_usage_kind == REGS_UsageKind_Normal && alias_slice.byte_size == 8) {mapped_type_key = e_type_key_basic(E_TypeKind_U64);} + else + { + mapped_type_key = e_type_key_reg_alias(e_base_ctx->primary_module->arch, alias_num); + } } }break; diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 80c42766..82f01992 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2240,25 +2240,25 @@ RD_VIEW_UI_FUNCTION_DEF(text) { MD5 md5 = rd_md5_from_hash(hash); String8 md5_string = str8_struct(&md5); - file_is_out_of_date = !str8_match(md5_string, checksum_expected, 0); + file_is_out_of_date = !MemoryIsZeroStruct(&md5) && !str8_match(md5_string, checksum_expected, 0); }break; case RDI_ChecksumKind_SHA1: { SHA1 sha1 = rd_sha1_from_hash(hash); String8 sha1_string = str8_struct(&sha1); - file_is_out_of_date = !str8_match(sha1_string, checksum_expected, 0); + file_is_out_of_date = !MemoryIsZeroStruct(&sha1) && !str8_match(sha1_string, checksum_expected, 0); }break; case RDI_ChecksumKind_SHA256: { SHA256 sha256 = rd_sha256_from_hash(hash); String8 sha256_string = str8_struct(&sha256); - file_is_out_of_date = !str8_match(sha256_string, checksum_expected, 0); + file_is_out_of_date = !MemoryIsZeroStruct(&sha256) && !str8_match(sha256_string, checksum_expected, 0); }break; case RDI_ChecksumKind_Timestamp: { FileProperties props = os_properties_from_file_path(rd_regs()->file_path); String8 timestamp_string = str8_struct(&props.modified); - file_is_out_of_date = !str8_match(timestamp_string, checksum_expected, 0); + file_is_out_of_date = !MemoryIsZeroStruct(&props.modified) && !str8_match(timestamp_string, checksum_expected, 0); }break; } @@ -2381,7 +2381,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) { auto_selected = 1; auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); - eval = e_eval_from_stringf("(reg:rip.u64 & (~(0x4000 - 1)))"); + eval = e_eval_from_stringf("(reg:rip & (~(0x4000 - 1)))"); } } diff --git a/src/regs/generated/regs.meta.c b/src/regs/generated/regs.meta.c index fab1e6c9..f1a01b06 100644 --- a/src/regs/generated/regs.meta.c +++ b/src/regs/generated/regs.meta.c @@ -166,38 +166,38 @@ REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, @@ -268,46 +268,46 @@ REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, }; String8 regs_g_reg_code_x64_string_table[103] = @@ -779,14 +779,14 @@ REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, }; REGS_UsageKind regs_g_alias_code_x86_usage_kind_table[36] = @@ -811,22 +811,22 @@ REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, +REGS_UsageKind_Vector, }; String8 regs_g_reg_code_x86_string_table[61] = diff --git a/src/regs/regs.mdesk b/src/regs/regs.mdesk index 25d35691..a26bdf09 100644 --- a/src/regs/regs.mdesk +++ b/src/regs/regs.mdesk @@ -67,38 +67,38 @@ REGS_RegTableX64: {es 16 Normal} {fs 16 Normal} {gs 16 Normal} - {zmm0 512 Normal} - {zmm1 512 Normal} - {zmm2 512 Normal} - {zmm3 512 Normal} - {zmm4 512 Normal} - {zmm5 512 Normal} - {zmm6 512 Normal} - {zmm7 512 Normal} - {zmm8 512 Normal} - {zmm9 512 Normal} - {zmm10 512 Normal} - {zmm11 512 Normal} - {zmm12 512 Normal} - {zmm13 512 Normal} - {zmm14 512 Normal} - {zmm15 512 Normal} - {zmm16 512 Normal} - {zmm17 512 Normal} - {zmm18 512 Normal} - {zmm19 512 Normal} - {zmm20 512 Normal} - {zmm21 512 Normal} - {zmm22 512 Normal} - {zmm23 512 Normal} - {zmm24 512 Normal} - {zmm25 512 Normal} - {zmm26 512 Normal} - {zmm27 512 Normal} - {zmm28 512 Normal} - {zmm29 512 Normal} - {zmm30 512 Normal} - {zmm31 512 Normal} + {zmm0 512 Vector} + {zmm1 512 Vector} + {zmm2 512 Vector} + {zmm3 512 Vector} + {zmm4 512 Vector} + {zmm5 512 Vector} + {zmm6 512 Vector} + {zmm7 512 Vector} + {zmm8 512 Vector} + {zmm9 512 Vector} + {zmm10 512 Vector} + {zmm11 512 Vector} + {zmm12 512 Vector} + {zmm13 512 Vector} + {zmm14 512 Vector} + {zmm15 512 Vector} + {zmm16 512 Vector} + {zmm17 512 Vector} + {zmm18 512 Vector} + {zmm19 512 Vector} + {zmm20 512 Vector} + {zmm21 512 Vector} + {zmm22 512 Vector} + {zmm23 512 Vector} + {zmm24 512 Vector} + {zmm25 512 Vector} + {zmm26 512 Vector} + {zmm27 512 Vector} + {zmm28 512 Vector} + {zmm29 512 Vector} + {zmm30 512 Vector} + {zmm31 512 Vector} {k0 64 Normal} {k1 64 Normal} {k2 64 Normal} @@ -172,46 +172,46 @@ REGS_AliasTableX64: {ch rcx 8 8 Normal} {dh rdx 8 8 Normal} {bh rbx 8 8 Normal} - {xmm0 zmm0 0 128 Normal} - {xmm1 zmm1 0 128 Normal} - {xmm2 zmm2 0 128 Normal} - {xmm3 zmm3 0 128 Normal} - {xmm4 zmm4 0 128 Normal} - {xmm5 zmm5 0 128 Normal} - {xmm6 zmm6 0 128 Normal} - {xmm7 zmm7 0 128 Normal} - {xmm8 zmm8 0 128 Normal} - {xmm9 zmm9 0 128 Normal} - {xmm10 zmm10 0 128 Normal} - {xmm11 zmm11 0 128 Normal} - {xmm12 zmm12 0 128 Normal} - {xmm13 zmm13 0 128 Normal} - {xmm14 zmm14 0 128 Normal} - {xmm15 zmm15 0 128 Normal} - {ymm0 zmm0 0 256 Normal} - {ymm1 zmm1 0 256 Normal} - {ymm2 zmm2 0 256 Normal} - {ymm3 zmm3 0 256 Normal} - {ymm4 zmm4 0 256 Normal} - {ymm5 zmm5 0 256 Normal} - {ymm6 zmm6 0 256 Normal} - {ymm7 zmm7 0 256 Normal} - {ymm8 zmm8 0 256 Normal} - {ymm9 zmm9 0 256 Normal} - {ymm10 zmm10 0 256 Normal} - {ymm11 zmm11 0 256 Normal} - {ymm12 zmm12 0 256 Normal} - {ymm13 zmm13 0 256 Normal} - {ymm14 zmm14 0 256 Normal} - {ymm15 zmm15 0 256 Normal} - {mm0 fpr0 0 64 Normal} - {mm1 fpr1 0 64 Normal} - {mm2 fpr2 0 64 Normal} - {mm3 fpr3 0 64 Normal} - {mm4 fpr4 0 64 Normal} - {mm5 fpr5 0 64 Normal} - {mm6 fpr6 0 64 Normal} - {mm7 fpr7 0 64 Normal} + {xmm0 zmm0 0 128 Vector} + {xmm1 zmm1 0 128 Vector} + {xmm2 zmm2 0 128 Vector} + {xmm3 zmm3 0 128 Vector} + {xmm4 zmm4 0 128 Vector} + {xmm5 zmm5 0 128 Vector} + {xmm6 zmm6 0 128 Vector} + {xmm7 zmm7 0 128 Vector} + {xmm8 zmm8 0 128 Vector} + {xmm9 zmm9 0 128 Vector} + {xmm10 zmm10 0 128 Vector} + {xmm11 zmm11 0 128 Vector} + {xmm12 zmm12 0 128 Vector} + {xmm13 zmm13 0 128 Vector} + {xmm14 zmm14 0 128 Vector} + {xmm15 zmm15 0 128 Vector} + {ymm0 zmm0 0 256 Vector} + {ymm1 zmm1 0 256 Vector} + {ymm2 zmm2 0 256 Vector} + {ymm3 zmm3 0 256 Vector} + {ymm4 zmm4 0 256 Vector} + {ymm5 zmm5 0 256 Vector} + {ymm6 zmm6 0 256 Vector} + {ymm7 zmm7 0 256 Vector} + {ymm8 zmm8 0 256 Vector} + {ymm9 zmm9 0 256 Vector} + {ymm10 zmm10 0 256 Vector} + {ymm11 zmm11 0 256 Vector} + {ymm12 zmm12 0 256 Vector} + {ymm13 zmm13 0 256 Vector} + {ymm14 zmm14 0 256 Vector} + {ymm15 zmm15 0 256 Vector} + {mm0 fpr0 0 64 Vector} + {mm1 fpr1 0 64 Vector} + {mm2 fpr2 0 64 Vector} + {mm3 fpr3 0 64 Vector} + {mm4 fpr4 0 64 Vector} + {mm5 fpr5 0 64 Vector} + {mm6 fpr6 0 64 Vector} + {mm7 fpr7 0 64 Vector} } //////////////////////////////// @@ -278,14 +278,14 @@ REGS_RegTableX86: {fs 16 Normal} {gs 16 Normal} // SIMD REGISTERS - {ymm0 256 Normal} - {ymm1 256 Normal} - {ymm2 256 Normal} - {ymm3 256 Normal} - {ymm4 256 Normal} - {ymm5 256 Normal} - {ymm6 256 Normal} - {ymm7 256 Normal} + {ymm0 256 Vector} + {ymm1 256 Vector} + {ymm2 256 Vector} + {ymm3 256 Vector} + {ymm4 256 Vector} + {ymm5 256 Vector} + {ymm6 256 Vector} + {ymm7 256 Vector} } @table(name base off size usage) @@ -310,22 +310,22 @@ REGS_AliasTableX86: {bl ebx 0 8 Normal} {bpl ebp 0 8 Normal} {spl esp 0 8 Normal} - {xmm0 ymm0 0 128 Normal} - {xmm1 ymm1 0 128 Normal} - {xmm2 ymm2 0 128 Normal} - {xmm3 ymm3 0 128 Normal} - {xmm4 ymm4 0 128 Normal} - {xmm5 ymm5 0 128 Normal} - {xmm6 ymm6 0 128 Normal} - {xmm7 ymm7 0 128 Normal} - {mm0 fpr0 0 64 Normal} - {mm1 fpr1 0 64 Normal} - {mm2 fpr2 0 64 Normal} - {mm3 fpr3 0 64 Normal} - {mm4 fpr4 0 64 Normal} - {mm5 fpr5 0 64 Normal} - {mm6 fpr6 0 64 Normal} - {mm7 fpr7 0 64 Normal} + {xmm0 ymm0 0 128 Vector} + {xmm1 ymm1 0 128 Vector} + {xmm2 ymm2 0 128 Vector} + {xmm3 ymm3 0 128 Vector} + {xmm4 ymm4 0 128 Vector} + {xmm5 ymm5 0 128 Vector} + {xmm6 ymm6 0 128 Vector} + {xmm7 ymm7 0 128 Vector} + {mm0 fpr0 0 64 Vector} + {mm1 fpr1 0 64 Vector} + {mm2 fpr2 0 64 Vector} + {mm3 fpr3 0 64 Vector} + {mm4 fpr4 0 64 Vector} + {mm5 fpr5 0 64 Vector} + {mm6 fpr6 0 64 Vector} + {mm7 fpr7 0 64 Vector} } //////////////////////////////// From f67cf8b59d96ff8c61374c6607346898d286ff9c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 14:51:34 -0700 Subject: [PATCH 063/133] remove incorrect space promotion rule --- src/eval/eval_interpret.c | 6 +----- src/eval/eval_ir.c | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index 12ce59a3..a31993c1 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -125,7 +125,7 @@ e_interpret(String8 bytecode) } else switch(op) { - case E_IRExtKind_SetSpace: {ctrlbits = RDI_EVAL_CTRLBITS(32, 0, 0);}break; + case E_IRExtKind_SetSpace:{ctrlbits = RDI_EVAL_CTRLBITS(32, 0, 0);}break; default: { result.code = E_InterpretationCode_BadOp; @@ -210,10 +210,6 @@ e_interpret(String8 bytecode) result.code = E_InterpretationCode_BadMemRead; goto done; } - if(e_space_match(selected_space, e_interpret_ctx->reg_space)) - { - selected_space = e_interpret_ctx->primary_space; - } }break; case RDI_EvalOp_RegRead: diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 2187a178..01a93360 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -2178,7 +2178,6 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I { string_mapped = 1; RDI_LocationReg loc = *(RDI_LocationReg *)(all_location_data + block->location_data_off); - REGS_RegCode regs_reg_code = regs_reg_code_from_arch_rdi_code(arch, loc.reg_code); REGS_Rng reg_rng = regs_reg_code_rng_table_from_arch(arch)[regs_reg_code]; E_OpList oplist = {0}; From 2cc7f45ec1860df1afac7082aad5dcb74950fe9d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 15:06:46 -0700 Subject: [PATCH 064/133] promote register values to primary module space values for memory view specifically --- src/eval/eval_ir.c | 4 ++-- src/raddbg/raddbg_views.c | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 01a93360..5575990d 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -2600,8 +2600,8 @@ e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_Space *current_space U32 op = root->op; { E_Space zero_space = zero_struct; - if(!MemoryMatchStruct(&root->space, &zero_space) && - !MemoryMatchStruct(&root->space, current_space)) + if(!e_space_match(root->space, zero_space) && + !e_space_match(root->space, *current_space)) { *current_space = root->space; e_oplist_push_set_space(arena, out, root->space); diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 82f01992..f9684933 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2604,6 +2604,11 @@ RD_VIEW_UI_FUNCTION_DEF(memory) Vec4F32 main_tx_color_rgba = ui_color_from_name(str8_lit("text")); Vec4F32 main_tx_color_hsva = hsva_from_rgba(main_tx_color_rgba); F32 main_font_size = ui_bottom_font_size(); + if(e_space_match(eval.space, e_base_ctx->thread_reg_space)) + { + eval = e_value_eval_from_eval(eval); + eval.space = e_base_ctx->primary_module->space; + } Rng1U64 view_range = rd_space_range_from_eval(eval); if(eval.space.kind == 0) { From 783988c0ac5fd88c6b96ec812adb292f6a6bda87 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 15:44:35 -0700 Subject: [PATCH 065/133] expand ctrl process memory cache access to allow waiting for fresh results, rather than any results; use when doing a ctrl process memory write, to prefer viewing less stale data on exact frame. also expand trap net generation with success bit, use to retry stepping commands across frames if process memory reads are hindered. abort after N retries. --- src/content/content.c | 16 ++---- src/ctrl/ctrl_core.c | 18 +++---- src/ctrl/ctrl_core.h | 4 +- src/dbg_engine/dbg_engine_core.c | 83 ++++++++++++++++++++------------ src/dbg_engine/dbg_engine_core.h | 17 +++++-- src/raddbg/raddbg_core.c | 16 +++--- src/raddbg/raddbg_views.c | 2 +- 7 files changed, 89 insertions(+), 67 deletions(-) diff --git a/src/content/content.c b/src/content/content.c index 09e4928a..8f353678 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -276,20 +276,12 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) // rjf: push hash into key's history if(key_node) { - U128 last_hash = {0}; - if(key_node->hash_history_gen >= 1) + if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) { - last_hash = key_node->hash_history[(key_node->hash_history_gen-1)%ArrayCount(key_node->hash_history)]; - } - if(!u128_match(last_hash, hash)) - { - if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) - { - key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; - } - key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; - key_node->hash_history_gen += 1; + key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; } + key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; + key_node->hash_history_gen += 1; } // rjf: key is new -> add this key to the associated root diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index cc702204..0879b0ca 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6114,7 +6114,7 @@ ctrl_memory_artifact_destroy(AC_Artifact artifact) } internal C_Key -ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale) +ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale) { ProfBeginFunction(); struct @@ -6127,7 +6127,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 String8 key = str8_struct(&key_data); Access *access = access_open(); AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, - .flags = AC_Flag_HighPriority, + .flags = AC_Flag_HighPriority | (wait_for_fresh ? AC_Flag_WaitForFresh : 0), .gen = ctrl_mem_gen(), .slots_count = 2048, .stale_out = out_is_stale, @@ -6142,7 +6142,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 //- rjf: process memory reading helpers internal CTRL_ProcessMemorySlice -ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us) +ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, B32 wait_for_fresh, U64 endt_us) { ProfBeginFunction(); CTRL_ProcessMemorySlice result = {0}; @@ -6168,7 +6168,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn { U64 page_base_vaddr = page_range.min + page_idx*page_size; B32 page_is_stale = 0; - C_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale); + C_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, wait_for_fresh, endt_us, &page_is_stale); U128 page_hash = c_hash_from_key(page_key, 0); U128 page_last_hash = c_hash_from_key(page_key, 1); result.stale = (result.stale || page_is_stale); @@ -6289,7 +6289,7 @@ ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, { Temp scratch = scratch_begin(0, 0); U64 needed_size = dim_1u64(range); - CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, range, endt_us); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, range, 0, endt_us); B32 good = (slice.data.size >= needed_size && !slice.any_byte_bad); if(good) { @@ -6322,15 +6322,15 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) // time. if(result) { - U64 endt_us = os_now_microseconds()+5000; + U64 endt_us = os_now_microseconds()+10000; U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process - Rng1U64 page_range = r1u64(range.min/page_size, range.max/page_size); + Rng1U64 page_range = r1u64(range.min/page_size, (range.max+page_size-1)/page_size); for EachInRange(page_idx, page_range) { Temp scratch = scratch_begin(0, 0); - ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, r1u64(page_idx*page_size, (page_idx+1)*page_size), endt_us); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, r1u64(page_idx*page_size, (page_idx+1)*page_size), 1, endt_us); scratch_end(scratch); - if(os_now_microseconds() >= endt_us) + if(!slice.stale || os_now_microseconds() >= endt_us) { break; } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 60e0729f..93ed7dc9 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1004,10 +1004,10 @@ internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); -internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); +internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale); //- rjf: process memory reading helpers -internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us); +internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, B32 wait_for_fresh, U64 endt_us); internal B32 ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us); #define ctrl_process_memory_read_struct(process, vaddr, is_stale_out, ptr, endt_us) ctrl_process_memory_read((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us)) diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index 6643359e..afd632a9 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -290,11 +290,11 @@ d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, D_CmdParams * // - for any instructions which may change the stack pointer, traps are placed // at them with the "save-stack-pointer | single-step-after" behaviors. -internal CTRL_TrapList +internal D_TrapNet d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread) { Temp scratch = scratch_begin(&arena, 1); - CTRL_TrapList result = {0}; + D_TrapNet result = {0}; // rjf: thread => unpacked info CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); @@ -305,13 +305,15 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread) String8 machine_code = {0}; { Rng1U64 rng = r1u64(ip_vaddr, ip_vaddr+max_instruction_size_from_arch(arch)); - CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, rng, os_now_microseconds()+5000); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, rng, 0, os_now_microseconds()+5000); machine_code = machine_code_slice.data; } // rjf: build traps if machine code was read successfully if(machine_code.size != 0) { + result.good = 1; + // rjf: decode instruction DASM_Inst inst = dasm_inst_from_code(scratch.arena, arch, ip_vaddr, machine_code, DASM_Syntax_Intel); @@ -319,7 +321,7 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread) if(inst.flags & DASM_InstFlag_Call || inst.flags & DASM_InstFlag_Repeats) { CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, ip_vaddr+inst.size}; - ctrl_trap_list_push(arena, &result, &trap); + ctrl_trap_list_push(arena, &result.traps, &trap); } } @@ -327,12 +329,12 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread) return result; } -internal CTRL_TrapList +internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) { Temp scratch = scratch_begin(&arena, 1); log_infof("step_over_line:\n{\n"); - CTRL_TrapList result = {0}; + D_TrapNet result = {0}; // rjf: thread => info Arch arch = thread->arch; @@ -380,7 +382,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) B32 good_machine_code = 0; if(good_line_info) { - CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, os_now_microseconds()+50000); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, 0, os_now_microseconds()+50000); machine_code = machine_code_slice.data; good_machine_code = (machine_code.size == dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad); LogInfoNamedBlockF("machine_code_slice") @@ -469,7 +471,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) if(add) { CTRL_Trap trap = {flags, trap_addr}; - ctrl_trap_list_push(arena, &result, &trap); + ctrl_trap_list_push(arena, &result.traps, &trap); } } @@ -477,11 +479,17 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) if(good_line_info && good_machine_code) { CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max}; - ctrl_trap_list_push(arena, &result, &trap); + ctrl_trap_list_push(arena, &result.traps, &trap); + } + + // rjf: good if we got machine code + if(good_machine_code) + { + result.good = 1; } // rjf: log - LogInfoNamedBlockF("traps") for(CTRL_TrapNode *n = result.first; n != 0; n = n->next) + LogInfoNamedBlockF("traps") for(CTRL_TrapNode *n = result.traps.first; n != 0; n = n->next) { log_infof("{flags:0x%x, vaddr:0x%I64x}\n", n->v.flags, n->v.vaddr); } @@ -491,11 +499,11 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) return result; } -internal CTRL_TrapList +internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) { Temp scratch = scratch_begin(&arena, 1); - CTRL_TrapList result = {0}; + D_TrapNet result = {0}; // rjf: thread => info Arch arch = thread->arch; @@ -538,7 +546,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) B32 good_machine_code = 0; if(good_line_info) { - CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, os_now_microseconds()+5000); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, 0, os_now_microseconds()+5000); machine_code = machine_code_slice.data; good_machine_code = (machine_code.size == dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad); } @@ -625,7 +633,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) if(add) { CTRL_Trap trap = {flags, trap_addr}; - ctrl_trap_list_push(arena, &result, &trap); + ctrl_trap_list_push(arena, &result.traps, &trap); } } @@ -633,7 +641,13 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) if(good_line_info && good_machine_code) { CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max}; - ctrl_trap_list_push(arena, &result, &trap); + ctrl_trap_list_push(arena, &result.traps, &trap); + } + + // rjf: good if we got machine code + if(good_machine_code) + { + result.good = 1; } scratch_end(scratch); @@ -981,7 +995,7 @@ d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 U64 tls_index = 0; if(addr_size != 0) { - CTRL_ProcessMemorySlice tls_index_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, tls_vaddr_range, 0); + CTRL_ProcessMemorySlice tls_index_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, tls_vaddr_range, 0, 0); if(tls_index_slice.data.size >= addr_size) { tls_index = *(U64 *)tls_index_slice.data.str; @@ -994,13 +1008,13 @@ d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 U64 thread_info_addr = root_vaddr; U64 tls_addr_off = tls_index*addr_size; U64 tls_addr_array = 0; - CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0); + CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0, 0); String8 tls_addr_array_data = tls_addr_array_slice.data; if(tls_addr_array_data.size >= 8) { MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64)); } - CTRL_ProcessMemorySlice result_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0); + CTRL_ProcessMemorySlice result_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0, 0); String8 result_data = result_slice.data; if(result_data.size >= 8) { @@ -1791,15 +1805,14 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P } else { - B32 good = 1; - CTRL_TrapList traps = {0}; + D_TrapNet trap_net = {0}; switch(cmd->kind) { default: break; - case D_CmdKind_StepIntoInst: {}break; - case D_CmdKind_StepOverInst: {traps = d_trap_net_from_thread__step_over_inst(scratch.arena, thread);}break; - case D_CmdKind_StepIntoLine: {traps = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break; - case D_CmdKind_StepOverLine: {traps = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; + case D_CmdKind_StepIntoInst: {trap_net.good = 1;}break; + case D_CmdKind_StepOverInst: {trap_net = d_trap_net_from_thread__step_over_inst(scratch.arena, thread);}break; + case D_CmdKind_StepIntoLine: {trap_net = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break; + case D_CmdKind_StepOverLine: {trap_net = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; case D_CmdKind_StepOut: { Access *access = access_open(); @@ -1812,32 +1825,42 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P { U64 vaddr = regs_rip_from_arch_block(thread->arch, callstack.concrete_frames[1]->regs); CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, vaddr}; - ctrl_trap_list_push(scratch.arena, &traps, &trap); + ctrl_trap_list_push(scratch.arena, &trap_net.traps, &trap); + trap_net.good = 1; } else { log_user_error(str8_lit("Could not find the return address of the current callstack frame successfully.")); - good = 0; } access_close(access); }break; } - if(good && traps.count != 0) + if(trap_net.good && trap_net.traps.count != 0) { need_run = 1; run_kind = D_RunKind_Step; run_thread = thread; run_flags = 0; - run_traps = traps; + run_traps = trap_net.traps; } - if(good && traps.count == 0) + else if(trap_net.good && trap_net.traps.count == 0) { need_run = 1; run_kind = D_RunKind_SingleStep; run_thread = thread; run_flags = 0; - run_traps = traps; + run_traps = trap_net.traps; + } + else if(!trap_net.good && params->retry_idx < 1000) + { + D_CmdParams params_copy = *params; + params_copy.retry_idx += 1; + d_push_cmd(cmd->kind, ¶ms_copy); + } + else if(!trap_net.good) + { + log_user_error(str8_lit("Could not successfully step.")); } } }break; diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index 1385e213..3748911b 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -69,6 +69,16 @@ struct D_PathMapArray U64 count; }; +//////////////////////////////// +//~ rjf: Trap Nets + +typedef struct D_TrapNet D_TrapNet; +struct D_TrapNet +{ + CTRL_TrapList traps; + B32 good; +}; + //////////////////////////////// //~ rjf: Tick Output Types @@ -187,6 +197,7 @@ struct D_CmdParams U32 pid; U32 rgba; D_TargetArray targets; + U64 retry_idx; }; typedef struct D_Cmd D_Cmd; @@ -358,9 +369,9 @@ internal void d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, //////////////////////////////// //~ rjf: Stepping "Trap Net" Builders -internal CTRL_TrapList d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread); -internal CTRL_TrapList d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread); -internal CTRL_TrapList d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread); +internal D_TrapNet d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread); +internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread); +internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread); //////////////////////////////// //~ rjf: Debug Info Lookups diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 2c907bda..7a3bf34f 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1805,7 +1805,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) default:{}break; case CTRL_EntityKind_Process: { - CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, entity->handle, range, rd_state->frame_eval_memread_endt_us); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, entity->handle, range, 0, rd_state->frame_eval_memread_endt_us); String8 data = slice.data; if(data.size == dim_1u64(range)) { @@ -2159,7 +2159,7 @@ rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated) CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); if(entity->kind == CTRL_EntityKind_Process) { - result = ctrl_key_from_process_vaddr_range(entity->handle, range, zero_terminated, 0, 0); + result = ctrl_key_from_process_vaddr_range(entity->handle, range, zero_terminated, 0, 0, 0); } }break; } @@ -4641,7 +4641,7 @@ rd_view_ui(Rng2F32 rect) CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(cell->eval.space); if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && space_entity->kind == CTRL_EntityKind_Process) { - CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, space_entity->handle, cell_vaddr_rng, rd_state->frame_eval_memread_endt_us); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, space_entity->handle, cell_vaddr_rng, 0, rd_state->frame_eval_memread_endt_us); for(U64 idx = 0; idx < (slice.data.size+63)/64; idx += 1) { if(slice.byte_changed_flags[idx] != 0) @@ -5047,7 +5047,7 @@ rd_view_ui(Rng2F32 rect) cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && row_info->callstack_thread == &ctrl_entity_nil && e_type_kind_from_key(cell->eval.irtree.type_key) != E_TypeKind_Function) - UI_FontSize(ui_top_font_size()*0.8f) + UI_FontSize(ui_top_font_size()*0.9f) { if(cell_width_px >= ui_top_font_size()*8.f) { @@ -7133,12 +7133,8 @@ rd_window_frame(void) ev_key_set_expansion(rd_view_eval_view(), ev_key_root(), ev_key_make(ev_hash_from_key(ev_key_root()), 1), 1); predicted_block_tree = ev_block_tree_from_eval(scratch.arena, rd_view_eval_view(), str8_zero(), hover_eval); } - F32 row_height_px = ui_top_px_height(); - U64 max_row_count = (U64)floor_f32(ui_top_font_size()*10.f / row_height_px); - if(ws->hover_eval_focused) - { - max_row_count *= 3; - } + F32 row_height_px = floor_f32(ui_top_font_size()*rd_setting_f32_from_name(str8_lit("row_height"))); + U64 max_row_count = 12; U64 needed_row_count = Min(max_row_count, predicted_block_tree.total_row_count); F32 width_px = floor_f32(70.f*ui_top_font_size()); F32 height_px = needed_row_count*row_height_px; diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index f9684933..5dd6e0c4 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2973,7 +2973,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); if(entity->kind == CTRL_EntityKind_Process) { - CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, entity->handle, viz_range_bytes, 0); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, entity->handle, viz_range_bytes, 0, 0); visible_memory_change_flags = slice.byte_changed_flags; visible_memory_bad_flags = slice.byte_bad_flags; } From ec69ebff35d88069baa8aa93127a9a691046db2e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 15:50:52 -0700 Subject: [PATCH 066/133] fix tick-deferred command mechanism in debug engine --- src/dbg_engine/dbg_engine_core.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index afd632a9..d5ee726f 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -1604,6 +1604,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P ////////////////////////////// //- rjf: process top-level commands // + D_CmdList deferred_cmds = {0}; CTRL_MsgList ctrl_msgs = {0}; ProfScope("process top-level commands") { @@ -1852,11 +1853,11 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P run_flags = 0; run_traps = trap_net.traps; } - else if(!trap_net.good && params->retry_idx < 1000) + else if(!trap_net.good && params->retry_idx < 100) { D_CmdParams params_copy = *params; params_copy.retry_idx += 1; - d_push_cmd(cmd->kind, ¶ms_copy); + d_cmd_list_push_new(scratch.arena, &deferred_cmds, cmd->kind, ¶ms_copy); } else if(!trap_net.good) { @@ -2119,6 +2120,14 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P MemoryZeroStruct(&d_state->cmds); } + ////////////////////////////// + //- rjf: push deferred commands + // + for EachNode(n, D_CmdNode, deferred_cmds.first) + { + d_cmd_list_push_new(d_state->cmds_arena, &d_state->cmds, n->cmd.kind, &n->cmd.params); + } + ////////////////////////////// //- rjf: push new control messages to queue - try to send queue to control, // clear queue if successful (if not, we'll just keep them around until From cd26bf1bcc7110e3b239f0bc00c4b738c7f977fa Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 16:06:59 -0700 Subject: [PATCH 067/133] only submit empty ctrl process memory artifacts if we have no other history; only retry on mem gen tears & valid ranges --- src/ctrl/ctrl_core.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 0879b0ca..1b0810a8 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6077,16 +6077,29 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) content_key.id.u128[0] = u128_hash_from_str8(key); } - //- rjf: read successful -> submit to hash store + //- rjf: determine if we have any history for this key + B32 key_has_history = 0; + { + U128 last_hash = c_hash_from_key(content_key, 0); + if(!u128_match(last_hash, u128_zero())) + { + key_has_history = 1; + } + } + + //- rjf: read successful, OR we have no history -> submit to hash store U128 hash = {0}; - if(range_size != 0 && pre_read_mem_gen == post_read_mem_gen) + if((zero_terminated_size > 0 || !key_has_history) && range_size != 0 && pre_read_mem_gen == post_read_mem_gen) { hash = c_submit_data(content_key, &range_arena, str8((U8*)range_base, zero_terminated_size)); } else if(range_arena != 0) { arena_release(range_arena); - retry_out[0] = 1; + if(pre_read_mem_gen != post_read_mem_gen && range_size != 0) + { + retry_out[0] = 1; + } } //- rjf: wakeup on new reads From 166b84cf3004fe8b979e46b0851f2e97c9107e99 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 16:24:54 -0700 Subject: [PATCH 068/133] eliminate content-layer-specific u128 hash --- src/content/content.c | 17 +---------------- src/content/content.h | 1 - src/ctrl/ctrl_core.c | 18 ++++++++++++------ src/tester/tester_main.c | 4 ++-- 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/content/content.c b/src/content/content.c index 8f353678..04a3b6bb 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -7,21 +7,6 @@ //////////////////////////////// //~ rjf: Basic Helpers -#if !defined(XXH_IMPLEMENTATION) -# define XXH_IMPLEMENTATION -# define XXH_STATIC_LINKING_ONLY -# include "third_party/xxHash/xxhash.h" -#endif - -internal U128 -c_hash_from_data(String8 data) -{ - U128 u128 = {0}; - XXH128_hash_t hash = XXH3_128bits(data.str, data.size); - MemoryCopy(&u128, &hash, sizeof(u128)); - return u128; -} - internal C_ID c_id_make(U64 u64_0, U64 u64_1) { @@ -181,7 +166,7 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; //- rjf: hash data, unpack hash - U128 hash = c_hash_from_data(data); + U128 hash = u128_hash_from_str8(data); U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count; U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; diff --git a/src/content/content.h b/src/content/content.h index e314f0f6..90f44cda 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -197,7 +197,6 @@ global C_Shared *c_shared = 0; //////////////////////////////// //~ rjf: Basic Helpers -internal U128 c_hash_from_data(String8 data); internal C_ID c_id_make(U64 u64_0, U64 u64_1); internal B32 c_id_match(C_ID a, C_ID b); internal C_Key c_key_make(C_Root root, C_ID id); diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 1b0810a8..5f4cdedf 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6009,15 +6009,15 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); if(range_size != 0) { + // rjf: set up arena U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); - if(range_arena == 0) - { - range_size = 0; - } - else + + // rjf: if we got an arena -> push buffer & read + if(range_arena != 0) { + // rjf: read as much as possible range_base = push_array_no_zero(range_arena, U8, range_size); U64 bytes_read = 0; U64 retry_count = 0; @@ -6042,16 +6042,22 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) break; } } + + // rjf: if we read nothing, release arena if(bytes_read == 0) { arena_release(range_arena); range_base = 0; range_arena = 0; } + + // rjf: if we only got a partial read, zero the rest else if(bytes_read < range_size) { MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); } + + // rjf: determine final size; zero terminate if needed; pop any unneeded bytes if zero-terminating zero_terminated_size = bytes_read; if(zero_terminated && range_base != 0) { @@ -6091,7 +6097,7 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) U128 hash = {0}; if((zero_terminated_size > 0 || !key_has_history) && range_size != 0 && pre_read_mem_gen == post_read_mem_gen) { - hash = c_submit_data(content_key, &range_arena, str8((U8*)range_base, zero_terminated_size)); + hash = c_submit_data(content_key, &range_arena, str8((U8 *)range_base, zero_terminated_size)); } else if(range_arena != 0) { diff --git a/src/tester/tester_main.c b/src/tester/tester_main.c index 4ee85062..9d34aad4 100644 --- a/src/tester/tester_main.c +++ b/src/tester/tester_main.c @@ -148,7 +148,7 @@ for(Test *test = test_##name_identifier; test != 0; test = 0) Temp scratch = scratch_begin(0, 0); String8 path = n->string; String8 data = os_data_from_file_path(scratch.arena, path); - rdi_hashes[idx] = c_hash_from_data(data); + rdi_hashes[idx] = u128_hash_from_str8(data); rdi_paths_array[idx] = path; scratch_end(scratch); } @@ -160,7 +160,7 @@ for(Test *test = test_##name_identifier; test != 0; test = 0) Temp scratch = scratch_begin(0, 0); String8 path = n->string; String8 data = os_data_from_file_path(scratch.arena, path); - dump_hashes[idx] = c_hash_from_data(data); + dump_hashes[idx] = u128_hash_from_str8(data); dump_paths_array[idx] = path; scratch_end(scratch); } From d2feaa5f568258f7d15abdbc05e588a3f89053e1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 16:45:02 -0700 Subject: [PATCH 069/133] oops, fix dbgi search arenas leak! --- src/dbg_info/dbg_info.c | 43 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 377106e7..077a7686 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -1071,8 +1071,16 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) } lane_sync(); - //- rjf: do wide search on all lanes - Arena *arena = arena_alloc(); + //- rjf: do wide search on all lanes + Arena *arena = arena_alloc(); + Arena **arenas = 0; + U64 arenas_count = lane_count(); + if(lane_idx() == 0) + { + arenas = push_array(arena, Arena *, arenas_count); + } + lane_sync_u64(&arenas, 0); + arenas[lane_idx()] = arena; DI_SearchItemChunkList *lanes_items = 0; ProfScope("do wide search on all lanes") { @@ -1383,9 +1391,10 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) lane_sync(); //- rjf: bundle as artifact - artifact.u64[0] = (U64)arena; - artifact.u64[1] = (U64)items.v; - artifact.u64[2] = items.count; + artifact.u64[0] = (U64)arenas; + artifact.u64[1] = arenas_count; + artifact.u64[2] = (U64)items.v; + artifact.u64[3] = items.count; } scratch_end(scratch); access_close(access); @@ -1395,12 +1404,20 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) internal void di_search_artifact_destroy(AC_Artifact artifact) -{ - Arena *arena = (Arena *)artifact.u64[0]; - if(arena != 0) - { - arena_release(arena); - } +{ + Temp scratch = scratch_begin(0, 0); + Arena **arenas = (Arena **)artifact.u64[0]; + U64 arenas_count = artifact.u64[1]; + Arena **arenas_copy = push_array(scratch.arena, Arena *, arenas_count); + MemoryCopy(arenas_copy, arenas, sizeof(Arena *) * arenas_count); + for EachIndex(idx, arenas_count) + { + if(arenas_copy[idx]) + { + arena_release(arenas_copy[idx]); + } + } + scratch_end(scratch); } internal DI_SearchItemArray @@ -1421,8 +1438,8 @@ di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, S AC_Artifact artifact = ac_artifact_from_key(access, key, di_search_artifact_create, di_search_artifact_destroy, endt_us, .gen = di_load_gen(), .flags = AC_Flag_Wide, .stale_out = stale_out); // rjf: unpack artifact - result.v = (DI_SearchItem *)artifact.u64[1]; - result.count = artifact.u64[2]; + result.v = (DI_SearchItem *)artifact.u64[2]; + result.count = artifact.u64[3]; scratch_end(scratch); } From 7ff5764696a64a9bf5ba0b84c006a2b0168a10a2 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 16:57:05 -0700 Subject: [PATCH 070/133] store successful queries keyed by target section as well, to avoid different table evals having different success states - fixes autocomplete flicker --- src/raddbg/raddbg_eval.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 59611487..e5b35811 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1653,11 +1653,12 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) B32 stale = 0; accel->section = section; accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us, &stale); - RD_Cfg *last_successful_query_cfg = rd_immediate_cfg_from_keyf("last_successful_query_%I64x", rd_regs()->view); + RD_Cfg *last_successful_query_cfg = rd_immediate_cfg_from_keyf("last_successful_query_%I64x_%I64u", rd_regs()->view, (U64)section); if(stale) { String8 last_query = last_successful_query_cfg->first->string; accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, last_query, endt_us, 0); + rd_request_frame(); } else { From fb825247ed61d80b9fbef41273829215ef2eee4f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 17:20:44 -0700 Subject: [PATCH 071/133] resolve register-space evaluations to primary-module space evaluations in the visualizers --- src/raddbg/raddbg_core.c | 3 ++- src/raddbg/raddbg_views.c | 42 +++++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 7a3bf34f..03383933 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -10773,7 +10773,8 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 query_expr, String8 strin E_TypeKind eval_type_kind = e_type_kind_from_key(e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)); if(eval_type_kind == E_TypeKind_Ptr || eval_type_kind == E_TypeKind_LRef || - eval_type_kind == E_TypeKind_RRef) + eval_type_kind == E_TypeKind_RRef || + e_space_match(eval.space, e_base_ctx->thread_reg_space)) { eval = e_value_eval_from_eval(eval); } diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 5dd6e0c4..0c7a0bb5 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2361,6 +2361,16 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) Temp scratch = scratch_begin(0, 0); Access *access = access_open(); + ////////////////////////////// + //- rjf: if disassembly views are parameterized by a register-space evaluation, + // we will interpret it as an address in the primary module. + // + if(e_space_match(eval.space, e_base_ctx->thread_reg_space)) + { + eval = e_value_eval_from_eval(eval); + eval.space = e_base_ctx->primary_module->space; + } + ////////////////////////////// //- rjf: if disassembly views are not parameterized by anything, they // automatically snap to the selected thread's RIP, OR the "temp look @@ -2596,6 +2606,27 @@ RD_VIEW_UI_FUNCTION_DEF(memory) Temp scratch = scratch_begin(0, 0); RD_MemoryViewState *mv = rd_view_state(RD_MemoryViewState); + ////////////////////////////// + //- rjf: if memory views are parameterized by a register-space evaluation, + // we will interpret it as an address in the primary module. + // + if(e_space_match(eval.space, e_base_ctx->thread_reg_space)) + { + eval = e_value_eval_from_eval(eval); + eval.space = e_base_ctx->primary_module->space; + } + + ////////////////////////////// + //- rjf: if memory views are parameterized by nothing, we will + // default to showing the entire memory space of the primary module. + // + Rng1U64 view_range = rd_space_range_from_eval(eval); + if(eval.space.kind == 0) + { + eval.space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); + view_range = rd_whole_range_from_eval_space(eval.space); + } + ////////////////////////////// //- rjf: unpack parameterization info // @@ -2604,17 +2635,6 @@ RD_VIEW_UI_FUNCTION_DEF(memory) Vec4F32 main_tx_color_rgba = ui_color_from_name(str8_lit("text")); Vec4F32 main_tx_color_hsva = hsva_from_rgba(main_tx_color_rgba); F32 main_font_size = ui_bottom_font_size(); - if(e_space_match(eval.space, e_base_ctx->thread_reg_space)) - { - eval = e_value_eval_from_eval(eval); - eval.space = e_base_ctx->primary_module->space; - } - Rng1U64 view_range = rd_space_range_from_eval(eval); - if(eval.space.kind == 0) - { - eval.space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); - view_range = rd_whole_range_from_eval_space(eval.space); - } U64 cursor_base_vaddr = rd_view_setting_u64_from_name(str8_lit("cursor")); U64 mark_base_vaddr = rd_view_setting_u64_from_name(str8_lit("mark")); U64 cursor_size = rd_view_setting_u64_from_name(str8_lit("cursor_size")); From 9e110bbe6de90f88fcde1ddde8c9fd3255143c1a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 7 Oct 2025 17:23:58 -0700 Subject: [PATCH 072/133] resolve register space -> primary module space in all visualizers which work on, broadly speaking, ranges of memory --- src/raddbg/raddbg_views.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 0c7a0bb5..431f1e9f 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -3962,6 +3962,16 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) Temp scratch = scratch_begin(0, 0); Access *access = access_open(); + ////////////////////////////// + //- rjf: if parameterized by a register-space evaluation, interpret as an + // address in the primary module. + // + if(e_space_match(eval.space, e_base_ctx->thread_reg_space)) + { + eval = e_value_eval_from_eval(eval); + eval.space = e_base_ctx->primary_module->space; + } + ////////////////////////////// //- rjf: evaluate expression // @@ -4544,6 +4554,16 @@ RD_VIEW_UI_FUNCTION_DEF(geo3d) Access *access = access_open(); RD_Geo3DViewState *state = rd_view_state(RD_Geo3DViewState); + ////////////////////////////// + //- rjf: if parameterized by a register-space evaluation, interpret as an + // address in the primary module. + // + if(e_space_match(eval.space, e_base_ctx->thread_reg_space)) + { + eval = e_value_eval_from_eval(eval); + eval.space = e_base_ctx->primary_module->space; + } + ////////////////////////////// //- rjf: unpack parameters // From fb0d42e6d86a700fa493fb60b7174f973a93e9d1 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 7 Oct 2025 17:14:26 -0700 Subject: [PATCH 073/133] extend stb_sprintf.h with formatter for Rng1U64 via %r --- src/third_party/stb/stb_sprintf.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/third_party/stb/stb_sprintf.h b/src/third_party/stb/stb_sprintf.h index 1238469f..113736aa 100644 --- a/src/third_party/stb/stb_sprintf.h +++ b/src/third_party/stb/stb_sprintf.h @@ -743,6 +743,30 @@ cl = lg; \ ++bf; } }break; + + case 'r': + { + Rng1U64 range = va_arg(va, Rng1U64); + *bf = '['; ++bf; + + U8 buffer[ARENA_HEADER_SIZE + 128]; + Arena *arena = arena_alloc_(&(ArenaParams){ .flags = ArenaFlag_NoChain, .reserve_size = sizeof(buffer), .commit_size = sizeof(buffer), .optional_backing_buffer = buffer }); + + String8 min = str8_from_u64(arena, range.min, 16, 0, 0); + MemoryCopyStr8(bf, min); + bf += min.size; + + *bf = ','; ++bf; + *bf = ' '; ++bf; + + arena_clear(arena); + String8 max = str8_from_u64(arena, range.max, 16, 0, 0); + MemoryCopyStr8(bf, max); + bf += max.size; + + *bf = ')'; ++bf; + }break; + // // NOTE(rjf): DEBUGGER PROJECT ADDITION ^^^ //- From 62ae5ca3f5f59b07c2c56234c347831385639b8e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 7 Oct 2025 18:11:43 -0700 Subject: [PATCH 074/133] stringify format and cfa opcodes enums --- src/dwarf/dwarf.c | 24 ++++++++++++++++++++++++ src/dwarf/dwarf.h | 4 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/dwarf/dwarf.c b/src/dwarf/dwarf.c index 3b946ae1..6063f0d7 100644 --- a/src/dwarf/dwarf.c +++ b/src/dwarf/dwarf.c @@ -434,6 +434,17 @@ dw_push_count_from_expr_op(DW_ExprOp op) //////////////////////////////// //~ rjf: String <=> Enum +internal String8 +dw_string_from_format(DW_Format format) +{ + switch (format) { + case DW_Format_Null: return str8_zero(); + case DW_Format_32Bit: return str8_lit("DWARF32"); + case DW_Format_64Bit: return str8_lit("DWARF64"); + } + return str8_zero(); +} + internal String8 dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op) { @@ -704,3 +715,16 @@ dw_string_from_register(Arena *arena, Arch arch, U64 reg_id) } return reg_str; } + +internal String8 +dw_string_from_cfa_opcode(DW_CFA cfa_opcode) +{ + switch (cfa_opcode) { +#define X(_NAME, _ID) case _ID: return str8_lit(Stringify(_NAME)); + DW_CFA_Kind1_XList(X) + DW_CFA_Kind2_XList(X) +#undef X + default: InvalidPath; break; + } + return str8_zero(); +} diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index 7a6b4b47..a0515bcc 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -1372,7 +1372,7 @@ typedef enum DW_CFAEnum { #define X(_N, _ID) DW_CFA_##_N = _ID, DW_CFA_Kind1_XList(X) - DW_CFA_Kind2_XList(X) + DW_CFA_Kind2_XList(X) #undef X DW_CFA_OplKind1 = DW_CFA_ValExpr, @@ -1785,6 +1785,7 @@ internal U64 dw_operand_count_from_expr_op(DW_ExprOp op); //////////////////////////////// //~ rjf: String <=> Enum +internal String8 dw_string_from_format(DW_Format format); internal String8 dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op); internal String8 dw_string_from_tag_kind(Arena *arena, DW_TagKind kind); internal String8 dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind); @@ -1800,5 +1801,6 @@ internal String8 dw_string_from_loc_list_entry_kind(Arena *arena, DW_LLE kind); internal String8 dw_string_from_section_kind(Arena *arena, DW_SectionKind kind); internal String8 dw_string_from_rng_list_entry_kind(Arena *arena, DW_RLE kind); internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id); +internal String8 dw_string_from_cfa_opcode(DW_CFA cfa_opcode); #endif // DWARF_H From 7cf3eaf73f0994b9f0d4d07fa12dcf05a7800090 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 7 Oct 2025 18:13:07 -0700 Subject: [PATCH 075/133] parsers for CIE and FDE --- src/dwarf/dwarf_parse.c | 154 ++++++++++++++++++++++++++++++++++++++++ src/dwarf/dwarf_parse.h | 54 ++++++++++++++ 2 files changed, 208 insertions(+) diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index b944156a..89cf0292 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -3323,3 +3323,157 @@ dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data) return expr; } +internal +DW_READ_CFI_PTR(dw_read_cfi_ptr) +{ + DW_UnpackedCIE *cie = ud; + U64 read_size = 0; + if (cie->segment_selector_size) { + NotImplemented; + } else { + read_size = str8_deserial_read(data, off, ptr_out, cie->address_size, cie->address_size); + } + return read_size; +} + +internal U64 +dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out) +{ + U32 first_four_bytes = 0; + str8_deserial_read_struct(data, off, &first_four_bytes); + DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; + + U64 length = 0; + U64 length_size = str8_deserial_read_dwarf_packed_size(data, off, &length); + if (length_size == 0) { goto exit; } + + Rng1U64 entry_range = rng_1u64(off + length_size, off + length_size + length); + String8 entry_data = str8_substr(data, entry_range); + U64 id = 0; + U64 id_size = str8_deserial_read_dwarf_uint(entry_data, 0, format, &id); + if (id_size == 0) { goto exit; } + + U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64; + desc_out->format = format; + desc_out->type = (id == id_type) ? DW_DescriptorEntryType_CIE : DW_DescriptorEntryType_FDE; + desc_out->entry_range = entry_range; + +exit:; + return length + length_size; +} + +internal B32 +dw_unpack_cie(String8 data, DW_Format format, Arch arch, DW_UnpackedCIE *cie_out) +{ + B32 is_parsed = 0; + U64 cursor = 0; + + U64 cie_id = 0; + U64 cie_id_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id); + if (cie_id_size == 0) { goto exit; } + cursor += cie_id_size; + + U8 version = 0; + U64 version_size = str8_deserial_read_struct(data, cursor, &version); + if (version_size == 0) { goto exit; } + cursor += version_size; + + String8 aug_string = {0}; + U64 aug_string_size = str8_deserial_read_cstr(data, cursor, &aug_string); + if (aug_string_size == 0) { goto exit; } + cursor += aug_string_size; + + U8 address_size = 0; + U8 segment_selector_size = 0; + if (version >= DW_Version_4) { + U64 address_size_size = str8_deserial_read_struct(data, cursor, &address_size); + if (address_size_size == 0) { goto exit; } + cursor += address_size_size; + + U64 segment_selector_size_size = str8_deserial_read_struct(data, cursor, &segment_selector_size); + if (segment_selector_size_size == 0) { goto exit; } + cursor += segment_selector_size; + } else { + address_size = byte_size_from_arch(arch); + } + + U64 code_align_factor = 0; + U64 code_align_factor_size = str8_deserial_read_uleb128(data, cursor, &code_align_factor); + if (code_align_factor_size == 0) { goto exit; } + cursor += code_align_factor_size; + + S64 data_align_factor = 0; + U64 data_align_factor_size = str8_deserial_read_sleb128(data, cursor, &data_align_factor); + if (data_align_factor_size == 0) { goto exit; } + cursor += data_align_factor_size; + + U64 ret_addr_reg = 0; + U64 ret_addr_reg_size = 0; + if (version == DW_Version_1) { ret_addr_reg_size = str8_deserial_read(data, cursor, &ret_addr_reg, sizeof(U8), sizeof(U8)); } + else { ret_addr_reg_size = str8_deserial_read_uleb128(data, cursor, &ret_addr_reg); } + if (ret_addr_reg_size == 0) { goto exit; } + cursor += ret_addr_reg_size; + + if (aug_string.size > 0) { goto exit; } + + cie_out->init_insts = str8_skip(data, cursor); + cie_out->aug_string = aug_string; + cie_out->code_align_factor = code_align_factor; + cie_out->data_align_factor = data_align_factor; + cie_out->ret_addr_reg = ret_addr_reg; + cie_out->version = version; + cie_out->address_size = address_size; + cie_out->segment_selector_size = segment_selector_size; + + is_parsed = 1; +exit:; + return is_parsed; +} + +internal B32 +dw_unpack_fde(String8 data, + DW_Format format, + DW_CIEFromOffsetFunc *cie_from_offset_func, + void *cie_from_offset_ud, + DW_UnpackedFDE *fde_out) +{ + B32 is_parsed = 0; + U64 cursor = 0; + + // extract CIE pointer + U64 cie_pointer = 0; + U64 cie_pointer_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_pointer); + if (cie_pointer_size == 0) { goto exit; } + cursor += cie_pointer_size; + + // map offset -> CIE + DW_UnpackedCIE *cie = cie_from_offset_func(cie_from_offset_ud, cie_pointer); + if (cie == 0) { goto exit; } + + // extract address of first instruction + U64 pc_begin = 0; + U64 pc_begin_size = dw_read_cfi_ptr(data, cursor, cie, &pc_begin); + if (pc_begin_size == 0) { goto exit; } + cursor += pc_begin_size; + + // extract instruction range size + U64 pc_range = 0; + U64 pc_range_size = dw_read_cfi_ptr(data, cursor, cie, &pc_range); + if (pc_range_size == 0) { goto exit; } + cursor += pc_range_size; + + // parse augmentation data + String8 aug_data = str8_substr(data, rng_1u64(cursor, cursor + cie->aug_data.size)); + cursor += cie->aug_data.size; + + // commit values to out + fde_out->format = format; + fde_out->cie_pointer = cie_pointer; + fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_range); + fde_out->insts = str8_skip(data, cursor); + + is_parsed = 1; +exit:; + return is_parsed; +} + diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index bb453c6e..d7a6fb65 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -353,6 +353,54 @@ typedef struct DW_Expr DW_ExprInst *last; } DW_Expr; +//////////////////////////////// +// .debug_frame + +typedef enum +{ + DW_DescriptorEntryType_Null, + DW_DescriptorEntryType_CIE, + DW_DescriptorEntryType_FDE +} DW_DescriptorEntryType; + +typedef struct DW_DescriptorEntry +{ + DW_DescriptorEntryType type; + DW_Format format; + Rng1U64 entry_range; +} DW_DescriptorEntry; + +typedef struct DW_UnpackedCIE +{ + String8 init_insts; + String8 aug_string; + String8 aug_data; + U64 code_align_factor; + S64 data_align_factor; + U64 ret_addr_reg; + DW_Format format; + U8 version; + U8 address_size; + U8 segment_selector_size; + Rng1U64 cfi_range; +} DW_UnpackedCIE; + +typedef struct DW_UnpackedFDE +{ + DW_Format format; + U64 cie_pointer; + Rng1U64 pc_range; + String8 insts; + Rng1U64 cfi_range; +} DW_UnpackedFDE; + +#define DW_READ_CFI_PTR(name) U64 name(String8 data, U64 off, void *ud, U64 *ptr_out) +typedef DW_READ_CFI_PTR(DW_ReadCfiPtrFunc); + +#define DW_CIE_FROM_OFFSET_FUNC(name) DW_UnpackedCIE * name(void *ud, U64 offset) +typedef DW_CIE_FROM_OFFSET_FUNC(DW_CIEFromOffsetFunc); + + // hasher internal U64 dw_hash_from_string(String8 string); @@ -470,4 +518,10 @@ internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *are internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data); +// debug frame + +internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out); +internal B32 dw_unpack_cie(String8 data, Arch arch, DW_Format format, DW_UnpackedCIE *cie_out); +internal B32 dw_unpack_fde(String8 data, DW_Format format, DW_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, DW_UnpackedFDE *fde_out); + #endif // DWARF_PARSE_H From e4f6c0fc8e89eb3d0563a982aba2aa05b1c219bf Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 7 Oct 2025 18:13:36 -0700 Subject: [PATCH 076/133] helper for querying arch bittness in byte size --- src/base/base_core.c | 6 ++++++ src/base/base_core.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/base/base_core.c b/src/base/base_core.c index 97515ce6..79655432 100644 --- a/src/base/base_core.c +++ b/src/base/base_core.c @@ -407,6 +407,12 @@ bit_size_from_arch(Arch arch) return arch_bitsize; } +internal U64 +byte_size_from_arch(Arch arch) +{ + return bit_size_from_arch(arch) / 8; +} + internal U64 max_instruction_size_from_arch(Arch arch) { diff --git a/src/base/base_core.h b/src/base/base_core.h index e9a166f2..bd67f5c6 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -959,6 +959,7 @@ internal B32 txt_rng_contains(TxtRng r, TxtPt pt); //~ rjf: Toolchain/Environment Enum Functions internal U64 bit_size_from_arch(Arch arch); +internal U64 byte_size_from_arch(Arch arch); internal U64 max_instruction_size_from_arch(Arch arch); //////////////////////////////// From 3560c7d3e747fcd588220b95a73f95ed59f0ff09 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 7 Oct 2025 18:14:37 -0700 Subject: [PATCH 077/133] dump CIE and FDE --- src/dwarf/dwarf_dump.c | 525 ++++++++++++++++++++++++----------------- src/dwarf/dwarf_dump.h | 37 +-- 2 files changed, 324 insertions(+), 238 deletions(-) diff --git a/src/dwarf/dwarf_dump.c b/src/dwarf/dwarf_dump.c index 21452a46..9ebeab09 100644 --- a/src/dwarf/dwarf_dump.c +++ b/src/dwarf/dwarf_dump.c @@ -9,13 +9,18 @@ dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off) { Temp scratch = scratch_begin(&arena, 1); String8 reg_str = dw_string_from_register(scratch.arena, arch, reg_idx); - String8 result = push_str8f(arena, "%S%+lld", reg_str, reg_off); + String8 result; + if (reg_off != 0) { + result = push_str8f(arena, "%S%+lld", reg_str, reg_off); + } else { + result = reg_str; + } scratch_end(scratch); return result; } internal String8List -dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) +dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) { Temp scratch = scratch_begin(&arena, 1); String8List result = {0}; @@ -66,7 +71,7 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 case DW_ExprOp_Addr: { U64 addr = 0; - cursor += str8_deserial_read(raw_data, cursor, &addr, address_size, 1); + cursor += str8_deserial_read(raw_data, cursor, &addr, addr_size, 1); op_value = push_str8f(scratch.arena, "%#llx", addr); } break; @@ -258,7 +263,7 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); Rng1U64 block_range = rng_1u64(cursor, cursor + block_size); String8 block_data = str8_substr(raw_data, block_range); - String8List block_expr = dw_string_list_from_expression(scratch.arena, block_data, cu_base, address_size, arch, ver, ext, format); + String8List block_expr = dw_string_list_from_expression(scratch.arena, block_data, cu_base, addr_size, arch, ver, ext, format); op_value = str8_list_join(scratch.arena, &block_expr, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(","), .post = str8_lit(" }")}); cursor += block_size; } break; @@ -315,6 +320,187 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 return result; } +internal String8 +dw_string_from_expression(Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = dw_string_list_from_expression(scratch.arena, expr, cu_base, addr_size, arch, ver, ext, format); + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=", "}); + return result; +} + +internal String8List +dw_string_list_from_cfi_program(Arena *arena, + U64 cu_base, + Arch arch, + DW_Version ver, + DW_Ext ext, + DW_Format format, + U64 pc_begin, + DW_UnpackedCIE *cie, + DW_ReadCfiPtrFunc *read_cfi_ptr_func, + void *read_cfi_ptr_ud, + String8 program) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + U64 pc = pc_begin; + for (U64 cursor = 0; cursor < program.size; ) { + DW_CFA opcode = 0; + cursor += str8_deserial_read_struct(program, cursor, &opcode); + + U64 operand = 0; + if ((opcode & DW_CFAMask_OpcodeHi) != 0) { + operand = opcode & DW_CFAMask_Operand; + opcode = opcode & DW_CFAMask_OpcodeHi; + } + + String8 operand_str = str8_lit("???"); + switch (opcode) { + case DW_CFA_Nop: { operand_str = str8_zero(); } break; + case DW_CFA_SetLoc: { + U64 address = 0; + cursor += read_cfi_ptr_func(program, cursor, read_cfi_ptr_ud, &address); + operand_str = str8f(arena, "0x%X", address); + } break; + case DW_CFA_AdvanceLoc1: { + U8 delta = 0; + cursor += str8_deserial_read_struct(program, cursor, &delta); + delta *= cie->code_align_factor; + pc += delta; + operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc); + } break; + case DW_CFA_AdvanceLoc2: { + U16 delta = 0; + cursor += str8_deserial_read_struct(program, cursor, &delta); + delta *= cie->code_align_factor; + pc += delta; + operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc); + } break; + case DW_CFA_AdvanceLoc4: { + U32 delta = 0; + cursor += str8_deserial_read_struct(program, cursor, &delta); + delta *= cie->code_align_factor; + pc += delta; + operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc); + } break; + case DW_CFA_OffsetExt: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + cursor += str8_deserial_read_uleb128(program, cursor, &offset); + operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, (S64)offset * cie->data_align_factor)); + } break; + case DW_CFA_RestoreExt: { operand_str = str8_zero(); } break; + case DW_CFA_Undefined: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + operand_str = str8f(arena, "%I64u", reg); + } break; + case DW_CFA_SameValue: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, 0)); + } break; + case DW_CFA_Register: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + cursor += str8_deserial_read_uleb128(program, cursor, &offset); + operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, (S64)offset)); + } break; + case DW_CFA_RememberState: { operand_str = str8_zero(); } break; + case DW_CFA_RestoreState: { operand_str = str8_zero(); } break; + case DW_CFA_DefCfa: { + U64 reg = 0, offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + cursor += str8_deserial_read_uleb128(program, cursor, &offset); + operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, offset)); + } break; + case DW_CFA_DefCfaRegister: { + U64 reg = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, 0)); + } break; + case DW_CFA_DefCfaOffset: { + U64 offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, &offset); + operand_str = str8f(arena, "+%I64u", offset); + } break; + case DW_CFA_DefCfaExpr: { + U64 expr_size = 0; + cursor += str8_deserial_read_uleb128(program, cursor, &expr_size); + String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size)); + String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format); + operand_str = str8f(arena, "%S", expr_str); + } break; + case DW_CFA_Expr: { + U64 reg = 0, expr_size = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + cursor += str8_deserial_read_uleb128(program, cursor, &expr_size); + String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size)); + String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, 0); + String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format); + operand_str = str8f(arena, "%S expression %S", reg_str, expr_str); + } break; + case DW_CFA_OffsetExtSf: { + U64 reg = 0; S64 offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + cursor += str8_deserial_read_sleb128(program, cursor, &offset); + String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, offset * cie->data_align_factor); + operand_str = str8f(arena, "%S", reg_str); + } break; + case DW_CFA_DefCfaSf: { + U64 reg = 0; S64 offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, ®); + cursor += str8_deserial_read_sleb128(program, cursor, &offset); + String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, offset * cie->data_align_factor); + operand_str = str8f(arena, "%S", reg_str); + } break; + case DW_CFA_ValOffset: { + U64 val = 0, offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, &val); + cursor += str8_deserial_read_uleb128(program, cursor, &offset); + operand_str = str8f(arena, "value 0x%llx, offset %+I64d", val, offset); + } break; + case DW_CFA_ValOffsetSf: { + U64 val = 0; S64 offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, &val); + cursor += str8_deserial_read_sleb128(program, cursor, &offset); + operand_str = str8f(arena, "value %llu, offset %+I64d", val, offset); + } break; + case DW_CFA_ValExpr: { + U64 val = 0; U64 expr_size = 0; + cursor += str8_deserial_read_uleb128(program, cursor, &val); + cursor += str8_deserial_read_uleb128(program, cursor, &expr_size); + String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size)); + String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format); + operand_str = str8f(arena, "value +%I64u, expression %S", val, expr_str); + } break; + case DW_CFA_AdvanceLoc: { + U64 delta = operand * cie->code_align_factor; + pc += delta; + operand_str = str8f(arena, "+%I64u; PC 0x%I64x", delta, pc); + } break; + case DW_CFA_Offset: { + U64 offset = 0; + cursor += str8_deserial_read_uleb128(program, cursor, &offset); + S64 v = (S64)offset * cie->data_align_factor; + operand_str = dw_string_from_reg_off(scratch.arena, arch, operand, v); + } break; + case DW_CFA_Restore: { + String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, operand, 0); + operand_str = str8f(arena, "%S", reg_str); + } break; + default: { NotImplemented; } break; + } + + str8_list_pushf(arena, &list, "DW_CFA_%S: %S", dw_string_from_cfa_opcode(opcode), operand_str); + } + + scratch_end(scratch); + return list; +} + internal String8 dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) { @@ -327,234 +513,43 @@ dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_bas #if 0 -internal void -dw_string_from_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) -{ - Temp scratch = scratch_begin(&arena, 1); - - U64 address_bit_size = bit_size_from_arch(arch); - U64 address_size = address_bit_size / 8; - - for (U64 cursor = 0; cursor < raw_data.size; /* empty */) { - DW_CFA opcode = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &opcode); - - U64 operand = 0; - if ((opcode & DW_CFAMask_OpcodeHi) != 0) { - operand = opcode & DW_CFAMask_Operand; - opcode = opcode & DW_CFAMask_OpcodeHi; - } - - switch (opcode) { - case DW_CFA_Nop: { - rd_printf("DW_CFA_nop"); - } break; - case DW_CFA_SetLoc: { - U64 address = 0; - switch (arch) { - case Arch_x64: cursor += dw_unwind_parse_pointer_x64(raw_data.str, rng_1u64(0,raw_data.size), ptr_ctx, cie->addr_encoding, cursor, &address); break; - - default: NotImplemented; break; - } - rd_printf("DW_CFA_set_loc: %#llx", address); - } break; - case DW_CFA_AdvanceLoc1: { - U8 delta = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &delta); - - rd_printf("DW_CFA_advance_loc1: %+u", delta * cie->code_align_factor); - } break; - case DW_CFA_AdvanceLoc2: { - U16 delta = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &delta); - - rd_printf("DW_CFA_advance_loc2: %+u", delta * cie->code_align_factor); - } break; - case DW_CFA_AdvanceLoc4: { - U32 delta = 0; - cursor += str8_deserial_read_struct(raw_data, cursor, &delta); - - rd_printf("DW_CFA_advance_loc4: %+u", delta * cie->code_align_factor); - } break; - case DW_CFA_OffsetExt: { - U64 reg_idx = 0, reg_off = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off); - - rd_printf("DW_CFA_offset_extended: %S register %llu (%S), offset %+llu", - dw_string_from_reg_off(scratch.arena, arch, reg_idx, (S64)reg_off * cie->data_align_factor)); - } break; - case DW_CFA_RestoreExt: { - rd_printf("DW_CFA_restore_extended"); - } break; - case DW_CFA_Undefined: { - U64 reg = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - - rd_printf("DW_CFA_undefined: %llu", reg); - } break; - case DW_CFA_SameValue: { - U64 reg = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - - rd_printf("DW_CFA_same_value: %S", dw_string_from_register(scratch.arena, arch, reg)); - } break; - case DW_CFA_Register: { - U64 reg_idx = 0, reg_off = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off); - - rd_printf("DW_CFA_register: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off)); - } break; - case DW_CFA_RememberState: { - rd_printf("DW_CFA_remember_state"); - } break; - case DW_CFA_RestoreState: { - rd_printf("DW_CFA_restore_state"); - } break; - case DW_CFA_DefCfa: { - U64 reg_idx = 0, reg_off = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off); - - rd_printf("DW_CFA_def_cfa: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off)); - } break; - case DW_CFA_DefCfaRegister: { - U64 reg = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - - rd_printf("DW_CFA_register: %llu (%S)", - reg, - dw_string_from_register(arena, arch, reg)); - } break; - case DW_CFA_DefCfaOffset: { - U64 offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); - - rd_printf("DW_CFA_def_cfa_offset: %llu", offset); - } break; - case DW_CFA_DefCfaExpr: { - U64 block_size = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); - String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); - cursor += block_size; - - rd_printf("DW_CFA_def_cfa_expression: %S", - dw_single_line_string_from_expression(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format)); - } break; - case DW_CFA_Expr: { - U64 reg = 0, block_size = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); - String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); - cursor += block_size; - - rd_printf("DW_CFA_expression: %S, expression %S", - dw_string_from_register(scratch.arena, arch, reg), - dw_single_line_string_from_expression(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format)); - } break; - case DW_CFA_OffsetExtSf: { - U64 reg_idx = 0; - S64 reg_off = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); - cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); - - rd_printf("DW_CFA_offset_ext_sf: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off * cie->data_align_factor)); - } break; - case DW_CFA_DefCfaSf: { - U64 reg_idx = 0; - S64 reg_off = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); - cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); - - rd_printf("DW_CFA_def_cfa_sf: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off * cie->data_align_factor)); - } break; - case DW_CFA_ValOffset: { - U64 val = 0, offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); - cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); - - rd_printf("DW_CFA_val_offset: value %llu, offset %+llu", val, offset); - } break; - case DW_CFA_ValOffsetSf: { - U64 val = 0; - S64 offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); - cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); - - rd_printf("DW_CFA_val_offset_sf: value %llu, offset %+lld", val, offset); - } break; - case DW_CFA_ValExpr: { - U64 val = 0; - U64 block_size = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &val); - cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); - String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); - cursor += block_size; - - rd_printf("DW_CFA_val_expr: value %+llu, expression %S", - val, - dw_single_line_string_from_expression(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format)); - } break; - case DW_CFA_AdvanceLoc: { - rd_printf("DW_CFA_advance_loc: %+llu", operand); - } break; - case DW_CFA_Offset: { - U64 offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); - S64 v = (S64)offset * cie->data_align_factor; - - rd_printf("DW_CFA_offset: %S", dw_string_from_reg_off(scratch.arena, arch, operand, v)); - } break; - case DW_CFA_Restore: { - rd_printf("DW_CFA_restore: %S", operand, dw_string_from_register(scratch.arena, arch, operand)); - } break; - default: { - rd_errorf("unknown CFI opcode %u", opcode); - } break; - } - } - - scratch_end(scratch); -} - internal String8 -dw_string_from_eh_ptr_enc(Arena *arena, DW_EhPtrEnc enc) +dw_string_from_eh_ptr_enc(Arena *arena, EH_PtrEnc enc) { - U8 type = enc & DW_EhPtrEnc_TypeMask; + U8 type = enc & EH_PtrEnc_TypeMask; String8 type_str = str8_lit("NULL"); switch (type) { - case DW_EhPtrEnc_Ptr: type_str = str8_lit("PTR"); break; - case DW_EhPtrEnc_ULEB128: type_str = str8_lit("ULEB128"); break; - case DW_EhPtrEnc_UData2: type_str = str8_lit("UDATA2"); break; - case DW_EhPtrEnc_UData4: type_str = str8_lit("UDATA4"); break; - case DW_EhPtrEnc_UData8: type_str = str8_lit("UDATA8"); break; - case DW_EhPtrEnc_Signed: type_str = str8_lit("SIGNED"); break; - case DW_EhPtrEnc_SLEB128: type_str = str8_lit("SLEB128"); break; - case DW_EhPtrEnc_SData2: type_str = str8_lit("SDATA2"); break; - case DW_EhPtrEnc_SData4: type_str = str8_lit("SDATA4"); break; - case DW_EhPtrEnc_SData8: type_str = str8_lit("SDATA8"); break; + case EH_PtrEnc_Ptr: type_str = str8_lit("PTR"); break; + case EH_PtrEnc_ULEB128: type_str = str8_lit("ULEB128"); break; + case EH_PtrEnc_UData2: type_str = str8_lit("UDATA2"); break; + case EH_PtrEnc_UData4: type_str = str8_lit("UDATA4"); break; + case EH_PtrEnc_UData8: type_str = str8_lit("UDATA8"); break; + case EH_PtrEnc_Signed: type_str = str8_lit("SIGNED"); break; + case EH_PtrEnc_SLEB128: type_str = str8_lit("SLEB128"); break; + case EH_PtrEnc_SData2: type_str = str8_lit("SDATA2"); break; + case EH_PtrEnc_SData4: type_str = str8_lit("SDATA4"); break; + case EH_PtrEnc_SData8: type_str = str8_lit("SDATA8"); break; } - U8 modifier = enc & DW_EhPtrEnc_ModifyMask; + U8 modifier = enc & EH_PtrEnc_ModifyMask; String8 modifier_str = str8_lit("NULL"); switch (modifier) { - case DW_EhPtrEnc_PcRel: modifier_str = str8_lit("PCREL"); break; - case DW_EhPtrEnc_TextRel: modifier_str = str8_lit("TEXTREL"); break; - case DW_EhPtrEnc_DataRel: modifier_str = str8_lit("DATAREL"); break; - case DW_EhPtrEnc_FuncRel: modifier_str = str8_lit("FUNCREL"); break; + case EH_PtrEnc_PcRel: modifier_str = str8_lit("PCREL"); break; + case EH_PtrEnc_TextRel: modifier_str = str8_lit("TEXTREL"); break; + case EH_PtrEnc_DataRel: modifier_str = str8_lit("DATAREL"); break; + case EH_PtrEnc_FuncRel: modifier_str = str8_lit("FUNCREL"); break; } String8 indir_str = str8_lit(""); - if (enc & DW_EhPtrEnc_Indirect) { + if (enc & EH_PtrEnc_Indirect) { indir_str = str8_lit("(INDIRECT)"); } return push_str8f(arena, "Type: %S, Modifier: %S %S", type_str, modifier_str, indir_str); } internal void -dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx) +dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx) { Temp scratch = scratch_begin(&arena, 1); - DW_CIEUnpacked cie = {0}; + DW_UnpackedCIE cie = {0}; for (U64 cursor = 0; cursor < raw_eh_frame.size; ) { U64 header_offset = cursor; @@ -572,7 +567,7 @@ dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh U32 entry_id = 0; // always 4-bytes, even when length is encoded as 64-bit integer cursor += str8_deserial_read_struct(raw_eh_frame, cursor, &entry_id); - // TODO: fix the freaking DW_EhPtrEnc_PCREL encoding. + // TODO: fix the freaking EH_PtrEnc_PCREL encoding. // it assumes "frame_base" points to the first byte of .eh_frame // but here base is start of ELF and we use range to select .eh_frame // bytes to read, which breaks parsing. @@ -597,7 +592,7 @@ dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh } // FDE else { - DW_FDEUnpacked fde = {0}; + DW_UnpackedFDE fde = {0}; dw_unwind_parse_fde_x64(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), ptr_ctx, &cie, 0, &fde); cfi_range = fde.cfi_range; @@ -1686,8 +1681,17 @@ dw_string_from_attrib_value(Arena *arena, DW_Input *input, Arch arch, DW_CompUni return result; } +internal +DW_CIE_FROM_OFFSET_FUNC(dwarf_dump_cie_from_offset) +{ + return hash_table_search_u64_raw(ud, offset); +} + internal String8List -dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubsetFlags subset_flags) +dw_dump_list_from_sections(Arena *arena, + DW_Input *input, + Arch arch, + DW_DumpSubsetFlags subset_flags) { String8List strings = {0}; String8 indent = str8_lit(" "); @@ -1715,8 +1719,7 @@ dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubs //- rjf: dump .debug_info // DumpSubset(DebugInfo) - { - Rng1U64List unit_ranges_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data); + { Rng1U64List unit_ranges_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data); Rng1U64Array unit_ranges = rng1u64_array_from_list(scratch.arena, &unit_ranges_list); for EachIndex(unit_idx, unit_ranges.count) { @@ -2147,6 +2150,88 @@ dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubs dumpf(" { 0x%08I64x %llu \"%S\" }\n", cursor, string.size, string); } } + + ////////////////////////////// + //~ dump .debug_frame + DumpSubset(DebugFrame) + { + HashTable *cie_ht = hash_table_init(scratch.arena, 0x2000); + String8 debug_frame = input->sec[DW_Section_Frame].data; + U64 addr_size = byte_size_from_arch(arch); + + // make offset -> CIE hash table + for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) { + DW_DescriptorEntry desc = {0}; + desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc); + if (desc.type == DW_DescriptorEntryType_CIE) { + String8 raw_cie = str8_substr(debug_frame, desc.entry_range); + U64 restore_pos = arena_pos(scratch.arena); + DW_UnpackedCIE *cie = push_array(scratch.arena, DW_UnpackedCIE, 1); + if (dw_unpack_cie(raw_cie, desc.format, arch, cie)) { + hash_table_push_u64_raw(scratch.arena, cie_ht, cursor, cie); + } else { + arena_pop_to(arena, restore_pos); + } + } + } + + for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) { + DW_DescriptorEntry desc = {0}; + desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc); + String8 raw_desc = str8_substr(debug_frame, desc.entry_range); + switch (desc.type) { + case DW_DescriptorEntryType_Null: {} break; + case DW_DescriptorEntryType_CIE: { + DW_UnpackedCIE cie = {0}; + if (dw_unpack_cie(raw_desc, desc.format, arch, &cie)) { + String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, cie.format, 0, &cie, dw_read_cfi_ptr, &cie, cie.init_insts); + + dumpf("CIE: // entry range: %r\n", desc.entry_range); + dumpf("{\n"); + dumpf(" Format: %S\n", dw_string_from_format(desc.format)); + dumpf(" Version: %u\n", cie.version); + dumpf(" Aug string: %S\n", cie.aug_string.size ? cie.aug_string : str8_lit("None")); + dumpf(" Code align: %I64u\n", cie.code_align_factor); + dumpf(" Data align: %I64d\n", cie.data_align_factor); + dumpf(" Return addr reg: %S\n", dw_string_from_register(scratch.arena, arch, cie.ret_addr_reg)); + if (cie.version > DW_Version_3) { + dumpf(" Address size: %u\n", cie.address_size); + dumpf(" Segment selector size: %u\n", cie.segment_selector_size); + } + dumpf(" Initial Insturction:\n"); + dumpf(" {\n"); + for EachNode(n, String8Node, init_insts_str_list.first) { dumpf(" %S\n", n->string); } + dumpf(" }\n"); + dumpf("}\n"); + } else { + dumpf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min); + } + } break; + case DW_DescriptorEntryType_FDE: { + DW_UnpackedFDE fde = {0}; + if (dw_unpack_fde(raw_desc, desc.format, dwarf_dump_cie_from_offset, cie_ht, &fde)) { + DW_UnpackedCIE *cie = hash_table_search_u64_raw(cie_ht, fde.cie_pointer); + String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, fde.format, fde.pc_range.min, cie, dw_read_cfi_ptr, cie, fde.insts); + + dumpf("FDE: // entry range: %r\n", desc.entry_range, dw_string_from_format(fde.format), fde.cie_pointer, fde.pc_range); + dumpf("{\n"); + { + dumpf(" Format: %S\n", dw_string_from_format(fde.format)); + dumpf(" CIE pointer: 0x%I64x\n", fde.cie_pointer); + dumpf(" PC range: %r\n", fde.pc_range); + dumpf(" Instructions:\n"); + dumpf(" {\n"); + for EachNode(n, String8Node, insts_str_list.first) { dumpf(" %S\n", n->string); } + dumpf(" }\n"); + } + dumpf("}\n"); + } else { + dumpf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min); + } + } break; + } + } + } ////////////////////////////// //- rjf: dump .debug_loc diff --git a/src/dwarf/dwarf_dump.h b/src/dwarf/dwarf_dump.h index 257dd09b..9e673a71 100644 --- a/src/dwarf/dwarf_dump.h +++ b/src/dwarf/dwarf_dump.h @@ -7,21 +7,22 @@ //////////////////////////////// //~ rjf: Dump Subset Types -#define DW_DumpSubset_XList \ -X(DebugInfo, debug_info, "DEBUG INFO")\ -X(DebugAbbrev, debug_abbrev, "DEBUG ABBREV")\ -X(DebugLine, debug_line, "DEBUG LINE")\ -X(DebugStr, debug_str, "DEBUG STR")\ -X(DebugLoc, debug_loc, "DEBUG LOC")\ -X(DebugRanges, debug_ranges, "DEBUG RANGES")\ -X(DebugARanges, debug_aranges, "DEBUG ARANGES")\ -X(DebugAddr, debug_addr, "DEBUG ADDR")\ -X(DebugLocLists, debug_loclists, "DEBUG LOCLISTS")\ -X(DebugRngLists, debug_rnglists, "DEBUG RNGLISTS")\ -X(DebugPubNames, debug_pubnames, "DEBUG PUBNAMES")\ -X(DebugPubTypes, debug_pubtypes, "DEBUG PUBTYPES")\ -X(DebugLineStr, debug_linestr, "DEBUG LINESTR")\ -X(DebugStrOffsets, debug_stroff, "DEBUG STROFF")\ +#define DW_DumpSubset_XList \ +X(DebugInfo, debug_info, "DEBUG INFO") \ +X(DebugAbbrev, debug_abbrev, "DEBUG ABBREV") \ +X(DebugLine, debug_line, "DEBUG LINE") \ +X(DebugStr, debug_str, "DEBUG STR") \ +X(DebugLoc, debug_loc, "DEBUG LOC") \ +X(DebugRanges, debug_ranges, "DEBUG RANGES") \ +X(DebugARanges, debug_aranges, "DEBUG ARANGES") \ +X(DebugAddr, debug_addr, "DEBUG ADDR") \ +X(DebugLocLists, debug_loclists, "DEBUG LOCLISTS") \ +X(DebugRngLists, debug_rnglists, "DEBUG RNGLISTS") \ +X(DebugPubNames, debug_pubnames, "DEBUG PUBNAMES") \ +X(DebugPubTypes, debug_pubtypes, "DEBUG PUBTYPES") \ +X(DebugLineStr, debug_linestr, "DEBUG LINESTR") \ +X(DebugStrOffsets, debug_stroff, "DEBUG STROFF") \ +X(DebugFrame, debug_frame, "DEBUG FRAME") \ typedef enum DW_DumpSubset { @@ -60,12 +61,12 @@ read_only global String8 dw_name_title_from_dump_subset_table[] = internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off); internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); internal String8 dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); -internal String8 dw_string_from_eh_ptr_enc (Arena *arena, DW_EhPtrEnc enc); +internal String8 dw_string_from_eh_ptr_enc (Arena *arena, EH_PtrEnc enc); #if 0 -internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); +internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_UnpackedCIE *cie, EH_PtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); -internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx); +internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx); internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Input *input); From 401d7b47df6c6002535373322b09b3ce0719343f Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 7 Oct 2025 20:28:06 -0700 Subject: [PATCH 078/133] factor out C++ ABI exception handling --- src/dwarf/dwarf_unwind.c | 251 ++++++++++++--------------------------- src/dwarf/dwarf_unwind.h | 93 ++------------- src/eh/eh_frame.c | 130 ++++++++++++++++++++ src/eh/eh_frame.h | 74 ++++++++++++ src/radbin/radbin_main.c | 2 + src/raddbg/raddbg_main.c | 2 + 6 files changed, 297 insertions(+), 255 deletions(-) create mode 100644 src/eh/eh_frame.c create mode 100644 src/eh/eh_frame.h diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index e3540442..168fd52e 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -55,7 +55,7 @@ dw_unwind_x64(String8 raw_text, //- find cfi records DW_CFIRecords cfi_recs = {0}; if (has_needed_sections) { - DW_EhPtrCtx ptr_ctx = {0}; + EH_PtrCtx ptr_ctx = {0}; ptr_ctx.raw_base_vaddr = frame_base_voff; ptr_ctx.text_vaddr = text_base_vaddr; ptr_ctx.data_vaddr = data_base_vaddr; @@ -75,11 +75,11 @@ dw_unwind_x64(String8 raw_text, //- cfi machine setup DW_CFIMachine machine = {0}; if (cfi_recs.valid) { - DW_EhPtrCtx ptr_ctx = {0}; + EH_PtrCtx ptr_ctx = {0}; ptr_ctx.raw_base_vaddr = frame_base_voff; ptr_ctx.text_vaddr = text_base_vaddr; ptr_ctx.data_vaddr = data_base_vaddr; - ptr_ctx.func_vaddr = cfi_recs.fde.ip_voff_range.min + rebase_voff_to_vaddr; // TODO: it's not super clear how to set up this member, need more test cases + ptr_ctx.func_vaddr = cfi_recs.fde.pc_range.min + rebase_voff_to_vaddr; // TODO: it's not super clear how to set up this member, need more test cases machine = dw_unwind_make_machine_x64(DW_UNWIND_X64__REG_SLOT_COUNT, &cfi_recs.cie, &ptr_ctx); } @@ -101,7 +101,7 @@ dw_unwind_x64(String8 raw_text, if (init_row != 0) { // upgrade machine with new equipment dw_unwind_machine_equip_initial_row_x64(&machine, init_row); - dw_unwind_machine_equip_fde_ip_x64(&machine, cfi_recs.fde.ip_voff_range.min); + dw_unwind_machine_equip_fde_ip_x64(&machine, cfi_recs.fde.pc_range.min); // decode main row Rng1U64 main_cfi_range = cfi_recs.fde.cfi_range; @@ -320,100 +320,10 @@ dw_unwind_init_x64(void) } } -internal U64 -dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx *ptr_ctx, DW_EhPtrEnc encoding, U64 off, U64 *ptr_out) -{ - // aligned offset - U64 pointer_off = off; - if (encoding == DW_EhPtrEnc_Aligned) { - pointer_off = AlignPow2(off, 8); // TODO: align to 4 bytes when we parse x86 ELF binary - encoding = DW_EhPtrEnc_Ptr; - } - - // decode pointer value - U64 size_param = 0; - U64 after_pointer_off = 0; - U64 raw_pointer = 0; - switch (encoding & DW_EhPtrEnc_TypeMask) { - default:break; - - case DW_EhPtrEnc_Ptr : size_param = 8; goto ufixed; - case DW_EhPtrEnc_UData2: size_param = 2; goto ufixed; - case DW_EhPtrEnc_UData4: size_param = 4; goto ufixed; - case DW_EhPtrEnc_UData8: size_param = 8; goto ufixed; - ufixed: - { - dw_based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); - after_pointer_off = pointer_off + size_param; - } break; - - // TODO: Signed is actually just a flag that indicates this int is negavite. - // There shouldn't be a read for Signed. - // For instance, (DW_EhPtrEnc_UData2 | DW_EhPtrEnc_Signed) == DW_EhPtrEnc_SData etc. - case DW_EhPtrEnc_Signed:size_param = 8; goto sfixed; - - case DW_EhPtrEnc_SData2:size_param = 2; goto sfixed; - case DW_EhPtrEnc_SData4:size_param = 4; goto sfixed; - case DW_EhPtrEnc_SData8:size_param = 8; goto sfixed; - sfixed: - { - dw_based_range_read(frame_base, frame_range, pointer_off, size_param, &raw_pointer); - after_pointer_off = pointer_off + size_param; - // sign extension - U64 sign_bit = size_param*8 - 1; - if ((raw_pointer >> sign_bit) != 0) { - raw_pointer |= (~(1 << sign_bit)) + 1; - } - } break; - - case DW_EhPtrEnc_ULEB128: - { - U64 size = dw_based_range_read_uleb128(frame_base, frame_range, pointer_off, &raw_pointer); - after_pointer_off = pointer_off + size; - } break; - - case DW_EhPtrEnc_SLEB128: - { - U64 size = dw_based_range_read_sleb128(frame_base, frame_range, pointer_off, - (S64*)&raw_pointer); - after_pointer_off = pointer_off + size; - } break; - } - - // apply relative bases - U64 pointer = raw_pointer; - if (pointer != 0) { - switch (encoding & DW_EhPtrEnc_ModifyMask) { - case DW_EhPtrEnc_PcRel: - { - pointer = ptr_ctx->raw_base_vaddr + frame_range.min + off + raw_pointer; - } break; - case DW_EhPtrEnc_TextRel: - { - pointer = ptr_ctx->text_vaddr + raw_pointer; - } break; - case DW_EhPtrEnc_DataRel: - { - pointer = ptr_ctx->data_vaddr + raw_pointer; - } break; - case DW_EhPtrEnc_FuncRel: - { - Assert(!"TODO: need a sample to verify implementation"); - pointer = ptr_ctx->func_vaddr + raw_pointer; - } break; - } - } - - // return - *ptr_out = pointer; - U64 result = after_pointer_off - off; - return(result); -} - //- eh_frame parsing internal void -dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off, DW_CIEUnpacked *cie_out) +dw_unwind_parse_cie_x64(void *base, Rng1U64 range, EH_PtrCtx *ptr_ctx, U64 off, DW_UnpackedCIE *cie_out) { NotImplemented; #if 0 @@ -474,9 +384,9 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off U64 aug_data_off = after_aug_size_off; U64 after_aug_data_off = after_aug_size_off; - DW_EhPtrEnc lsda_encoding = DW_EhPtrEnc_Omit; + EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit; U64 handler_ip = 0; - DW_EhPtrEnc addr_encoding = DW_EhPtrEnc_UData8; + EH_PtrEnc addr_encoding = EH_PtrEnc_UData8; if (has_augmentation_size > 0) { U64 aug_data_cursor = aug_data_off; @@ -487,7 +397,7 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off aug_data_cursor += sizeof(lsda_encoding); } break; case 'P': { - DW_EhPtrEnc handler_encoding = DW_EhPtrEnc_Omit; + EH_PtrEnc handler_encoding = EH_PtrEnc_Omit; dw_based_range_read_struct(base, range, aug_data_cursor, &handler_encoding); U64 ptr_off = aug_data_cursor + sizeof(handler_encoding); @@ -516,6 +426,7 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off // commit values to out cie_out->version = version; + cie_out->lsda_encoding = lsda_encoding; cie_out->addr_encoding = addr_encoding; cie_out->has_augmentation_size = has_augmentation_size; @@ -531,68 +442,15 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off #endif } -internal void -dw_unwind_parse_fde_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, DW_CIEUnpacked *cie, U64 off, DW_FDEUnpacked *fde_out) -{ - // pull out pointer encoding field - DW_EhPtrEnc ptr_enc = cie->addr_encoding; - - // ip first - U64 ip_first_off = off; - U64 ip_first = 0; - U64 ip_first_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, ptr_enc, ip_first_off, &ip_first); - - // ip range size - U64 ip_range_size_off = ip_first_off + ip_first_size; - U64 ip_range_size = 0; - U64 ip_range_size_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, ptr_enc & DW_EhPtrEnc_TypeMask, ip_range_size_off, &ip_range_size); - - // augmentation data - U64 aug_data_off = ip_range_size_off + ip_range_size_size; - U64 after_aug_data_off = aug_data_off; - U64 lsda_ip = 0; - - if (cie->has_augmentation_size) { - // augmentation size - U64 augmentation_size = 0; - U64 aug_size_size = dw_based_range_read_uleb128(base, range, aug_data_off, &augmentation_size); - U64 after_aug_size_off = aug_data_off + aug_size_size; - - // extract lsda (only thing that can actually be in FDE's augmentation data as far as we know) - DW_EhPtrEnc lsda_encoding = cie->lsda_encoding; - if (lsda_encoding != DW_EhPtrEnc_Omit) { - U64 lsda_off = after_aug_size_off; - dw_unwind_parse_pointer_x64(base, range, ptr_ctx, lsda_encoding, lsda_off, &lsda_ip); - } - - // set offset at end of augmentation data - after_aug_data_off = after_aug_size_off + augmentation_size; - } - - // cfi range - U64 cfi_off = range.min + after_aug_data_off; - U64 cfi_size = 0; - if (range.max > cfi_off) { - cfi_size = range.max - cfi_off; - } - - // commit values to out - fde_out->ip_voff_range.min = ip_first; - fde_out->ip_voff_range.max = ip_first + ip_range_size; - fde_out->lsda_ip = lsda_ip; - fde_out->cfi_range.min = cfi_off; - fde_out->cfi_range.max = cfi_off + cfi_size; -} - internal DW_CFIRecords -dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_ctx, U64 ip_voff) +dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, EH_PtrCtx *ptr_ctx, U64 ip_voff) { Temp scratch = scratch_begin(0, 0); DW_CFIRecords result = {0}; - DW_CIEUnpackedNode *cie_first = 0; - DW_CIEUnpackedNode *cie_last = 0; + DW_UnpackedCIENode *cie_first = 0; + DW_UnpackedCIENode *cie_last = 0; U64 cursor = 0; for (;;) { @@ -632,10 +490,10 @@ dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_c // CIE if (discrim == 0) { - DW_CIEUnpacked cie = {0}; + DW_UnpackedCIE cie = {0}; dw_unwind_parse_cie_x64(raw_rec.str, rng_1u64(0, raw_rec.size), ptr_ctx, after_discrim_off, &cie); if (cie.version != 0) { - DW_CIEUnpackedNode *node = push_array(scratch.arena, DW_CIEUnpackedNode, 1); + DW_UnpackedCIENode *node = push_array(scratch.arena, DW_UnpackedCIENode, 1); node->cie = cie; node->offset = rec_off; SLLQueuePush(cie_first, cie_last, node); @@ -647,8 +505,8 @@ dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_c U64 cie_offset = rec_range.min + discrim_off - discrim; // get cie node - DW_CIEUnpackedNode *cie_node = 0; - for (DW_CIEUnpackedNode *node = cie_first; node != 0; node = node->next) { + DW_UnpackedCIENode *cie_node = 0; + for (DW_UnpackedCIENode *node = cie_first; node != 0; node = node->next) { if (node->offset == cie_offset) { cie_node = node; break; @@ -656,12 +514,13 @@ dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_c } // parse fde - DW_FDEUnpacked fde = {0}; + DW_UnpackedFDE fde = {0}; if (cie_node != 0) { - dw_unwind_parse_fde_x64(raw_rec.str, rng_1u64(0,raw_rec.size), ptr_ctx, &cie_node->cie, after_discrim_off, &fde); + NotImplemented; + //dw_unwind_parse_fde_x64(raw_rec.str, rng_1u64(0,raw_rec.size), ptr_ctx, &cie_node->cie, after_discrim_off, &fde); } - if (contains_1u64(fde.ip_voff_range, ip_voff)) { + if (contains_1u64(fde.pc_range, ip_voff)) { result.valid = 1; result.cie = cie_node->cie; result.fde = fde; @@ -679,7 +538,7 @@ dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_c } internal U64 -dw_search_eh_frame_hdr_linear_x64(String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx, U64 location) +dw_search_eh_frame_hdr_linear_x64(String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 location) { // Table contains only addresses for first instruction in a function and we cannot // guarantee that result is FDE that corresponds to the input location. @@ -695,7 +554,7 @@ dw_search_eh_frame_hdr_linear_x64(String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx if (version == 1) { #if 0 - DW_EhPtrCtx ptr_ctx = {0}; + EH_PtrCtx ptr_ctx = {0}; // Set this to base address of .eh_frame_hdr. Entries are relative // to this section for some reason. ptr_ctx.data_vaddr = range.min; @@ -704,7 +563,7 @@ dw_search_eh_frame_hdr_linear_x64(String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx ptr_ctx.text_vaddr = 0; #endif - DW_EhPtrEnc eh_frame_ptr_enc = 0, fde_count_enc = 0, table_enc = 0; + EH_PtrEnc eh_frame_ptr_enc = 0, fde_count_enc = 0, table_enc = 0; cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &eh_frame_ptr_enc); cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &fde_count_enc); cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &table_enc); @@ -733,7 +592,7 @@ dw_search_eh_frame_hdr_linear_x64(String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx } internal DW_CFIRecords -dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx, U64 ip_voff) +dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 ip_voff) { DW_CFIRecords result = {0}; @@ -771,15 +630,16 @@ dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_fra Rng1U64 fde_range = rng_1u64(0, fde_read_offset + (fde_size - sizeof(fde_discrim))); // parse CIE - DW_CIEUnpacked cie = {0}; + DW_UnpackedCIE cie = {0}; dw_unwind_parse_cie_x64(raw_eh_frame.str, cie_range, ptr_ctx, cie_read_offset, &cie); // parse FDE - DW_FDEUnpacked fde = {0}; - dw_unwind_parse_fde_x64(raw_eh_frame.str, fde_range, ptr_ctx, &cie, fde_read_offset, &fde); + DW_UnpackedFDE fde = {0}; + NotImplemented; + //dw_unwind_parse_fde_x64(raw_eh_frame.str, fde_range, ptr_ctx, &cie, fde_read_offset, &fde); // range check instruction pointer - if (contains_1u64(fde.ip_voff_range, ip_voff)) { + if (contains_1u64(fde.pc_range, ip_voff)) { result.valid = 1; result.cie = cie; result.fde = fde; @@ -793,7 +653,7 @@ dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_fra //- cfi machine internal DW_CFIMachine -dw_unwind_make_machine_x64(U64 cells_per_row, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx) +dw_unwind_make_machine_x64(U64 cells_per_row, DW_UnpackedCIE *cie, EH_PtrCtx *ptr_ctx) { DW_CFIMachine result = {0}; result.cells_per_row = cells_per_row; @@ -843,8 +703,8 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin B32 result = 0; // pull out machine's equipment - DW_CIEUnpacked *cie = machine->cie; - DW_EhPtrCtx *ptr_ctx = machine->ptr_ctx; + DW_UnpackedCIE *cie = machine->cie; + EH_PtrCtx *ptr_ctx = machine->ptr_ctx; U64 cells_per_row = machine->cells_per_row; DW_CFIRow *initial_row = machine->initial_row; @@ -910,7 +770,9 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin } } break; case DW_CFADecode_Address: { - o_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, cie->addr_encoding, decode_cursor, out); + // TODO: + NotImplemented; + //o_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, cie->addr_encoding, decode_cursor, out); } break; case DW_CFADecode_ULEB128: { o_size = dw_based_range_read_uleb128(base, range, decode_cursor, out); @@ -1163,3 +1025,46 @@ dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machin return result; } +//////////////////////////////// + +internal String8 +dw_string_from_eh_ptr_enc_type(EH_PtrEnc type) +{ + switch (type) { + case EH_PtrEnc_Ptr: return str8_lit("Ptr"); + case EH_PtrEnc_ULEB128: return str8_lit("ULEB128"); + case EH_PtrEnc_UData2: return str8_lit("UData2"); + case EH_PtrEnc_UData4: return str8_lit("UData4"); + case EH_PtrEnc_UData8: return str8_lit("UData8"); + case EH_PtrEnc_Signed: return str8_lit("Signed"); + case EH_PtrEnc_SLEB128: return str8_lit("SLEB128"); + case EH_PtrEnc_SData2: return str8_lit("SData2"); + case EH_PtrEnc_SData4: return str8_lit("SData4"); + case EH_PtrEnc_SData8: return str8_lit("SData8"); + } + return str8_zero(); +} + +internal String8 +dw_string_from_eh_ptr_enc_modifier(EH_PtrEnc modifier) +{ + switch (modifier) { + case EH_PtrEnc_PcRel: return str8_lit("PcRel"); + case EH_PtrEnc_TextRel: return str8_lit("TextRel"); + case EH_PtrEnc_DataRel: return str8_lit("DataRel"); + case EH_PtrEnc_FuncRel: return str8_lit("FuncRel"); + case EH_PtrEnc_Aligned: return str8_lit("Aligned"); + } + return str8_zero(); +} + +internal String8 +dw_string_from_eh_ptr_enc(Arena *arena, EH_PtrEnc enc) +{ + String8 type_str = dw_string_from_eh_ptr_enc_type(enc & EH_PtrEnc_TypeMask); + String8 modifer_str = dw_string_from_eh_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask); + String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero(); + String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str); + return result; +} + diff --git a/src/dwarf/dwarf_unwind.h b/src/dwarf/dwarf_unwind.h index f2e6d2c1..54f7f187 100644 --- a/src/dwarf/dwarf_unwind.h +++ b/src/dwarf/dwarf_unwind.h @@ -14,87 +14,19 @@ typedef struct DW_UnwindResult // EH: Exception Frames -typedef U8 DW_EhPtrEnc; -enum +typedef struct DW_UnpackedCIENode { - DW_EhPtrEnc_TypeMask = 0x0F, - DW_EhPtrEnc_Ptr = 0x00, // Pointer sized unsigned value - DW_EhPtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value - DW_EhPtrEnc_UData2 = 0x02, // Unsigned 16-bit value - DW_EhPtrEnc_UData4 = 0x03, // Unsigned 32-bit value - DW_EhPtrEnc_UData8 = 0x04, // Unsigned 64-bit value - DW_EhPtrEnc_Signed = 0x08, // Signed pointer - DW_EhPtrEnc_SLEB128 = 0x09, // Signed LE base-128 value - DW_EhPtrEnc_SData2 = 0x0A, // Signed 16-bit value - DW_EhPtrEnc_SData4 = 0x0B, // Signed 32-bit value - DW_EhPtrEnc_SData8 = 0x0C, // Signed 64-bit value -}; - -enum -{ - DW_EhPtrEnc_ModifyMask = 0x70, - DW_EhPtrEnc_PcRel = 0x10, // Value is relative to the current program counter. - DW_EhPtrEnc_TextRel = 0x20, // Value is relative to the .text section. - DW_EhPtrEnc_DataRel = 0x30, // Value is relative to the .got or .eh_frame_hdr section. - DW_EhPtrEnc_FuncRel = 0x40, // Value is relative to the function. - DW_EhPtrEnc_Aligned = 0x50, // Value is aligned to an address unit sized boundary. -}; - -enum -{ - DW_EhPtrEnc_Indirect = 0x80, // This flag indicates that value is stored in virtual memory. - DW_EhPtrEnc_Omit = 0xFF, -}; - -typedef struct DW_EhPtrCtx -{ - U64 raw_base_vaddr; // address where pointer is being read - U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64) - U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64) - U64 func_vaddr; // base address of function where IP is located -} DW_EhPtrCtx; - -// CIE: Common Information Entry -typedef struct DW_CIEUnpacked -{ - U8 version; - DW_EhPtrEnc lsda_encoding; - DW_EhPtrEnc addr_encoding; - - B32 has_augmentation_size; - U64 augmentation_size; - String8 augmentation; - - U64 code_align_factor; - S64 data_align_factor; - U64 ret_addr_reg; - - U64 handler_ip; - - Rng1U64 cfi_range; -} DW_CIEUnpacked; - -typedef struct DW_CIEUnpackedNode -{ - struct DW_CIEUnpackedNode *next; - DW_CIEUnpacked cie; + struct DW_UnpackedCIENode *next; + DW_UnpackedCIE cie; U64 offset; -} DW_CIEUnpackedNode; - -// FDE: Frame Description Entry -typedef struct DW_FDEUnpacked -{ - Rng1U64 ip_voff_range; - U64 lsda_ip; - Rng1U64 cfi_range; -} DW_FDEUnpacked; +} DW_UnpackedCIENode; // CFI: Call Frame Information typedef struct DW_CFIRecords { B32 valid; - DW_CIEUnpacked cie; - DW_FDEUnpacked fde; + DW_UnpackedCIE cie; + DW_UnpackedFDE fde; } DW_CFIRecords; typedef enum DW_CFICFARule{ @@ -144,10 +76,10 @@ typedef struct DW_CFIRow typedef struct DW_CFIMachine { U64 cells_per_row; - DW_CIEUnpacked *cie; - DW_EhPtrCtx *ptr_ctx; + DW_UnpackedCIE *cie; DW_CFIRow *initial_row; U64 fde_ip; + EH_PtrCtx *ptr_ctx; } DW_CFIMachine; typedef U8 DW_CFADecode; @@ -200,17 +132,14 @@ internal DW_UnwindResult dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, // x64 Unwind Helper Functions internal void dw_unwind_init_x64(void); -internal U64 dw_unwind_parse_pointer_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, DW_EhPtrEnc ptr_enc, U64 off, U64 *ptr_out); //- eh_frame parsing -internal void dw_unwind_parse_cie_x64(void *base,Rng1U64 range,DW_EhPtrCtx *ptr_ctx, U64 off, DW_CIEUnpacked *cie_out); -internal void dw_unwind_parse_fde_x64(void *base,Rng1U64 range,DW_EhPtrCtx *ptr_ctx, DW_CIEUnpacked *parent_cie, U64 off, DW_FDEUnpacked *fde_out); -internal DW_CFIRecords dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_ctx, U64 ip_voff); -internal DW_CFIRecords dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx, U64 ip_voff); +internal DW_CFIRecords dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, EH_PtrCtx *ptr_ctx, U64 ip_voff); +internal DW_CFIRecords dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 ip_voff); //- cfi machine -internal DW_CFIMachine dw_unwind_make_machine_x64(U64 cells_per_row, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx); +internal DW_CFIMachine dw_unwind_make_machine_x64(U64 cells_per_row, DW_UnpackedCIE *cie, EH_PtrCtx *ptr_ctx); internal void dw_unwind_machine_equip_initial_row_x64(DW_CFIMachine *machine, DW_CFIRow *initial_row); internal void dw_unwind_machine_equip_fde_ip_x64(DW_CFIMachine *machine, U64 fde_ip); diff --git a/src/eh/eh_frame.c b/src/eh/eh_frame.c new file mode 100644 index 00000000..bebc714c --- /dev/null +++ b/src/eh/eh_frame.c @@ -0,0 +1,130 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal U64 +eh_read_ptr(String8 frame_base, U64 off, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out) +{ + U64 ptr_off = off; + + // align read offset as needed + if (encoding == EH_PtrEnc_Aligned) { + ptr_off = AlignPow2(ptr_off, ptr_ctx->ptr_align); + encoding = EH_PtrEnc_Ptr; + } + + // decode pointer value + U64 decode_size = 0; + U64 raw_ptr_size = 0; + U64 raw_ptr = 0; + switch (encoding & EH_PtrEnc_TypeMask) { + default: { InvalidPath; } break; + + case EH_PtrEnc_Ptr : { raw_ptr_size = 8; } goto ufixed; + case EH_PtrEnc_UData2: { raw_ptr_size = 2; } goto ufixed; + case EH_PtrEnc_UData4: { raw_ptr_size = 4; } goto ufixed; + case EH_PtrEnc_UData8: { raw_ptr_size = 8; } goto ufixed; + ufixed: { + decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size); + } break; + + // TODO: Signed is actually just a flag that indicates this int is negavite. + // There shouldn't be a read for Signed. + // For instance, (EH_PtrEnc_UData2 | EH_PtrEnc_Signed) == EH_PtrEnc_SData etc. + case EH_PtrEnc_Signed: { raw_ptr_size = 8; } goto sfixed; + + case EH_PtrEnc_SData2: { raw_ptr_size = 2; } goto sfixed; + case EH_PtrEnc_SData4: { raw_ptr_size = 4; } goto sfixed; + case EH_PtrEnc_SData8: { raw_ptr_size = 8; } goto sfixed; + sfixed: { + decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size); + raw_ptr = extend_sign64(raw_ptr, raw_ptr_size); + } break; + + case EH_PtrEnc_ULEB128: { decode_size += str8_deserial_read_uleb128(frame_base, ptr_off, &raw_ptr); } break; + case EH_PtrEnc_SLEB128: { decode_size += str8_deserial_read_sleb128(frame_base, ptr_off, (S64*)&raw_ptr); } break; + } + + // apply relative bases + if (decode_size > 0) { + U64 ptr = raw_ptr; + switch (encoding & EH_PtrEnc_ModifierMask) { + case EH_PtrEnc_PcRel: { ptr = ptr_ctx->raw_base_vaddr + off + raw_ptr; } break; + case EH_PtrEnc_TextRel: { ptr = ptr_ctx->text_vaddr + raw_ptr; } break; + case EH_PtrEnc_DataRel: { ptr = ptr_ctx->data_vaddr + raw_ptr; } break; + case EH_PtrEnc_FuncRel: { + Assert(!"TODO: need a sample to verify implementation"); + ptr = ptr_ctx->func_vaddr + raw_ptr; + } break; + } + + if (ptr_out) { + *ptr_out = raw_ptr; + } + } + + return decode_size; +} + +internal U64 +eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out) +{ + // TODO: + // Handle "eh" param, it indicates presence of EH Data field. + // On 32bit arch it is a 4-byte and on 64-bit 8-byte value. + // Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html + // Reference doc doesn't clarify structure for EH Data though + + U64 cursor = 0; + + EH_AugFlags aug_flags = 0; + EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit; + EH_PtrEnc addr_encoding = EH_PtrEnc_UData8; + EH_PtrEnc handler_encoding = EH_PtrEnc_Omit; + U64 handler_ip = 0; + if (str8_match(str8_prefix(aug_string, 1), str8_lit("z"), 0)) { + U64 aug_data_off = cursor; + U64 aug_data_size = 0; + cursor += str8_deserial_read_uleb128(aug_string, cursor, &aug_data_size); + cursor += aug_data_size; + + String8 aug_data = str8_substr(aug_data, rng_1u64(aug_data_off, aug_data_off + aug_data_size)); + U64 aug_cursor = 0; + for (U8 *ptr = aug_string.str; ptr < (aug_string.str+aug_string.size); ptr += 1) { + switch (*ptr) { + case 'L': { + aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &lsda_encoding); + aug_flags |= EH_AugFlag_HasLSDA; + } break; + case 'P': { + aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &handler_encoding); + aug_cursor += str8_deserial_read_dwarf_ptr(aug_data, aug_cursor, ptr_ctx, handler_encoding, &handler_ip); + aug_flags |= EH_AugFlag_HasHandler; + } break; + case 'R': { + aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &addr_encoding); + aug_flags |= EH_AugFlag_HasAddrEnc; + } break; + default: { Assert(!"failed to parse augmentation string"); goto exit; } break; + } + } + } + + if (aug_out) { + aug_out->handler_ip = handler_ip; + aug_out->handler_encoding = handler_encoding; + aug_out->lsda_encoding = handler_encoding; + aug_out->addr_encoding = addr_encoding; + aug_out->flags = aug_flags; + } + +exit:; + U64 parse_size = cursor; + return parse_size; +} + +internal U64 +eh_size_from_aug_data(String8 aug_string, String8 data, EH_PtrCtx *ptr_ctx) +{ + return eh_parse_aug_data(aug_string, data, ptr_ctx, 0); +} + diff --git a/src/eh/eh_frame.h b/src/eh/eh_frame.h new file mode 100644 index 00000000..f4ee576c --- /dev/null +++ b/src/eh/eh_frame.h @@ -0,0 +1,74 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef EH_FRAME_H +#define EH_FRAME_H + +typedef U8 EH_PtrEnc; +enum +{ + EH_PtrEnc_Ptr = 0x00, // Pointer sized unsigned value + EH_PtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value + EH_PtrEnc_UData2 = 0x02, // Unsigned 16-bit value + EH_PtrEnc_UData4 = 0x03, // Unsigned 32-bit value + EH_PtrEnc_UData8 = 0x04, // Unsigned 64-bit value + EH_PtrEnc_Signed = 0x08, // Signed pointer + EH_PtrEnc_SLEB128 = 0x09, // Signed LE base-128 value + EH_PtrEnc_SData2 = 0x0A, // Signed 16-bit value + EH_PtrEnc_SData4 = 0x0B, // Signed 32-bit value + EH_PtrEnc_SData8 = 0x0C, // Signed 64-bit value + + EH_PtrEnc_TypeMask = 0x0F, +}; + +enum +{ + EH_PtrEnc_PcRel = 0x10, // Value is relative to the current program counter. + EH_PtrEnc_TextRel = 0x20, // Value is relative to the .text section. + EH_PtrEnc_DataRel = 0x30, // Value is relative to the .got or .eh_frame_hdr section. + EH_PtrEnc_FuncRel = 0x40, // Value is relative to the function. + EH_PtrEnc_Aligned = 0x50, // Value is aligned to an address unit sized boundary. + + EH_PtrEnc_ModifierMask = 0x70, +}; + +enum +{ + EH_PtrEnc_Indirect = 0x80, // Value is stored in virtual memory. + EH_PtrEnc_Omit = 0xFF, +}; + +typedef struct EH_PtrCtx +{ + U64 raw_base_vaddr; // address where pointer is being read + U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64) + U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64) + U64 func_vaddr; // base address of function where IP is located + U64 ptr_align; +} EH_PtrCtx; + +typedef U8 EH_AugFlags; +enum +{ + EH_AugFlag_HasLSDA = (1 << 0), + EH_AugFlag_HasHandler = (1 << 1), + EH_AugFlag_HasAddrEnc = (1 << 2), +}; + +typedef struct EH_Augmentation +{ + EH_AugFlags flags; + U64 handler_ip; + EH_PtrEnc handler_encoding; + EH_PtrEnc lsda_encoding; + EH_PtrEnc addr_encoding; +} EH_Augmentation; + +//////////////////////////////// + +internal U64 eh_read_ptr(String8 frame_base, U64 off, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out); +internal U64 eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out); +internal U64 eh_size_from_aug_data(String8 aug_string, String8 data, EH_PtrCtx *ptr_ctx); + +#endif // EH_FRAME_H + diff --git a/src/radbin/radbin_main.c b/src/radbin/radbin_main.c index e1abc2fc..51a65730 100644 --- a/src/radbin/radbin_main.c +++ b/src/radbin/radbin_main.c @@ -22,6 +22,7 @@ #include "elf/elf_parse.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" +#include "eh/eh_frame.h" #include "dwarf/dwarf_inc.h" #include "msf/msf.h" #include "msf/msf_parse.h" @@ -46,6 +47,7 @@ #include "elf/elf_parse.c" #include "codeview/codeview.c" #include "codeview/codeview_parse.c" +#include "eh/eh_frame.c" #include "dwarf/dwarf_inc.c" #include "msf/msf.c" #include "msf/msf_parse.c" diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index a59ab36f..3861c3f4 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -239,6 +239,7 @@ #include "pdb/pdb.h" #include "pdb/pdb_parse.h" #include "pdb/pdb_stringize.h" +#include "eh/eh_frame.h" #include "dwarf/dwarf_inc.h" #include "rdi_from_coff/rdi_from_coff.h" #include "rdi_from_elf/rdi_from_elf.h" @@ -285,6 +286,7 @@ #include "pdb/pdb.c" #include "pdb/pdb_parse.c" #include "pdb/pdb_stringize.c" +#include "eh/eh_frame.c" #include "dwarf/dwarf_inc.c" #include "rdi_from_coff/rdi_from_coff.c" #include "rdi_from_elf/rdi_from_elf.c" From e1986c9594c9e84a8c39fad402b3408597c4d14d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 7 Oct 2025 20:37:00 -0700 Subject: [PATCH 079/133] clang fixes --- src/dwarf/dwarf_dump.c | 2 +- src/dwarf/dwarf_parse.h | 2 +- src/dwarf/dwarf_unwind.c | 10 ++++++---- src/eh/eh_frame.c | 10 ++-------- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/dwarf/dwarf_dump.c b/src/dwarf/dwarf_dump.c index 9ebeab09..08f586a9 100644 --- a/src/dwarf/dwarf_dump.c +++ b/src/dwarf/dwarf_dump.c @@ -325,7 +325,7 @@ dw_string_from_expression(Arena *arena, String8 expr, U64 cu_base, U64 addr_size { Temp scratch = scratch_begin(&arena, 1); String8List list = dw_string_list_from_expression(scratch.arena, expr, cu_base, addr_size, arch, ver, ext, format); - String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=", "}); + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); return result; } diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index d7a6fb65..b22ac96f 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -521,7 +521,7 @@ internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size // debug frame internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out); -internal B32 dw_unpack_cie(String8 data, Arch arch, DW_Format format, DW_UnpackedCIE *cie_out); +internal B32 dw_unpack_cie(String8 data, DW_Format format, Arch arch, DW_UnpackedCIE *cie_out); internal B32 dw_unpack_fde(String8 data, DW_Format format, DW_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, DW_UnpackedFDE *fde_out); #endif // DWARF_PARSE_H diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index 168fd52e..5165da1f 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -569,13 +569,15 @@ dw_search_eh_frame_hdr_linear_x64(String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &table_enc); U64 eh_frame_ptr = 0, fde_count = 0; - cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, eh_frame_ptr_enc, cursor, &eh_frame_ptr); - cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, fde_count_enc, cursor, &fde_count); + NotImplemented; + //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, eh_frame_ptr_enc, cursor, &eh_frame_ptr); + //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, fde_count_enc, cursor, &fde_count); for (U64 fde_idx = 0; fde_idx < fde_count; ++fde_idx) { U64 init_location = 0, address = 0; - cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &init_location); - cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &address); + NotImplemented; + //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &init_location); + //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &address); S64 current_delta = (S64)(location - init_location); S64 closest_delta = (S64)(location - closest_location); diff --git a/src/eh/eh_frame.c b/src/eh/eh_frame.c index bebc714c..fd56a313 100644 --- a/src/eh/eh_frame.c +++ b/src/eh/eh_frame.c @@ -82,13 +82,7 @@ eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_A EH_PtrEnc handler_encoding = EH_PtrEnc_Omit; U64 handler_ip = 0; if (str8_match(str8_prefix(aug_string, 1), str8_lit("z"), 0)) { - U64 aug_data_off = cursor; - U64 aug_data_size = 0; - cursor += str8_deserial_read_uleb128(aug_string, cursor, &aug_data_size); - cursor += aug_data_size; - - String8 aug_data = str8_substr(aug_data, rng_1u64(aug_data_off, aug_data_off + aug_data_size)); - U64 aug_cursor = 0; + U64 aug_cursor = 0; for (U8 *ptr = aug_string.str; ptr < (aug_string.str+aug_string.size); ptr += 1) { switch (*ptr) { case 'L': { @@ -97,7 +91,7 @@ eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_A } break; case 'P': { aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &handler_encoding); - aug_cursor += str8_deserial_read_dwarf_ptr(aug_data, aug_cursor, ptr_ctx, handler_encoding, &handler_ip); + aug_cursor += eh_read_ptr(aug_data, aug_cursor, ptr_ctx, handler_encoding, &handler_ip); aug_flags |= EH_AugFlag_HasHandler; } break; case 'R': { From 7eb64dbd13881c90e4eb4f4bf76dbd94d21c6069 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 7 Oct 2025 20:42:52 -0700 Subject: [PATCH 080/133] metagen does not have this macro... --- src/third_party/stb/stb_sprintf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/third_party/stb/stb_sprintf.h b/src/third_party/stb/stb_sprintf.h index 113736aa..55f95241 100644 --- a/src/third_party/stb/stb_sprintf.h +++ b/src/third_party/stb/stb_sprintf.h @@ -753,7 +753,7 @@ cl = lg; \ Arena *arena = arena_alloc_(&(ArenaParams){ .flags = ArenaFlag_NoChain, .reserve_size = sizeof(buffer), .commit_size = sizeof(buffer), .optional_backing_buffer = buffer }); String8 min = str8_from_u64(arena, range.min, 16, 0, 0); - MemoryCopyStr8(bf, min); + MemoryCopy(bf, min.str, min.size); bf += min.size; *bf = ','; ++bf; @@ -761,7 +761,7 @@ cl = lg; \ arena_clear(arena); String8 max = str8_from_u64(arena, range.max, 16, 0, 0); - MemoryCopyStr8(bf, max); + MemoryCopy(bf, max.str, max.size); bf += max.size; *bf = ')'; ++bf; From 96477c65dd1ae34b4cda21144cb189b54668aaba Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 8 Oct 2025 12:58:59 -0700 Subject: [PATCH 081/133] switch to martins hash --- src/base/base_core.h | 31 + src/base/base_hash.c | 35 +- src/ctrl/ctrl_core.c | 3 +- src/raddbg/raddbg_core.c | 7 +- src/raddbg/raddbg_views.c | 2 + src/text/text.c | 2 + src/third_party/martins_hash/md5.h | 435 ++++++++++++++ src/third_party/martins_hash/sha1.h | 441 ++++++++++++++ src/third_party/martins_hash/sha256.h | 472 +++++++++++++++ src/third_party/martins_hash/sha512.h | 508 ++++++++++++++++ src/third_party/tomcrypt_hash/tomcrypt_hash.h | 567 ------------------ 11 files changed, 1913 insertions(+), 590 deletions(-) create mode 100644 src/third_party/martins_hash/md5.h create mode 100644 src/third_party/martins_hash/sha1.h create mode 100644 src/third_party/martins_hash/sha256.h create mode 100644 src/third_party/martins_hash/sha512.h delete mode 100644 src/third_party/tomcrypt_hash/tomcrypt_hash.h diff --git a/src/base/base_core.h b/src/base/base_core.h index bd67f5c6..a6f41da6 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -84,6 +84,37 @@ # define C_LINKAGE #endif +//////////////////////////////// +//~ rjf: Optimization Settings + +#if COMPILER_MSVC +# define OPTIMIZE_BEGIN _Pragma("optimize(\"\", on)") +# define OPTIMIZE_END _Pragma("optimize(\"\", off)") +#elif COMPILER_CLANG +# define OPTIMIZE_BEGIN _Pragma("clang optimize on") +# define OPTIMIZE_END _Pragma("clang optimize off") +#elif COMPILER_GCC +# define OPTIMIZE_BEGIN _Pragma("GCC push_options") _Pragma("GCC optimize(\"O2\")") +# define OPTIMIZE_END _Pragma("GCC pop_options") +#else +# define OPTIMIZE_BEGIN +# define OPTIMIZE_END +#endif + +#if COMPILER_MSVC && !BUILD_DEBUG +# define NO_OPTIMIZE_BEGIN _Pragma("optimize(\"\", off)") +# define NO_OPTIMIZE_END _Pragma("optimize(\"\", on)") +#elif COMPILER_CLANG && !BUILD_DEBUG +# define NO_OPTIMIZE_BEGIN _Pragma("clang optimize off") +# define NO_OPTIMIZE_END _Pragma("clang optimize on") +#elif COMPILER_GCC && !BUILD_DEBUG +# define NO_OPTIMIZE_BEGIN _Pragma("GCC push_options") _Pragma("GCC optimize(\"O0\")") +# define NO_OPTIMIZE_END _Pragma("GCC pop_options") +#else +# define NO_OPTIMIZE_BEGIN +# define NO_OPTIMIZE_END +#endif + //////////////////////////////// //~ rjf: Versions diff --git a/src/base/base_hash.c b/src/base/base_hash.c index 6799d6b2..0ca3f684 100644 --- a/src/base/base_hash.c +++ b/src/base/base_hash.c @@ -4,37 +4,34 @@ //////////////////////////////// //~ rjf: MD5 -#if !defined(MD5_API) -# define MD5_API static -# include "third_party/md5/md5.c" -# include "third_party/md5/md5.h" -#endif +#include "third_party/martins_hash/md5.h" internal MD5 md5_from_data(String8 data) { - MD5_CTX ctx = {0}; - MD5_Init(&ctx); - MD5_Update(&ctx, (void*)data.str, data.size); + md5_ctx ctx = {0}; + md5_init(&ctx); + md5_update(&ctx, (void*)data.str, data.size); MD5 result = {0}; - MD5_Final(result.u8, &ctx); + md5_finish(&ctx, result.u8); return result; } //////////////////////////////// -//~ rjf: SHA1 +//~ rjf: SHA -#include "third_party/tomcrypt_hash/tomcrypt_hash.h" +#include "third_party/martins_hash/sha1.h" +#include "third_party/martins_hash/sha256.h" internal SHA1 sha1_from_data(String8 data) { SHA1 result = {0}; { - SHA1State state = {0}; - sha1_init(&state); - sha1_process(&state, data.str, data.size); - sha1_done(&state, result.u8); + sha1_ctx ctx = {0}; + sha1_init(&ctx); + sha1_update(&ctx, data.str, data.size); + sha1_finish(&ctx, result.u8); } return result; } @@ -44,10 +41,10 @@ sha256_from_data(String8 data) { SHA256 result = {0}; { - SHA256State state = {0}; - sha256_init(&state); - sha256_process(&state, data.str, data.size); - sha256_done(&state, result.u8); + sha256_ctx ctx = {0}; + sha256_init(&ctx); + sha256_update(&ctx, data.str, data.size); + sha256_finish(&ctx, result.u8); } return result; } diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 5f4cdedf..9bc20a44 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6136,13 +6136,14 @@ internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale) { ProfBeginFunction(); +#pragma pack(push, 1) struct { CTRL_Handle process; Rng1U64 vaddr_range; B32 zero_terminated; - B32 _padding_; } key_data = {process, vaddr_range, zero_terminated}; +#pragma pack(pop) String8 key = str8_struct(&key_data); Access *access = access_open(); AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 03383933..e9ca65a1 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -5779,10 +5779,11 @@ rd_store_view_loading_info(B32 is_loading, U64 progress_u64, U64 progress_u64_ta { RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); RD_ViewState *view_state = rd_view_state_from_cfg(view); + B32 loading_state_is_new = (is_loading && view_state->loading_t_target != (F32)!!is_loading); view_state->loading_t_target = (F32)!!is_loading; view_state->loading_progress_v = progress_u64; view_state->loading_progress_v_target = progress_u64_target; - if(view_state->last_frame_index_built+1 < rd_state->frame_index) + if(loading_state_is_new || view_state->last_frame_index_built+1 < rd_state->frame_index) { view_state->loading_t = view_state->loading_t_target; } @@ -5983,7 +5984,7 @@ rd_window_state_from_os_handle(OS_Handle os) } #if COMPILER_MSVC && !BUILD_DEBUG -#pragma optimize("", off) +NO_OPTIMIZE_BEGIN #endif internal void @@ -9954,7 +9955,7 @@ rd_window_frame(void) } #if COMPILER_MSVC && !BUILD_DEBUG -#pragma optimize("", on) +NO_OPTIMIZE_END #endif //////////////////////////////// diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 431f1e9f..ec71f5b0 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -4024,12 +4024,14 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) for EachIndex(rewind_idx, C_KEY_HASH_HISTORY_COUNT) { U128 hash = c_hash_from_key(texture_key, rewind_idx); +#pragma pack(push, 1) struct { U128 hash; RD_BitmapTopology top; } key_data = {hash, topology}; +#pragma pack(pop) String8 key = str8_struct(&key_data); AC_Artifact artifact = ac_artifact_from_key(access, key, rd_bitmap_artifact_create, rd_bitmap_artifact_destroy, 0); R_Handle texture_candidate = {0}; diff --git a/src/text/text.c b/src/text/text.c index d86062fc..c81d1e08 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -2250,11 +2250,13 @@ txt_artifact_destroy(AC_Artifact artifact) internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) { +#pragma pack(push, 1) struct { U128 hash; TXT_LangKind lang; } key = {hash, lang}; +#pragma pack(pop) String8 key_string = str8_struct(&key); AC_Artifact artifact = ac_artifact_from_key(access, key_string, txt_artifact_create, txt_artifact_destroy, 0, .flags = AC_Flag_Wide); TXT_Artifact *txt_artifact = (TXT_Artifact *)artifact.u64[0]; diff --git a/src/third_party/martins_hash/md5.h b/src/third_party/martins_hash/md5.h new file mode 100644 index 00000000..54632d0e --- /dev/null +++ b/src/third_party/martins_hash/md5.h @@ -0,0 +1,435 @@ +#pragma once + +// https://www.rfc-editor.org/rfc/rfc1321.html + +#include +#include + +// +// interface +// + +#define MD5_DIGEST_SIZE 16 +#define MD5_BLOCK_SIZE 64 + +typedef struct { + uint8_t buffer[MD5_BLOCK_SIZE]; + uint64_t count; + uint32_t state[4]; +} md5_ctx; + +static inline void md5_init(md5_ctx* ctx); +static inline void md5_update(md5_ctx* ctx, const void* data, size_t size); +static inline void md5_finish(md5_ctx* ctx, uint8_t digest[MD5_DIGEST_SIZE]); + +// +// implementation +// + +#include // memcpy, memset + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcast-align" +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +# pragma clang diagnostic ignored "-Wlanguage-extension-token" +# pragma clang diagnostic ignored "-Wdeclaration-after-statement" +#endif + +#if defined(__clang__) +# define MD5_ROL32(x,n) __builtin_rotateleft32(x, n) +#elif defined(_MSC_VER) +# include +# define MD5_ROL32(x,n) _rotl(x, n) +#else +# define MD5_ROL32(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) +#endif + +#if defined(_MSC_VER) +# define MD5_GET32LE(ptr) *((const _UNALIGNED uint32_t*)(ptr)) +# define MD5_SET32LE(ptr,x) *((_UNALIGNED uint32_t*)(ptr)) = (x) +# define MD5_SET64LE(ptr,x) *((_UNALIGNED uint64_t*)(ptr)) = (x) +#else +# define MD5_GET32LE(ptr) \ + ( \ + ((ptr)[0] << 0) | \ + ((ptr)[1] << 8) | \ + ((ptr)[2] << 16) | \ + ((ptr)[3] << 24) \ + ) +# define MD5_SET32LE(ptr, x) do \ + { \ + (ptr)[0] = (uint8_t)((x) >> 0); \ + (ptr)[1] = (uint8_t)((x) >> 8); \ + (ptr)[2] = (uint8_t)((x) >> 16); \ + (ptr)[3] = (uint8_t)((x) >> 24); \ + } \ + while (0) +# define MD5_SET64LE(ptr, x) do \ + { \ + (ptr)[0] = (uint8_t)((x) >> 0); \ + (ptr)[1] = (uint8_t)((x) >> 8); \ + (ptr)[2] = (uint8_t)((x) >> 16); \ + (ptr)[3] = (uint8_t)((x) >> 24); \ + (ptr)[4] = (uint8_t)((x) >> 32); \ + (ptr)[5] = (uint8_t)((x) >> 40); \ + (ptr)[6] = (uint8_t)((x) >> 48); \ + (ptr)[7] = (uint8_t)((x) >> 56); \ + } \ + while (0) +#endif + +// MD5_COMPILER_BARRIER forces clang to do better codegen without spilling registers to stack too much +#if defined(__clang__) || defined(__GNUC__) +# define MD5_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") +#else +# define MD5_COMPILER_BARRIER() +#endif + + +#if defined(__x86_64__) || defined(_M_AMD64) + +#if defined(__clang__) || defined(__GNUC__) +# include +# define MD5_TARGET(str) __attribute__((target(str))) +# define MD5_CPUID_EX(x, y, info) __cpuid_count(x, y, info[0], info[1], info[2], info[3]) +# define MD5_ANDN_U32(x,y) (~(x) & (y)) +#else +# include +# define MD5_TARGET(str) +# define MD5_CPUID_EX(x, y, info) __cpuidex(info, x, y) +# define MD5_ANDN_U32(x,y) _andn_u32(x,y) +#endif + +#if defined(__clang__) +# define MD5_RORX_U32(x,n) __builtin_rotateright32(x, n) +#elif defined(_MSC_VER) +# define MD5_RORX_U32(x,n) _rorx_u32(x,n) +#else +# define MD5_RORX_U32(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) +#endif + +#define MD5_CPUID_INIT (1 << 0) +#define MD5_CPUID_BMI2 (1 << 1) + +static inline int md5_cpuid(void) +{ + static int cpuid; + + int result = cpuid; + if (result == 0) + { + int info[4]; + + MD5_CPUID_EX(7, 0, info); + int has_bmi = info[1] & (1 << 3); + int has_bmi2 = info[1] & (1 << 8); + + result |= MD5_CPUID_INIT; + if (has_bmi && has_bmi2) + { + result |= MD5_CPUID_BMI2; + } + + cpuid = result; + } + +#if defined(MD5_CPUID_MASK) + result &= MD5_CPUID_MASK; +#endif + + return result; +} + +MD5_TARGET("bmi,bmi2,tune=znver1") +static void md5_process_bmi2(uint32_t* state, const uint8_t* block, size_t count) +{ + // "tune=znver1" allows clang to use LEA with [reg+reg+imm] operand which helps performance on modern CPU's + // -1 in I will get folded together with constant k + + #define F(x,y,z) (x & y) + MD5_ANDN_U32(x, z) + #define G(x,y,z) (x & z) + MD5_ANDN_U32(z, y) + #define H(x,y,z) (x ^ y ^ z) + #define I(x,y,z) 0 - 1 - (y ^ MD5_ANDN_U32(x, z)) + + #define X(i) MD5_GET32LE(block + i*sizeof(uint32_t)) + + #define ROUND(F, a, b, c, d, x, k, r) do { \ + a += (k) + F(b, c, d) + (x); \ + a = MD5_RORX_U32(a, 32-r) + b; \ + } while (0) + + #define QROUND_F(x0, x1, x2, x3, k0, k1, k2, k3) do { \ + ROUND(F, a, b, c, d, X(x0), k0, 7); \ + ROUND(F, d, a, b, c, X(x1), k1, 12); \ + ROUND(F, c, d, a, b, X(x2), k2, 17); \ + ROUND(F, b, c, d, a, X(x3), k3, 22); \ + } while (0) + + #define QROUND_G(x0, x1, x2, x3, k0, k1, k2, k3) do { \ + ROUND(G, a, b, c, d, X(x0), k0, 5); \ + ROUND(G, d, a, b, c, X(x1), k1, 9); \ + ROUND(G, c, d, a, b, X(x2), k2, 14); \ + ROUND(G, b, c, d, a, X(x3), k3, 20); \ + } while (0) + + #define QROUND_H(x0, x1, x2, x3, k0, k1, k2, k3) do { \ + ROUND(H, a, b, c, d, X(x0), k0, 4); \ + ROUND(H, d, a, b, c, X(x1), k1, 11); \ + ROUND(H, c, d, a, b, X(x2), k2, 16); \ + ROUND(H, b, c, d, a, X(x3), k3, 23); \ + } while (0) + + #define QROUND_I(x0, x1, x2, x3, k0, k1, k2, k3) do { \ + ROUND(I, a, b, c, d, X(x0), k0, 6); \ + ROUND(I, d, a, b, c, X(x1), k1, 10); \ + ROUND(I, c, d, a, b, X(x2), k2, 15); \ + ROUND(I, b, c, d, a, X(x3), k3, 21); \ + } while (0) + + uint32_t a = state[0]; + uint32_t b = state[1]; + uint32_t c = state[2]; + uint32_t d = state[3]; + + do + { + uint32_t last_a = a; + uint32_t last_b = b; + uint32_t last_c = c; + uint32_t last_d = d; + + QROUND_F( 0, 1, 2, 3, 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee); + QROUND_F( 4, 5, 6, 7, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501); + QROUND_F( 8, 9, 10, 11, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be); + QROUND_F(12, 13, 14, 15, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821); + MD5_COMPILER_BARRIER(); + + QROUND_G( 1, 6, 11, 0, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa); + QROUND_G( 5, 10, 15, 4, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8); + QROUND_G( 9, 14, 3, 8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed); + QROUND_G(13, 2, 7, 12, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a); + MD5_COMPILER_BARRIER(); + + QROUND_H( 5, 8, 11, 14, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c); + QROUND_H( 1, 4, 7, 10, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70); + QROUND_H(13, 0, 3, 6, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05); + QROUND_H( 9, 12, 15, 2, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665); + MD5_COMPILER_BARRIER(); + + QROUND_I( 0, 7, 14, 5, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039); + QROUND_I(12, 3, 10, 1, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1); + QROUND_I( 8, 15, 6, 13, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1); + QROUND_I( 4, 11, 2, 9, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391); + MD5_COMPILER_BARRIER(); + + a += last_a; + b += last_b; + c += last_c; + d += last_d; + + block += MD5_BLOCK_SIZE; + } + while (--count); + + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + + #undef QROUND_F + #undef QROUND_G + #undef QROUND_H + #undef QROUND_I + #undef ROUND + #undef X + #undef F + #undef G + #undef H + #undef I +} + +#endif // defined(__x86_64__) || defined(_M_AMD64) + +static void md5_process(uint32_t* state, const uint8_t* block, size_t count) +{ +#if defined(__x86_64__) || defined(_M_AMD64) + int cpuid = md5_cpuid(); + if (cpuid & MD5_CPUID_BMI2) + { + md5_process_bmi2(state, block, count); + return; + } +#endif + + // F function uses 3 operations instead of 4 when "bit select" instruction is not available + // (x & y) | (~x & z) == (z ^ (x & (y ^ z)) + + // G function uses + instead of | for better ILP + + // #define F(x,y,z) ((x & y) | (~x & z)) + #define F(x,y,z) (z ^ (x & (y ^ z))) + #define G(x,y,z) (x & z) + (y & ~z) + #define H(x,y,z) (x ^ y ^ z) + #define I(x,y,z) (y ^ (x | ~z)) + + #define X(i) MD5_GET32LE(block + i*sizeof(uint32_t)) + + #define ROUND(F, a, b, c, d, x, k, r) do { \ + a += F(b, c, d) + (x) + (k); \ + a = MD5_ROL32(a, r) + b; \ + } while (0) + + #define QROUND_F(x0, x1, x2, x3, k0, k1, k2, k3) do { \ + ROUND(F, a, b, c, d, X(x0), k0, 7); \ + ROUND(F, d, a, b, c, X(x1), k1, 12); \ + ROUND(F, c, d, a, b, X(x2), k2, 17); \ + ROUND(F, b, c, d, a, X(x3), k3, 22); \ + } while (0) + + #define QROUND_G(x0, x1, x2, x3, k0, k1, k2, k3) do { \ + ROUND(G, a, b, c, d, X(x0), k0, 5); \ + ROUND(G, d, a, b, c, X(x1), k1, 9); \ + ROUND(G, c, d, a, b, X(x2), k2, 14); \ + ROUND(G, b, c, d, a, X(x3), k3, 20); \ + } while (0) + + #define QROUND_H(x0, x1, x2, x3, k0, k1, k2, k3) do { \ + ROUND(H, a, b, c, d, X(x0), k0, 4); \ + ROUND(H, d, a, b, c, X(x1), k1, 11); \ + ROUND(H, c, d, a, b, X(x2), k2, 16); \ + ROUND(H, b, c, d, a, X(x3), k3, 23); \ + } while (0) + + #define QROUND_I(x0, x1, x2, x3, k0, k1, k2, k3) do { \ + ROUND(I, a, b, c, d, X(x0), k0, 6); \ + ROUND(I, d, a, b, c, X(x1), k1, 10); \ + ROUND(I, c, d, a, b, X(x2), k2, 15); \ + ROUND(I, b, c, d, a, X(x3), k3, 21); \ + } while (0) + + uint32_t a = state[0]; + uint32_t b = state[1]; + uint32_t c = state[2]; + uint32_t d = state[3]; + + do + { + uint32_t last_a = a; + uint32_t last_b = b; + uint32_t last_c = c; + uint32_t last_d = d; + + QROUND_F( 0, 1, 2, 3, 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee); + QROUND_F( 4, 5, 6, 7, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501); + QROUND_F( 8, 9, 10, 11, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be); + QROUND_F(12, 13, 14, 15, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821); + MD5_COMPILER_BARRIER(); + + QROUND_G( 1, 6, 11, 0, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa); + QROUND_G( 5, 10, 15, 4, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8); + QROUND_G( 9, 14, 3, 8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed); + QROUND_G(13, 2, 7, 12, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a); + MD5_COMPILER_BARRIER(); + + QROUND_H( 5, 8, 11, 14, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c); + QROUND_H( 1, 4, 7, 10, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70); + QROUND_H(13, 0, 3, 6, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05); + QROUND_H( 9, 12, 15, 2, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665); + MD5_COMPILER_BARRIER(); + + QROUND_I( 0, 7, 14, 5, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039); + QROUND_I(12, 3, 10, 1, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1); + QROUND_I( 8, 15, 6, 13, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1); + QROUND_I( 4, 11, 2, 9, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391); + MD5_COMPILER_BARRIER(); + + a += last_a; + b += last_b; + c += last_c; + d += last_d; + + block += MD5_BLOCK_SIZE; + } + while (--count); + + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + + #undef QROUND_F + #undef QROUND_G + #undef QROUND_H + #undef QROUND_I + #undef ROUND + #undef X + #undef F + #undef G + #undef H + #undef I +} + +void md5_init(md5_ctx* ctx) +{ + ctx->count = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +void md5_update(md5_ctx* ctx, const void* data, size_t size) +{ + const uint8_t* buffer = (const uint8_t*)data; + + size_t pending = ctx->count % MD5_BLOCK_SIZE; + ctx->count += size; + + size_t available = MD5_BLOCK_SIZE - pending; + if (pending && size >= available) + { + memcpy(ctx->buffer + pending, buffer, available); + md5_process(ctx->state, ctx->buffer, 1); + buffer += available; + size -= available; + pending = 0; + } + + size_t count = size / MD5_BLOCK_SIZE; + if (count) + { + md5_process(ctx->state, buffer, count); + buffer += count * MD5_BLOCK_SIZE; + size -= count * MD5_BLOCK_SIZE; + } + + memcpy(ctx->buffer + pending, buffer, size); +} + +void md5_finish(md5_ctx* ctx, uint8_t digest[MD5_DIGEST_SIZE]) +{ + uint64_t count = ctx->count; + uint64_t bitcount = count * 8; + + size_t pending = count % MD5_BLOCK_SIZE; + size_t blocks = pending < MD5_BLOCK_SIZE - sizeof(bitcount) ? 1 : 2; + + ctx->buffer[pending++] = 0x80; + + uint8_t padding[2 * MD5_BLOCK_SIZE]; + memcpy(padding, ctx->buffer, MD5_BLOCK_SIZE); + memset(padding + pending, 0, MD5_BLOCK_SIZE); + MD5_SET64LE(padding + blocks * MD5_BLOCK_SIZE - sizeof(bitcount), bitcount); + + md5_process(ctx->state, padding, blocks); + + for (size_t i=0; i<4; i++) + { + MD5_SET32LE(digest + i*sizeof(uint32_t), ctx->state[i]); + } +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif diff --git a/src/third_party/martins_hash/sha1.h b/src/third_party/martins_hash/sha1.h new file mode 100644 index 00000000..043ac986 --- /dev/null +++ b/src/third_party/martins_hash/sha1.h @@ -0,0 +1,441 @@ +#pragma once + +// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf + +#include +#include + +// +// interface +// + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 + +typedef struct { + uint8_t buffer[SHA1_BLOCK_SIZE]; + uint64_t count; + uint32_t state[5]; +} sha1_ctx; + +static inline void sha1_init(sha1_ctx* ctx); +static inline void sha1_update(sha1_ctx* ctx, const void* data, size_t size); +static inline void sha1_finish(sha1_ctx* ctx, uint8_t digest[SHA1_DIGEST_SIZE]); + +// +// implementation +// + +#include // memcpy, memset + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcast-align" +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +# pragma clang diagnostic ignored "-Wlanguage-extension-token" +# pragma clang diagnostic ignored "-Wdeclaration-after-statement" +#elif defined(_MSC_VER) +# pragma warning (push) +# pragma warning (disable : 4127) +#endif + +#if defined(__clang__) +# define SHA1_ROL32(x,n) __builtin_rotateleft32(x, n) +#elif defined(_MSC_VER) +# include +# define SHA1_ROL32(x,n) _rotl(x, n) +#else +# define SHA1_ROL32(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) +#endif + +#if defined(_MSC_VER) +# include +# define SHA1_GET32BE(ptr) _byteswap_ulong( *((const _UNALIGNED uint32_t*)(ptr)) ) +# define SHA1_SET32BE(ptr,x) *((_UNALIGNED uint32_t*)(ptr)) = _byteswap_ulong(x) +# define SHA1_SET64BE(ptr,x) *((_UNALIGNED uint64_t*)(ptr)) = _byteswap_uint64(x) +#else +# define SHA1_GET32BE(ptr) \ + ( \ + ((ptr)[0] << 24) | \ + ((ptr)[1] << 16) | \ + ((ptr)[2] << 8) | \ + ((ptr)[3] << 0) \ + ) +# define SHA1_SET32BE(ptr, x) do \ + { \ + (ptr)[0] = (uint8_t)((x) >> 24); \ + (ptr)[1] = (uint8_t)((x) >> 16); \ + (ptr)[2] = (uint8_t)((x) >> 8); \ + (ptr)[3] = (uint8_t)((x) >> 0); \ + } \ + while (0) +# define SHA1_SET64BE(ptr, x) do \ + { \ + (ptr)[0] = (uint8_t)((x) >> 56); \ + (ptr)[1] = (uint8_t)((x) >> 48); \ + (ptr)[2] = (uint8_t)((x) >> 40); \ + (ptr)[3] = (uint8_t)((x) >> 32); \ + (ptr)[4] = (uint8_t)((x) >> 24); \ + (ptr)[5] = (uint8_t)((x) >> 16); \ + (ptr)[6] = (uint8_t)((x) >> 8); \ + (ptr)[7] = (uint8_t)((x) >> 0); \ + } \ + while (0) +#endif + +#if defined(__x86_64__) || defined(_M_AMD64) + +#include // SSSE3 +#include // SHANI + +#if defined(__clang__) || defined(__GNUC__) +# include +# define SHA1_TARGET(str) __attribute__((target(str))) +# define SHA1_CPUID(x, info) __cpuid(x, info[0], info[1], info[2], info[3]) +# define SHA1_CPUID_EX(x, y, info) __cpuid_count(x, y, info[0], info[1], info[2], info[3]) +#else +# include +# define SHA1_TARGET(str) +# define SHA1_CPUID(x, info) __cpuid(info, x) +# define SHA1_CPUID_EX(x, y, info) __cpuidex(info, x, y) +#endif + +#define SHA1_CPUID_INIT (1 << 0) +#define SHA1_CPUID_SHANI (1 << 1) + +static inline int sha1_cpuid(void) +{ + static int cpuid; + + int result = cpuid; + if (result == 0) + { + int info[4]; + + SHA1_CPUID(1, info); + int has_ssse3 = info[3] & (1 << 9); + + SHA1_CPUID_EX(7, 0, info); + int has_shani = info[1] & (1 << 29); + + result |= SHA1_CPUID_INIT; + if (has_ssse3 && has_shani) + { + result |= SHA1_CPUID_SHANI; + } + + cpuid = result; + } + +#if defined(SHA1_CPUID_MASK) + result &= SHA1_CPUID_MASK; +#endif + + return result; +} + +SHA1_TARGET("ssse3,sha") +static void sha1_process_shani(uint32_t* state, const uint8_t* block, size_t count) +{ + const __m128i* buffer = (const __m128i*)block; + + // for performing two operations in one: + // 1) dwords need to be loaded as big-endian + // 2) order of dwords need to be reversed for sha instructions: [0,1,2,3] -> [3,2,1,0] + const __m128i bswap = _mm_setr_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0); + + #define W(i) w[(i)%4] + + // 4 wide round calculations + #define QROUND(i) do { \ + /* first four rounds loads input message */ \ + if (i < 4) W(i) = _mm_shuffle_epi8(_mm_loadu_si128(&buffer[i]), bswap); \ + /* update previous message dwords for next rounds */ \ + if (i > 0 && i < 17) W(i-1) = _mm_sha1msg1_epu32(W(i-1), W(i)); \ + if (i > 1 && i < 18) W(i-2) = _mm_xor_si128(W(i-2), W(i)); \ + if (i > 2 && i < 19) W(i-3) = _mm_sha1msg2_epu32(W(i-3), W(i)); \ + /* calculate E from message dwords */ \ + if (i == 0) tmp = _mm_add_epi32(e0, W(i)); \ + if (i != 0) tmp = _mm_sha1nexte_epu32(e0, W(i)); \ + /* round function */ \ + e0 = abcd; \ + abcd = _mm_sha1rnds4_epu32(abcd, tmp, (i/5)%4); \ + } while(0) + + // load initial state + __m128i abcd = _mm_loadu_si128((const __m128i*)state); // [d,c,b,a] + __m128i e0 = _mm_loadu_si32(&state[4]); // [0,0,0,e] + + // change dword order + abcd = _mm_shuffle_epi32(abcd, _MM_SHUFFLE(0,1,2,3)); // [a,b,c,d] where a is in the top lane + e0 = _mm_slli_si128(e0, 12); // [e,0,0,0] where e is in top lane + + do + { + // remember current state + __m128i last_abcd = abcd; + __m128i last_e0 = e0; + + __m128i tmp, w[4]; + + QROUND(0); + QROUND(1); + QROUND(2); + QROUND(3); + QROUND(4); + QROUND(5); + QROUND(6); + QROUND(7); + QROUND(8); + QROUND(9); + QROUND(10); + QROUND(11); + QROUND(12); + QROUND(13); + QROUND(14); + QROUND(15); + QROUND(16); + QROUND(17); + QROUND(18); + QROUND(19); + + // update next state + abcd = _mm_add_epi32(abcd, last_abcd); + e0 = _mm_sha1nexte_epu32(e0, last_e0); + + buffer += 4; + } + while (--count); + + // restore dword order + abcd = _mm_shuffle_epi32(abcd, _MM_SHUFFLE(0,1,2,3)); + e0 = _mm_shuffle_epi32(e0, _MM_SHUFFLE(0,1,2,3)); + + // save the new state + _mm_storeu_si128((__m128i*)state, abcd); + _mm_storeu_si32(&state[4], e0); + + #undef QROUND + #undef W +} + +#endif // defined(__x86_64__) || defined(_M_AMD64) + +static void sha1_process(uint32_t* state, const uint8_t* block, size_t count) +{ +#if defined(__x86_64__) || defined(_M_AMD64) + int cpuid = sha1_cpuid(); + if (cpuid & SHA1_CPUID_SHANI) + { + sha1_process_shani(state, block, count); + return; + } +#endif + + #define F1(x,y,z) (0x5a827999 + ((x & (y ^ z)) ^ z)) + #define F2(x,y,z) (0x6ed9eba1 + (x ^ y ^ z)) + #define F3(x,y,z) (0x8f1bbcdc + ((x & y) | (z & (x | y)))) + #define F4(x,y,z) (0xca62c1d6 + (x ^ y ^ z)) + + #define W(i) w[(i+16)%16] + + #define ROUND(i,a,b,c,d,e,F) do \ + { \ + uint32_t w0; \ + if (i < 16) W(i) = w0 = SHA1_GET32BE(block + i*sizeof(uint32_t)); \ + if (i >= 16) W(i) = w0 = SHA1_ROL32(W(i-3) ^ W(i-8) ^ W(i-14) ^ W(i-16), 1); \ + \ + e += SHA1_ROL32(a,5) + F(b,c,d) + w0; \ + b = SHA1_ROL32(b,30); \ + } while (0) + + uint32_t a = state[0]; + uint32_t b = state[1]; + uint32_t c = state[2]; + uint32_t d = state[3]; + uint32_t e = state[4]; + + do + { + uint32_t last_a = a; + uint32_t last_b = b; + uint32_t last_c = c; + uint32_t last_d = d; + uint32_t last_e = e; + + uint32_t w[16]; + + ROUND( 0, a, b, c, d, e, F1); + ROUND( 1, e, a, b, c, d, F1); + ROUND( 2, d, e, a, b, c, F1); + ROUND( 3, c, d, e, a, b, F1); + ROUND( 4, b, c, d, e, a, F1); + ROUND( 5, a, b, c, d, e, F1); + ROUND( 6, e, a, b, c, d, F1); + ROUND( 7, d, e, a, b, c, F1); + ROUND( 8, c, d, e, a, b, F1); + ROUND( 9, b, c, d, e, a, F1); + ROUND(10, a, b, c, d, e, F1); + ROUND(11, e, a, b, c, d, F1); + ROUND(12, d, e, a, b, c, F1); + ROUND(13, c, d, e, a, b, F1); + ROUND(14, b, c, d, e, a, F1); + ROUND(15, a, b, c, d, e, F1); + ROUND(16, e, a, b, c, d, F1); + ROUND(17, d, e, a, b, c, F1); + ROUND(18, c, d, e, a, b, F1); + ROUND(19, b, c, d, e, a, F1); + + ROUND(20, a, b, c, d, e, F2); + ROUND(21, e, a, b, c, d, F2); + ROUND(22, d, e, a, b, c, F2); + ROUND(23, c, d, e, a, b, F2); + ROUND(24, b, c, d, e, a, F2); + ROUND(25, a, b, c, d, e, F2); + ROUND(26, e, a, b, c, d, F2); + ROUND(27, d, e, a, b, c, F2); + ROUND(28, c, d, e, a, b, F2); + ROUND(29, b, c, d, e, a, F2); + ROUND(30, a, b, c, d, e, F2); + ROUND(31, e, a, b, c, d, F2); + ROUND(32, d, e, a, b, c, F2); + ROUND(33, c, d, e, a, b, F2); + ROUND(34, b, c, d, e, a, F2); + ROUND(35, a, b, c, d, e, F2); + ROUND(36, e, a, b, c, d, F2); + ROUND(37, d, e, a, b, c, F2); + ROUND(38, c, d, e, a, b, F2); + ROUND(39, b, c, d, e, a, F2); + + ROUND(40, a, b, c, d, e, F3); + ROUND(41, e, a, b, c, d, F3); + ROUND(42, d, e, a, b, c, F3); + ROUND(43, c, d, e, a, b, F3); + ROUND(44, b, c, d, e, a, F3); + ROUND(45, a, b, c, d, e, F3); + ROUND(46, e, a, b, c, d, F3); + ROUND(47, d, e, a, b, c, F3); + ROUND(48, c, d, e, a, b, F3); + ROUND(49, b, c, d, e, a, F3); + ROUND(50, a, b, c, d, e, F3); + ROUND(51, e, a, b, c, d, F3); + ROUND(52, d, e, a, b, c, F3); + ROUND(53, c, d, e, a, b, F3); + ROUND(54, b, c, d, e, a, F3); + ROUND(55, a, b, c, d, e, F3); + ROUND(56, e, a, b, c, d, F3); + ROUND(57, d, e, a, b, c, F3); + ROUND(58, c, d, e, a, b, F3); + ROUND(59, b, c, d, e, a, F3); + + ROUND(60, a, b, c, d, e, F4); + ROUND(61, e, a, b, c, d, F4); + ROUND(62, d, e, a, b, c, F4); + ROUND(63, c, d, e, a, b, F4); + ROUND(64, b, c, d, e, a, F4); + ROUND(65, a, b, c, d, e, F4); + ROUND(66, e, a, b, c, d, F4); + ROUND(67, d, e, a, b, c, F4); + ROUND(68, c, d, e, a, b, F4); + ROUND(69, b, c, d, e, a, F4); + ROUND(70, a, b, c, d, e, F4); + ROUND(71, e, a, b, c, d, F4); + ROUND(72, d, e, a, b, c, F4); + ROUND(73, c, d, e, a, b, F4); + ROUND(74, b, c, d, e, a, F4); + ROUND(75, a, b, c, d, e, F4); + ROUND(76, e, a, b, c, d, F4); + ROUND(77, d, e, a, b, c, F4); + ROUND(78, c, d, e, a, b, F4); + ROUND(79, b, c, d, e, a, F4); + + a += last_a; + b += last_b; + c += last_c; + d += last_d; + e += last_e; + + block += SHA1_BLOCK_SIZE; + } + while (--count); + + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + state[4] = e; + + #undef ROUND + #undef W + #undef F1 + #undef F2 + #undef F3 + #undef F4 +} + +void sha1_init(sha1_ctx* ctx) +{ + ctx->count = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xc3d2e1f0; +} + +void sha1_update(sha1_ctx* ctx, const void* data, size_t size) +{ + const uint8_t* buffer = (const uint8_t*)data; + + size_t pending = ctx->count % SHA1_BLOCK_SIZE; + ctx->count += size; + + size_t available = SHA1_BLOCK_SIZE - pending; + if (pending && size >= available) + { + memcpy(ctx->buffer + pending, buffer, available); + sha1_process(ctx->state, ctx->buffer, 1); + buffer += available; + size -= available; + pending = 0; + } + + size_t count = size / SHA1_BLOCK_SIZE; + if (count) + { + sha1_process(ctx->state, buffer, count); + buffer += count * SHA1_BLOCK_SIZE; + size -= count * SHA1_BLOCK_SIZE; + } + + memcpy(ctx->buffer + pending, buffer, size); +} + +void sha1_finish(sha1_ctx* ctx, uint8_t digest[SHA1_DIGEST_SIZE]) +{ + uint64_t count = ctx->count; + uint64_t bitcount = count * 8; + + size_t pending = count % SHA1_BLOCK_SIZE; + size_t blocks = pending < SHA1_BLOCK_SIZE - sizeof(bitcount) ? 1 : 2; + + ctx->buffer[pending++] = 0x80; + + uint8_t padding[2 * SHA1_BLOCK_SIZE]; + memcpy(padding, ctx->buffer, SHA1_BLOCK_SIZE); + memset(padding + pending, 0, SHA1_BLOCK_SIZE); + SHA1_SET64BE(padding + blocks * SHA1_BLOCK_SIZE - sizeof(bitcount), bitcount); + + sha1_process(ctx->state, padding, blocks); + + for (size_t i=0; i<5; i++) + { + SHA1_SET32BE(digest + i*sizeof(uint32_t), ctx->state[i]); + } +} + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(_MSC_VER) +# pragma warning (pop) +#endif diff --git a/src/third_party/martins_hash/sha256.h b/src/third_party/martins_hash/sha256.h new file mode 100644 index 00000000..72a0fad6 --- /dev/null +++ b/src/third_party/martins_hash/sha256.h @@ -0,0 +1,472 @@ +#pragma once + +// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf +// https://www.rfc-editor.org/rfc/rfc6234 + +#include +#include + +// +// interface +// + +#define SHA224_DIGEST_SIZE 28 +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +typedef struct { + uint8_t buffer[SHA256_BLOCK_SIZE]; + uint64_t count; + uint32_t state[8]; +} sha256_ctx; + +typedef sha256_ctx sha224_ctx; + +static inline void sha256_init(sha256_ctx* ctx); +static inline void sha256_update(sha256_ctx* ctx, const void* data, size_t size); +static inline void sha256_finish(sha256_ctx* ctx, uint8_t digest[SHA256_DIGEST_SIZE]); + +static inline void sha224_init(sha224_ctx* ctx); +static inline void sha224_update(sha224_ctx* ctx, const void* data, size_t size); +static inline void sha224_finish(sha224_ctx* ctx, uint8_t digest[SHA224_DIGEST_SIZE]); + +// +// implementation +// + +#include // memcpy, memset + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcast-align" +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +# pragma clang diagnostic ignored "-Wlanguage-extension-token" +# pragma clang diagnostic ignored "-Wdeclaration-after-statement" +#elif defined(_MSC_VER) +# pragma warning (push) +# pragma warning (disable : 4127) +#endif + +#if defined(__clang__) +# define SHA256_ROR32(x,n) __builtin_rotateright32(x, n) +#elif defined(_MSC_VER) +# include +# define SHA256_ROR32(x,n) _rotr(x, n) +#else +# define SHA256_ROR32(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) +#endif + +#if defined(_MSC_VER) +# include +# define SHA256_GET32BE(ptr) _byteswap_ulong( *((const _UNALIGNED uint32_t*)(ptr)) ) +# define SHA256_SET32BE(ptr,x) *((_UNALIGNED uint32_t*)(ptr)) = _byteswap_ulong(x) +# define SHA256_SET64BE(ptr,x) *((_UNALIGNED uint64_t*)(ptr)) = _byteswap_uint64(x) +#else +# define SHA256_GET32BE(ptr) \ + ( \ + ((ptr)[0] << 24) | \ + ((ptr)[1] << 16) | \ + ((ptr)[2] << 8) | \ + ((ptr)[3] << 0) \ + ) +# define SHA256_SET32BE(ptr, x) do \ + { \ + (ptr)[0] = (uint8_t)((x) >> 24); \ + (ptr)[1] = (uint8_t)((x) >> 16); \ + (ptr)[2] = (uint8_t)((x) >> 8); \ + (ptr)[3] = (uint8_t)((x) >> 0); \ + } \ + while (0) +# define SHA256_SET64BE(ptr, x) do \ + { \ + (ptr)[0] = (uint8_t)((x) >> 56); \ + (ptr)[1] = (uint8_t)((x) >> 48); \ + (ptr)[2] = (uint8_t)((x) >> 40); \ + (ptr)[3] = (uint8_t)((x) >> 32); \ + (ptr)[4] = (uint8_t)((x) >> 24); \ + (ptr)[5] = (uint8_t)((x) >> 16); \ + (ptr)[6] = (uint8_t)((x) >> 8); \ + (ptr)[7] = (uint8_t)((x) >> 0); \ + } \ + while (0) +#endif + +#if defined(__x86_64__) || defined(_M_AMD64) + +#include // SSSE3 +#include // SHANI + +#if defined(__clang__) || defined(__GNUC__) +# include +# define SHA256_TARGET(str) __attribute__((target(str))) +# define SHA256_CPUID(x, info) __cpuid(x, info[0], info[1], info[2], info[3]) +# define SHA256_CPUID_EX(x, y, info) __cpuid_count(x, y, info[0], info[1], info[2], info[3]) +#else +# include +# define SHA256_TARGET(str) +# define SHA256_CPUID(x, info) __cpuid(info, x) +# define SHA256_CPUID_EX(x, y, info) __cpuidex(info, x, y) +#endif + +#define SHA256_CPUID_INIT (1 << 0) +#define SHA256_CPUID_SHANI (1 << 1) + +static inline int sha256_cpuid(void) +{ + static int cpuid; + + int result = cpuid; + if (result == 0) + { + int info[4]; + + SHA256_CPUID(1, info); + int has_ssse3 = info[3] & (1 << 9); + + SHA256_CPUID_EX(7, 0, info); + int has_shani = info[1] & (1 << 29); + + result |= SHA256_CPUID_INIT; + if (has_ssse3 && has_shani) + { + result |= SHA256_CPUID_SHANI; + } + + cpuid = result; + } + +#if defined(SHA256_CPUID_MASK) + result &= SHA256_CPUID_MASK; +#endif + + return result; +} + +SHA256_TARGET("ssse3,sha") +static void sha256_process_shani(uint32_t* state, const uint8_t* block, size_t count) +{ + const __m128i* buffer = (const __m128i*)block; + + // to byteswap when doing big-ending load for message dwords + const __m128i bswap = _mm_setr_epi8(3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12); + + static const uint32_t K[16][4] = + { + { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5 }, + { 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5 }, + { 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3 }, + { 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174 }, + { 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc }, + { 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da }, + { 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7 }, + { 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967 }, + { 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13 }, + { 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85 }, + { 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3 }, + { 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070 }, + { 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5 }, + { 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3 }, + { 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208 }, + { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }, + }; + + #define W(i) w[(i)%4] + + // 4 wide round calculations + #define QROUND(i) do { \ + /* first four rounds loads input message */ \ + if (i < 4) W(i) = _mm_shuffle_epi8(_mm_loadu_si128(&buffer[i]), bswap); \ + /* add round constant */ \ + tmp = _mm_add_epi32(W(i), _mm_loadu_si128((const __m128i*)K[i])); \ + /* update previous message dwords for next rounds */ \ + if (i > 2 && i < 15) W(i-3) = _mm_sha256msg2_epu32(_mm_add_epi32(W(i-3), _mm_alignr_epi8(W(i), W(i-1), 4)), W(i)); \ + if (i > 0 && i < 13) W(i-1) = _mm_sha256msg1_epu32(W(i-1), W(i)); \ + /* round functions */ \ + state1 = _mm_sha256rnds2_epu32(state1, state0, tmp); \ + state0 = _mm_sha256rnds2_epu32(state0, state1, _mm_shuffle_epi32(tmp, _MM_SHUFFLE(0,0,3,2))); \ + } while(0) + + // load initial state + __m128i abcd = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)&state[0]), _MM_SHUFFLE(0,1,2,3)); // [a,b,c,d] + __m128i efgh = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)&state[4]), _MM_SHUFFLE(0,1,2,3)); // [e,f,g,h] + + // dword order for sha256rnds2 instruction + __m128i state0 = _mm_unpackhi_epi64(efgh, abcd); // [a,b,e,f] + __m128i state1 = _mm_unpacklo_epi64(efgh, abcd); // [c,d,g,h] + + do + { + // remember current state + __m128i last0 = state0; + __m128i last1 = state1; + + __m128i tmp, w[4]; + + QROUND(0); + QROUND(1); + QROUND(2); + QROUND(3); + QROUND(4); + QROUND(5); + QROUND(6); + QROUND(7); + QROUND(8); + QROUND(9); + QROUND(10); + QROUND(11); + QROUND(12); + QROUND(13); + QROUND(14); + QROUND(15); + + // update next state + state0 = _mm_add_epi32(state0, last0); + state1 = _mm_add_epi32(state1, last1); + + buffer += 4; + } + while (--count); + + // restore dword order + abcd = _mm_unpackhi_epi64(state1, state0); + efgh = _mm_unpacklo_epi64(state1, state0); + + // save the new state + _mm_storeu_si128((__m128i*)&state[0], _mm_shuffle_epi32(abcd, _MM_SHUFFLE(0,1,2,3))); + _mm_storeu_si128((__m128i*)&state[4], _mm_shuffle_epi32(efgh, _MM_SHUFFLE(0,1,2,3))); + + #undef QROUND + #undef W +} + +#endif // defined(__x86_64__) || defined(_M_AMD64) + +static void sha256_process(uint32_t* state, const uint8_t* block, size_t count) +{ +#if defined(__x86_64__) || defined(_M_AMD64) + int cpuid = sha256_cpuid(); + if (cpuid & SHA256_CPUID_SHANI) + { + sha256_process_shani(state, block, count); + return; + } +#endif + + #define Ch(x,y,z) ((x & (y ^ z)) ^ z) + #define Maj(x,y,z) ((x & y) | (z & (x | y))) + + #define BSig0(x) (SHA256_ROR32(x, 2) ^ SHA256_ROR32(x, 13) ^ SHA256_ROR32(x, 22)) + #define BSig1(x) (SHA256_ROR32(x, 6) ^ SHA256_ROR32(x, 11) ^ SHA256_ROR32(x, 25)) + #define SSig0(x) (SHA256_ROR32(x, 7) ^ SHA256_ROR32(x, 18) ^ (x >> 3)) + #define SSig1(x) (SHA256_ROR32(x, 17) ^ SHA256_ROR32(x, 19) ^ (x >> 10)) + + #define W(i) w[(i+16)%16] + + #define ROUND(i,a,b,c,d,e,f,g,h,K) do \ + { \ + uint32_t w0; \ + if (i < 16) W(i) = w0 = SHA256_GET32BE(block + i*sizeof(uint32_t)); \ + if (i >= 16) W(i) = w0 = SSig1(W(i-2)) + W(i-7) + SSig0(W(i-15)) + W(i-16); \ + \ + uint32_t t1 = h + BSig1(e) + Ch(e,f,g) + K + w0; \ + uint32_t t2 = BSig0(a) + Maj(a,b,c); \ + d += t1; \ + h = t1 + t2; \ + } while (0) + + do + { + uint32_t a = state[0]; + uint32_t b = state[1]; + uint32_t c = state[2]; + uint32_t d = state[3]; + uint32_t e = state[4]; + uint32_t f = state[5]; + uint32_t g = state[6]; + uint32_t h = state[7]; + + uint32_t w[16]; + + ROUND( 0, a, b, c, d, e, f, g, h, 0x428a2f98); + ROUND( 1, h, a, b, c, d, e, f, g, 0x71374491); + ROUND( 2, g, h, a, b, c, d, e, f, 0xb5c0fbcf); + ROUND( 3, f, g, h, a, b, c, d, e, 0xe9b5dba5); + ROUND( 4, e, f, g, h, a, b, c, d, 0x3956c25b); + ROUND( 5, d, e, f, g, h, a, b, c, 0x59f111f1); + ROUND( 6, c, d, e, f, g, h, a, b, 0x923f82a4); + ROUND( 7, b, c, d, e, f, g, h, a, 0xab1c5ed5); + ROUND( 8, a, b, c, d, e, f, g, h, 0xd807aa98); + ROUND( 9, h, a, b, c, d, e, f, g, 0x12835b01); + ROUND(10, g, h, a, b, c, d, e, f, 0x243185be); + ROUND(11, f, g, h, a, b, c, d, e, 0x550c7dc3); + ROUND(12, e, f, g, h, a, b, c, d, 0x72be5d74); + ROUND(13, d, e, f, g, h, a, b, c, 0x80deb1fe); + ROUND(14, c, d, e, f, g, h, a, b, 0x9bdc06a7); + ROUND(15, b, c, d, e, f, g, h, a, 0xc19bf174); + ROUND(16, a, b, c, d, e, f, g, h, 0xe49b69c1); + ROUND(17, h, a, b, c, d, e, f, g, 0xefbe4786); + ROUND(18, g, h, a, b, c, d, e, f, 0x0fc19dc6); + ROUND(19, f, g, h, a, b, c, d, e, 0x240ca1cc); + ROUND(20, e, f, g, h, a, b, c, d, 0x2de92c6f); + ROUND(21, d, e, f, g, h, a, b, c, 0x4a7484aa); + ROUND(22, c, d, e, f, g, h, a, b, 0x5cb0a9dc); + ROUND(23, b, c, d, e, f, g, h, a, 0x76f988da); + ROUND(24, a, b, c, d, e, f, g, h, 0x983e5152); + ROUND(25, h, a, b, c, d, e, f, g, 0xa831c66d); + ROUND(26, g, h, a, b, c, d, e, f, 0xb00327c8); + ROUND(27, f, g, h, a, b, c, d, e, 0xbf597fc7); + ROUND(28, e, f, g, h, a, b, c, d, 0xc6e00bf3); + ROUND(29, d, e, f, g, h, a, b, c, 0xd5a79147); + ROUND(30, c, d, e, f, g, h, a, b, 0x06ca6351); + ROUND(31, b, c, d, e, f, g, h, a, 0x14292967); + ROUND(32, a, b, c, d, e, f, g, h, 0x27b70a85); + ROUND(33, h, a, b, c, d, e, f, g, 0x2e1b2138); + ROUND(34, g, h, a, b, c, d, e, f, 0x4d2c6dfc); + ROUND(35, f, g, h, a, b, c, d, e, 0x53380d13); + ROUND(36, e, f, g, h, a, b, c, d, 0x650a7354); + ROUND(37, d, e, f, g, h, a, b, c, 0x766a0abb); + ROUND(38, c, d, e, f, g, h, a, b, 0x81c2c92e); + ROUND(39, b, c, d, e, f, g, h, a, 0x92722c85); + ROUND(40, a, b, c, d, e, f, g, h, 0xa2bfe8a1); + ROUND(41, h, a, b, c, d, e, f, g, 0xa81a664b); + ROUND(42, g, h, a, b, c, d, e, f, 0xc24b8b70); + ROUND(43, f, g, h, a, b, c, d, e, 0xc76c51a3); + ROUND(44, e, f, g, h, a, b, c, d, 0xd192e819); + ROUND(45, d, e, f, g, h, a, b, c, 0xd6990624); + ROUND(46, c, d, e, f, g, h, a, b, 0xf40e3585); + ROUND(47, b, c, d, e, f, g, h, a, 0x106aa070); + ROUND(48, a, b, c, d, e, f, g, h, 0x19a4c116); + ROUND(49, h, a, b, c, d, e, f, g, 0x1e376c08); + ROUND(50, g, h, a, b, c, d, e, f, 0x2748774c); + ROUND(51, f, g, h, a, b, c, d, e, 0x34b0bcb5); + ROUND(52, e, f, g, h, a, b, c, d, 0x391c0cb3); + ROUND(53, d, e, f, g, h, a, b, c, 0x4ed8aa4a); + ROUND(54, c, d, e, f, g, h, a, b, 0x5b9cca4f); + ROUND(55, b, c, d, e, f, g, h, a, 0x682e6ff3); + ROUND(56, a, b, c, d, e, f, g, h, 0x748f82ee); + ROUND(57, h, a, b, c, d, e, f, g, 0x78a5636f); + ROUND(58, g, h, a, b, c, d, e, f, 0x84c87814); + ROUND(59, f, g, h, a, b, c, d, e, 0x8cc70208); + ROUND(60, e, f, g, h, a, b, c, d, 0x90befffa); + ROUND(61, d, e, f, g, h, a, b, c, 0xa4506ceb); + ROUND(62, c, d, e, f, g, h, a, b, 0xbef9a3f7); + ROUND(63, b, c, d, e, f, g, h, a, 0xc67178f2); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; + + block += SHA256_BLOCK_SIZE; + } + while (--count); + + #undef ROUND + #undef W + #undef Ch + #undef Maj + #undef BSig0 + #undef BSig1 + #undef SSig0 + #undef SSig1 +} + +void sha256_init(sha256_ctx* ctx) +{ + ctx->count = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void sha256_update(sha256_ctx* ctx, const void* data, size_t size) +{ + const uint8_t* buffer = (const uint8_t*)data; + + size_t pending = ctx->count % SHA256_BLOCK_SIZE; + ctx->count += size; + + size_t available = SHA256_BLOCK_SIZE - pending; + if (pending && size >= available) + { + memcpy(ctx->buffer + pending, buffer, available); + sha256_process(ctx->state, ctx->buffer, 1); + buffer += available; + size -= available; + pending = 0; + } + + size_t count = size / SHA256_BLOCK_SIZE; + if (count) + { + sha256_process(ctx->state, buffer, count); + buffer += count * SHA256_BLOCK_SIZE; + size -= count * SHA256_BLOCK_SIZE; + } + + memcpy(ctx->buffer + pending, buffer, size); +} + +void sha256_finish(sha256_ctx* ctx, uint8_t digest[SHA256_DIGEST_SIZE]) +{ + uint64_t count = ctx->count; + uint64_t bitcount = count * 8; + + size_t pending = count % SHA256_BLOCK_SIZE; + size_t blocks = pending < SHA256_BLOCK_SIZE - sizeof(bitcount) ? 1 : 2; + + ctx->buffer[pending++] = 0x80; + + uint8_t padding[2 * SHA256_BLOCK_SIZE]; + memcpy(padding, ctx->buffer, SHA256_BLOCK_SIZE); + memset(padding + pending, 0, SHA256_BLOCK_SIZE); + SHA256_SET64BE(padding + blocks * SHA256_BLOCK_SIZE - sizeof(bitcount), bitcount); + + sha256_process(ctx->state, padding, blocks); + + for (size_t i=0; i<8; i++) + { + SHA256_SET32BE(digest + i*sizeof(uint32_t), ctx->state[i]); + } +} + +void sha224_init(sha224_ctx* ctx) +{ + ctx->count = 0; + ctx->state[0] = 0xc1059ed8; + ctx->state[1] = 0x367cd507; + ctx->state[2] = 0x3070dd17; + ctx->state[3] = 0xf70e5939; + ctx->state[4] = 0xffc00b31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64f98fa7; + ctx->state[7] = 0xbefa4fa4; +} + +void sha224_update(sha224_ctx* ctx, const void* data, size_t size) +{ + sha256_update(ctx, data, size); +} + +void sha224_finish(sha224_ctx* ctx, uint8_t digest[SHA224_DIGEST_SIZE]) +{ + uint8_t temp[SHA256_DIGEST_SIZE]; + sha256_finish(ctx, temp); + + memcpy(digest, temp, SHA224_DIGEST_SIZE); +} + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(_MSC_VER) +# pragma warning (pop) +#endif diff --git a/src/third_party/martins_hash/sha512.h b/src/third_party/martins_hash/sha512.h new file mode 100644 index 00000000..2a7dad07 --- /dev/null +++ b/src/third_party/martins_hash/sha512.h @@ -0,0 +1,508 @@ +#pragma once + +// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf +// https://www.rfc-editor.org/rfc/rfc6234 + +#include +#include + +// +// interface +// + +#define SHA384_DIGEST_SIZE 48 +#define SHA512_DIGEST_SIZE 64 +#define SHA512_BLOCK_SIZE 128 + +typedef struct { + uint8_t buffer[SHA512_BLOCK_SIZE]; + uint64_t count[2]; + uint64_t state[8]; +} sha512_ctx; + +typedef sha512_ctx sha384_ctx; + +static inline void sha512_init(sha512_ctx* ctx); +static inline void sha512_update(sha512_ctx* ctx, const void* data, size_t size); +static inline void sha512_finish(sha512_ctx* ctx, uint8_t digest[SHA512_DIGEST_SIZE]); + +static inline void sha384_init(sha384_ctx* ctx); +static inline void sha384_update(sha384_ctx* ctx, const void* data, size_t size); +static inline void sha384_finish(sha384_ctx* ctx, uint8_t digest[SHA384_DIGEST_SIZE]); + +// +// implementation +// + +#include // memcpy, memset + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcast-align" +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +# pragma clang diagnostic ignored "-Wlanguage-extension-token" +# pragma clang diagnostic ignored "-Wdeclaration-after-statement" +#elif defined(_MSC_VER) +# pragma warning (push) +# pragma warning (disable : 4127) +#endif + +#if defined(__clang__) +# define SHA512_ROR64(x,n) __builtin_rotateright64(x, n) +#elif defined(_MSC_VER) +# include +# define SHA512_ROR64(x,n) _rotr64(x, n) +#else +# define SHA512_ROR64(x,n) ( ((x) >> (n)) | ((x) << (64-(n))) ) +#endif + +#if defined(_MSC_VER) +# include +# define SHA512_GET64BE(ptr) _byteswap_uint64( *((const _UNALIGNED uint64_t*)(ptr)) ) +# define SHA512_SET64BE(ptr,x) *((_UNALIGNED uint64_t*)(ptr)) = _byteswap_uint64(x) +#else +# define SHA512_GET64BE(ptr) \ + ( \ + ((uint64_t)((ptr)[0]) << 56) | \ + ((uint64_t)((ptr)[1]) << 48) | \ + ((uint64_t)((ptr)[2]) << 40) | \ + ((uint64_t)((ptr)[3]) << 32) | \ + ((uint64_t)((ptr)[4]) << 24) | \ + ((uint64_t)((ptr)[5]) << 16) | \ + ((uint64_t)((ptr)[6]) << 8) | \ + ((uint64_t)((ptr)[7]) << 0) \ + ) +# define SHA512_SET64BE(ptr, x) do \ + { \ + (ptr)[0] = (uint8_t)((x) >> 56); \ + (ptr)[1] = (uint8_t)((x) >> 48); \ + (ptr)[2] = (uint8_t)((x) >> 40); \ + (ptr)[3] = (uint8_t)((x) >> 32); \ + (ptr)[4] = (uint8_t)((x) >> 24); \ + (ptr)[5] = (uint8_t)((x) >> 16); \ + (ptr)[6] = (uint8_t)((x) >> 8); \ + (ptr)[7] = (uint8_t)((x) >> 0); \ + } \ + while (0) +#endif + +#if defined(__x86_64__) || defined(_M_AMD64) + +#include + +#if defined(__clang__) || defined(__GNUC__) +# include +# define SHA512_TARGET(str) __attribute__((target(str))) +# define SHA512_CPUID(x, info) __cpuid(x, info[0], info[1], info[2], info[3]) +# define SHA512_CPUID_EX(x, y, info) __cpuid_count(x, y, info[0], info[1], info[2], info[3]) +# define SHA512_XGETBV(x) __builtin_ia32_xgetbv(x) +#else +# include +# define SHA512_TARGET(str) +# define SHA512_CPUID(x, info) __cpuid(info, x) +# define SHA512_CPUID_EX(x, y, info) __cpuidex(info, x, y) +# define SHA512_XGETBV(x) _xgetbv(x) +#endif + +#define SHA512_CPUID_INIT (1 << 0) +#define SHA512_CPUID_VSHA512 (1 << 1) + +SHA512_TARGET("xsave") +static inline int sha512_cpuid(void) +{ + static int cpuid; + + int result = cpuid; + if (result == 0) + { + int info[4]; + + SHA256_CPUID(1, info); + int has_xsave = info[2] & (1 << 26); + + int has_ymm = 0; + if (has_xsave) + { + uint64_t xcr0 = SHA512_XGETBV(0); + has_ymm = xcr0 & (1 << 2); + } + + SHA256_CPUID_EX(7, 0, info); + int has_avx2 = info[1] & (1 << 5); + + SHA256_CPUID_EX(7, 1, info); + int has_sha512 = info[0] & (1 << 0); + + result |= SHA256_CPUID_INIT; + if (has_ymm && has_avx2 && has_sha512) + { + result |= SHA512_CPUID_VSHA512; + } + + cpuid = result; + } + +#if defined(SHA512_CPUID_MASK) + result &= SHA512_CPUID_MASK; +#endif + + return result; +} + +SHA512_TARGET("avx2,sha512") +static void sha512_process_vsha512(uint64_t* state, const uint8_t* block, size_t count) +{ + const __m256i* buffer = (const __m256i*)block; + + // to byteswap when doing big-ending load for message qwords + const __m256i bswap = _mm256_broadcastsi128_si256(_mm_setr_epi8(7,6,5,4,3,2,1,0, 15,14,13,12,11,10,9,8)); + + static const uint64_t K[20][4] = + { + { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc }, + { 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118 }, + { 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2 }, + { 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694 }, + { 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65 }, + { 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5 }, + { 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4 }, + { 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70 }, + { 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df }, + { 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b }, + { 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30 }, + { 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8 }, + { 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8 }, + { 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3 }, + { 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec }, + { 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b }, + { 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178 }, + { 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b }, + { 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c }, + { 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 }, + }; + + #define W(i) w[(i)%4] + + // 4 wide round calculations + #define QROUND(i) do { \ + /* first four rounds loads input message */ \ + if (i < 4) W(i) = _mm256_shuffle_epi8(_mm256_loadu_si256(&buffer[i]), bswap); \ + /* add round constant */ \ + tmp = _mm256_add_epi64(W(i), _mm256_loadu_si256((const __m256i*)K[i])); \ + /* update previous message qwords for next rounds */ \ + if (i > 2 && i < 19) W(i-3) = _mm256_sha512msg2_epi64(_mm256_add_epi64(W(i-3), _mm256_permute4x64_epi64(_mm256_blend_epi32(W(i-1), W(i), 3), _MM_SHUFFLE(0,3,2,1))), W(i)); \ + if (i > 0 && i < 17) W(i-1) = _mm256_sha512msg1_epi64(W(i-1), _mm256_castsi256_si128(W(i))); \ + /* round functions */ \ + state1 = _mm256_sha512rnds2_epi64(state1, state0, _mm256_castsi256_si128(tmp)); \ + state0 = _mm256_sha512rnds2_epi64(state0, state1, _mm256_extracti128_si256(tmp, 1)); \ + } while(0) + + // load initial state + __m256i abcd = _mm256_permute4x64_epi64(_mm256_loadu_si256((const __m256i*)&state[0]), _MM_SHUFFLE(0,1,2,3)); // [a,b,c,d] + __m256i efgh = _mm256_permute4x64_epi64(_mm256_loadu_si256((const __m256i*)&state[4]), _MM_SHUFFLE(0,1,2,3)); // [e,f,g,h] + + // qword order for vsha512rnds2 instruction + __m256i state0 = _mm256_permute2x128_si256(efgh, abcd, (3 << 4) | 1); // [a,b,e,f] + __m256i state1 = _mm256_permute2x128_si256(efgh, abcd, (2 << 4) | 0); // [c,d,g,h] + + do + { + // remember current state + __m256i last0 = state0; + __m256i last1 = state1; + + __m256i tmp, w[4]; + + QROUND(0); + QROUND(1); + QROUND(2); + QROUND(3); + QROUND(4); + QROUND(5); + QROUND(6); + QROUND(7); + QROUND(8); + QROUND(9); + QROUND(10); + QROUND(11); + QROUND(12); + QROUND(13); + QROUND(14); + QROUND(15); + QROUND(16); + QROUND(17); + QROUND(18); + QROUND(19); + + // update next state + state0 = _mm256_add_epi64(state0, last0); + state1 = _mm256_add_epi64(state1, last1); + + buffer += 4; + } + while (--count); + + // restore qword order + abcd = _mm256_permute2x128_si256(state1, state0, (3 << 4) | 1); + efgh = _mm256_permute2x128_si256(state1, state0, (2 << 4) | 0); + + // save the new state + _mm256_storeu_si256((__m256i*)&state[0], _mm256_permute4x64_epi64(abcd, _MM_SHUFFLE(0,1,2,3))); + _mm256_storeu_si256((__m256i*)&state[4], _mm256_permute4x64_epi64(efgh, _MM_SHUFFLE(0,1,2,3))); + + #undef QROUND + #undef W +} + +#endif // defined(__x86_64__) || defined(_M_AMD64) + +static void sha512_process(uint64_t* state, const uint8_t* block, size_t count) +{ +#if defined(__x86_64__) || defined(_M_AMD64) + int cpuid = sha512_cpuid(); + if (cpuid & SHA512_CPUID_VSHA512) + { + sha512_process_vsha512(state, block, count); + return; + } +#endif + + #define Ch(x,y,z) ((x & (y ^ z)) ^ z) + #define Maj(x,y,z) ((x & y) | (z & (x | y))) + + #define BSig0(x) (SHA512_ROR64(x, 28) ^ SHA512_ROR64(x, 34) ^ SHA512_ROR64(x, 39)) + #define BSig1(x) (SHA512_ROR64(x, 14) ^ SHA512_ROR64(x, 18) ^ SHA512_ROR64(x, 41)) + #define SSig0(x) (SHA512_ROR64(x, 1) ^ SHA512_ROR64(x, 8) ^ (x >> 7)) + #define SSig1(x) (SHA512_ROR64(x, 19) ^ SHA512_ROR64(x, 61) ^ (x >> 6)) + + #define W(i) w[(i+16)%16] + + #define ROUND(i,a,b,c,d,e,f,g,h,K) do \ + { \ + uint64_t w0; \ + if (i < 16) W(i) = w0 = SHA512_GET64BE(block + i*sizeof(uint64_t)); \ + if (i >= 16) W(i) = w0 = SSig1(W(i-2)) + W(i-7) + SSig0(W(i-15)) + W(i-16); \ + \ + uint64_t t1 = h + BSig1(e) + Ch(e,f,g) + K + w0; \ + uint64_t t2 = BSig0(a) + Maj(a,b,c); \ + d += t1; \ + h = t1 + t2; \ + } while (0) + + do + { + uint64_t a = state[0]; + uint64_t b = state[1]; + uint64_t c = state[2]; + uint64_t d = state[3]; + uint64_t e = state[4]; + uint64_t f = state[5]; + uint64_t g = state[6]; + uint64_t h = state[7]; + + uint64_t w[16]; + + ROUND( 0, a, b, c, d, e, f, g, h, 0x428a2f98d728ae22); + ROUND( 1, h, a, b, c, d, e, f, g, 0x7137449123ef65cd); + ROUND( 2, g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2f); + ROUND( 3, f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbc); + ROUND( 4, e, f, g, h, a, b, c, d, 0x3956c25bf348b538); + ROUND( 5, d, e, f, g, h, a, b, c, 0x59f111f1b605d019); + ROUND( 6, c, d, e, f, g, h, a, b, 0x923f82a4af194f9b); + ROUND( 7, b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118); + ROUND( 8, a, b, c, d, e, f, g, h, 0xd807aa98a3030242); + ROUND( 9, h, a, b, c, d, e, f, g, 0x12835b0145706fbe); + ROUND(10, g, h, a, b, c, d, e, f, 0x243185be4ee4b28c); + ROUND(11, f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2); + ROUND(12, e, f, g, h, a, b, c, d, 0x72be5d74f27b896f); + ROUND(13, d, e, f, g, h, a, b, c, 0x80deb1fe3b1696b1); + ROUND(14, c, d, e, f, g, h, a, b, 0x9bdc06a725c71235); + ROUND(15, b, c, d, e, f, g, h, a, 0xc19bf174cf692694); + ROUND(16, a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2); + ROUND(17, h, a, b, c, d, e, f, g, 0xefbe4786384f25e3); + ROUND(18, g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5); + ROUND(19, f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65); + ROUND(20, e, f, g, h, a, b, c, d, 0x2de92c6f592b0275); + ROUND(21, d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483); + ROUND(22, c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4); + ROUND(23, b, c, d, e, f, g, h, a, 0x76f988da831153b5); + ROUND(24, a, b, c, d, e, f, g, h, 0x983e5152ee66dfab); + ROUND(25, h, a, b, c, d, e, f, g, 0xa831c66d2db43210); + ROUND(26, g, h, a, b, c, d, e, f, 0xb00327c898fb213f); + ROUND(27, f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4); + ROUND(28, e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2); + ROUND(29, d, e, f, g, h, a, b, c, 0xd5a79147930aa725); + ROUND(30, c, d, e, f, g, h, a, b, 0x06ca6351e003826f); + ROUND(31, b, c, d, e, f, g, h, a, 0x142929670a0e6e70); + ROUND(32, a, b, c, d, e, f, g, h, 0x27b70a8546d22ffc); + ROUND(33, h, a, b, c, d, e, f, g, 0x2e1b21385c26c926); + ROUND(34, g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aed); + ROUND(35, f, g, h, a, b, c, d, e, 0x53380d139d95b3df); + ROUND(36, e, f, g, h, a, b, c, d, 0x650a73548baf63de); + ROUND(37, d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8); + ROUND(38, c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6); + ROUND(39, b, c, d, e, f, g, h, a, 0x92722c851482353b); + ROUND(40, a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364); + ROUND(41, h, a, b, c, d, e, f, g, 0xa81a664bbc423001); + ROUND(42, g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791); + ROUND(43, f, g, h, a, b, c, d, e, 0xc76c51a30654be30); + ROUND(44, e, f, g, h, a, b, c, d, 0xd192e819d6ef5218); + ROUND(45, d, e, f, g, h, a, b, c, 0xd69906245565a910); + ROUND(46, c, d, e, f, g, h, a, b, 0xf40e35855771202a); + ROUND(47, b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8); + ROUND(48, a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8); + ROUND(49, h, a, b, c, d, e, f, g, 0x1e376c085141ab53); + ROUND(50, g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99); + ROUND(51, f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8); + ROUND(52, e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63); + ROUND(53, d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acb); + ROUND(54, c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373); + ROUND(55, b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3); + ROUND(56, a, b, c, d, e, f, g, h, 0x748f82ee5defb2fc); + ROUND(57, h, a, b, c, d, e, f, g, 0x78a5636f43172f60); + ROUND(58, g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72); + ROUND(59, f, g, h, a, b, c, d, e, 0x8cc702081a6439ec); + ROUND(60, e, f, g, h, a, b, c, d, 0x90befffa23631e28); + ROUND(61, d, e, f, g, h, a, b, c, 0xa4506cebde82bde9); + ROUND(62, c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915); + ROUND(63, b, c, d, e, f, g, h, a, 0xc67178f2e372532b); + ROUND(64, a, b, c, d, e, f, g, h, 0xca273eceea26619c); + ROUND(65, h, a, b, c, d, e, f, g, 0xd186b8c721c0c207); + ROUND(66, g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1e); + ROUND(67, f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178); + ROUND(68, e, f, g, h, a, b, c, d, 0x06f067aa72176fba); + ROUND(69, d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6); + ROUND(70, c, d, e, f, g, h, a, b, 0x113f9804bef90dae); + ROUND(71, b, c, d, e, f, g, h, a, 0x1b710b35131c471b); + ROUND(72, a, b, c, d, e, f, g, h, 0x28db77f523047d84); + ROUND(73, h, a, b, c, d, e, f, g, 0x32caab7b40c72493); + ROUND(74, g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebc); + ROUND(75, f, g, h, a, b, c, d, e, 0x431d67c49c100d4c); + ROUND(76, e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6); + ROUND(77, d, e, f, g, h, a, b, c, 0x597f299cfc657e2a); + ROUND(78, c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faec); + ROUND(79, b, c, d, e, f, g, h, a, 0x6c44198c4a475817); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; + + block += SHA512_BLOCK_SIZE; + } + while (--count); + + #undef ROUND + #undef W + #undef Ch + #undef Maj + #undef BSig0 + #undef BSig1 + #undef SSig0 + #undef SSig1 +} + +void sha512_init(sha512_ctx* ctx) +{ + ctx->count[0] = 0; + ctx->count[1] = 0; + ctx->state[0] = 0x6a09e667f3bcc908; + ctx->state[1] = 0xbb67ae8584caa73b; + ctx->state[2] = 0x3c6ef372fe94f82b; + ctx->state[3] = 0xa54ff53a5f1d36f1; + ctx->state[4] = 0x510e527fade682d1; + ctx->state[5] = 0x9b05688c2b3e6c1f; + ctx->state[6] = 0x1f83d9abfb41bd6b; + ctx->state[7] = 0x5be0cd19137e2179; +} + +void sha512_update(sha512_ctx* ctx, const void* data, size_t size) +{ + const uint8_t* buffer = (const uint8_t*)data; + + size_t pending = ctx->count[0] % SHA512_BLOCK_SIZE; + ctx->count[0] += size; + ctx->count[1] += size > ctx->count[0]; + + size_t available = SHA512_BLOCK_SIZE - pending; + if (pending && size >= available) + { + memcpy(ctx->buffer + pending, buffer, available); + sha512_process(ctx->state, ctx->buffer, 1); + buffer += available; + size -= available; + pending = 0; + } + + size_t count = size / SHA512_BLOCK_SIZE; + if (count) + { + sha512_process(ctx->state, buffer, count); + buffer += count * SHA512_BLOCK_SIZE; + size -= count * SHA512_BLOCK_SIZE; + } + + memcpy(ctx->buffer + pending, buffer, size); +} + +void sha512_finish(sha512_ctx* ctx, uint8_t digest[SHA512_DIGEST_SIZE]) +{ + uint64_t count0 = ctx->count[0]; + uint64_t count1 = ctx->count[1]; + uint64_t bitcount[2] = { (count0 << 3), (count1 << 3) | (count0 >> 61) }; + + size_t pending = count0 % SHA512_BLOCK_SIZE; + size_t blocks = pending < SHA512_BLOCK_SIZE - sizeof(bitcount) ? 1 : 2; + + ctx->buffer[pending++] = 0x80; + + uint8_t padding[2 * SHA512_BLOCK_SIZE]; + memcpy(padding, ctx->buffer, SHA512_BLOCK_SIZE); + memset(padding + pending, 0, SHA512_BLOCK_SIZE); + SHA512_SET64BE(padding + blocks * SHA512_BLOCK_SIZE - 2*sizeof(uint64_t), bitcount[1]); + SHA512_SET64BE(padding + blocks * SHA512_BLOCK_SIZE - 1*sizeof(uint64_t), bitcount[0]); + + sha512_process(ctx->state, padding, blocks); + + for (size_t i=0; i<8; i++) + { + SHA512_SET64BE(digest + i*sizeof(uint64_t), ctx->state[i]); + } +} + +void sha384_init(sha384_ctx* ctx) +{ + ctx->count[0] = 0; + ctx->count[1] = 0; + ctx->state[0] = 0xcbbb9d5dc1059ed8; + ctx->state[1] = 0x629a292a367cd507; + ctx->state[2] = 0x9159015a3070dd17; + ctx->state[3] = 0x152fecd8f70e5939; + ctx->state[4] = 0x67332667ffc00b31; + ctx->state[5] = 0x8eb44a8768581511; + ctx->state[6] = 0xdb0c2e0d64f98fa7; + ctx->state[7] = 0x47b5481dbefa4fa4; +} + +void sha384_update(sha512_ctx* ctx, const void* data, size_t size) +{ + sha512_update(ctx, data, size); +} + +void sha384_finish(sha384_ctx* ctx, uint8_t digest[SHA384_DIGEST_SIZE]) +{ + uint8_t temp[SHA512_DIGEST_SIZE]; + sha512_finish(ctx, temp); + + memcpy(digest, temp, SHA384_DIGEST_SIZE); +} + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(_MSC_VER) +# pragma warning (pop) +#endif diff --git a/src/third_party/tomcrypt_hash/tomcrypt_hash.h b/src/third_party/tomcrypt_hash/tomcrypt_hash.h deleted file mode 100644 index 07770f01..00000000 --- a/src/third_party/tomcrypt_hash/tomcrypt_hash.h +++ /dev/null @@ -1,567 +0,0 @@ -// This is a collection of code originally sourced from LibTomCrypt, located at -// https://github.com/libtom/libtomcrypt, released under the following license: -// -// --- -// -// The LibTom license -// -// This is free and unencumbered software released into the public domain. -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. -// -// In jurisdictions that recognize copyright laws, the author or authors -// of this software dedicate any and all copyright interest in the -// software to the public domain. We make this dedication for the benefit -// of the public at large and to the detriment of our heirs and -// successors. We intend this dedication to be an overt act of -// relinquishment in perpetuity of all present and future rights to this -// software under copyright law. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// For more information, please refer to -// -// --- -// -// The code has been narrowed down and slightly modified, to include only the -// things that the RAD Debugger project needs, and to work with the project's -// build structure cleanly. - -#ifndef TOMCRYPT_HASH_H -#define TOMCRYPT_HASH_H - -//////////////////////////////// -//~ rjf: Common Helpers - -#define CRYPT_OK 1 - -#define LOAD32H(x, y) \ -do { x = ((U32)((y)[0] & 255)<<24) | \ -((U32)((y)[1] & 255)<<16) | \ -((U32)((y)[2] & 255)<<8) | \ -((U32)((y)[3] & 255)); } while(0) - -#define STORE32H(x, y) \ -do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ -(y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0) - -#define STORE64H(x, y) \ -do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ -(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ -(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ -(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0) - -#define LTC_TMPVAR__(n, l) n ## l -#define LTC_TMPVAR_(n, l) LTC_TMPVAR__(n, l) -#define LTC_TMPVAR(n) LTC_TMPVAR_(LTC_ ## n ## _, __LINE__) - -#define ROL(x, y) ( (((U32)(x)<<(U32)((y)&31)) | (((U32)(x)&0xFFFFFFFFUL)>>(U32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) -#define ROR(x, y) ( ((((U32)(x)&0xFFFFFFFFUL)>>(U32)((y)&31)) | ((U32)(x)<<(U32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) -#define ROLc(x, y) ( (((U32)(x)<<(U32)((y)&31)) | (((U32)(x)&0xFFFFFFFFUL)>>(U32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) -#define RORc(x, y) ( ((((U32)(x)&0xFFFFFFFFUL)>>(U32)((y)&31)) | ((U32)(x)<<(U32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) - -#define MIN(x, y) ( ((x)<(y))?(x):(y) ) - -//////////////////////////////// -//~ rjf: SHA256 - -typedef struct SHA256State SHA256State; -struct SHA256State -{ - U64 length; - U32 state[8], curlen; - U8 buf[64]; -}; - -/* Various logical functions */ -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) RORc((x),(n)) -#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) - -/* compress 512-bits */ -static int s_sha256_compress(SHA256State *state, const unsigned char *buf) -{ - U32 S[8], W[64], t0, t1; - int i; - - /* copy state into S */ - for (i = 0; i < 8; i++) { - S[i] = state->state[i]; - } - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) { - LOAD32H(W[i], buf + (4*i)); - } - - /* fill W[16..63] */ - for (i = 16; i < 64; i++) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } - - /* Compress */ -#define RND(a,b,c,d,e,f,g,h,i,ki) \ -t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ -t1 = Sigma0(a) + Maj(a, b, c); \ -d += t0; \ -h = t0 + t1; - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); -#undef RND - - /* feedback */ - for (i = 0; i < 8; i++) { - state->state[i] = state->state[i] + S[i]; - } - return CRYPT_OK; -} - -/** - Initialize the hash state - @param md The hash state you wish to initialize - @return CRYPT_OK if successful -*/ -int sha256_init(SHA256State *state) -{ - state->curlen = 0; - state->length = 0; - state->state[0] = 0x6A09E667UL; - state->state[1] = 0xBB67AE85UL; - state->state[2] = 0x3C6EF372UL; - state->state[3] = 0xA54FF53AUL; - state->state[4] = 0x510E527FUL; - state->state[5] = 0x9B05688CUL; - state->state[6] = 0x1F83D9ABUL; - state->state[7] = 0x5BE0CD19UL; - return CRYPT_OK; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful -*/ - -int sha256_process(SHA256State *state, const unsigned char *in, unsigned long inlen) -{ - unsigned long n; - int err; - int block_size = 64; - if(state->curlen > sizeof(state->buf)) - { - return 0; // CRYPT_INVALID_ARG - } - if(((state->length + inlen * 8) < state->length) || ((inlen * 8) < inlen)) - { - return 0; // CRYPT_HASH_OVERFLOW - } - while(inlen > 0) - { - if(state->curlen == 0 && inlen >= block_size) - { - if ((err = s_sha256_compress(state, in)) != CRYPT_OK) - { - return err; - } - state->length += block_size * 8; - in += block_size; - inlen -= block_size; - } else { - n = MIN(inlen, (block_size - state->curlen)); - MemoryCopy(state->buf + state->curlen, in, (size_t)n); - state->curlen += n; - in += n; - inlen -= n; - if(state->curlen == block_size) - { - if((err = s_sha256_compress(state, state->buf)) != CRYPT_OK) - { - return err; - } - state->length += 8*block_size; - state->curlen = 0; - } - } - } - return CRYPT_OK; -} - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (32 bytes) - @return CRYPT_OK if successful -*/ -int sha256_done(SHA256State *state, unsigned char *out) -{ - int i; - - if (state->curlen >= sizeof(state->buf)) { - return 0; // CRYPT_INVALID_ARG - } - - - /* increase the length of the message */ - state->length += state->curlen * 8; - - /* append the '1' bit */ - state->buf[state->curlen++] = (unsigned char)0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (state->curlen > 56) { - while (state->curlen < 64) { - state->buf[state->curlen++] = (unsigned char)0; - } - s_sha256_compress(state, state->buf); - state->curlen = 0; - } - - /* pad upto 56 bytes of zeroes */ - while (state->curlen < 56) { - state->buf[state->curlen++] = (unsigned char)0; - } - - /* store length */ - STORE64H(state->length, state->buf+56); - s_sha256_compress(state, state->buf); - - /* copy output */ - for (i = 0; i < 8; i++) { - STORE32H(state->state[i], out+(4*i)); - } - return CRYPT_OK; -} - -#undef Ch -#undef Maj -#undef S -#undef R -#undef Sigma0 -#undef Sigma1 -#undef Gamma0 -#undef Gamma1 - -//////////////////////////////// -//~ rjf: SHA1 - -typedef struct SHA1State SHA1State; -struct SHA1State -{ - U64 length; - U32 state[5], curlen; - unsigned char buf[64]; -}; - -#define F0(x,y,z) (z ^ (x & (y ^ z))) -#define F1(x,y,z) (x ^ y ^ z) -#define F2(x,y,z) ((x & y) | (z & (x | y))) -#define F3(x,y,z) (x ^ y ^ z) - -static int s_sha1_compress(SHA1State *state, const unsigned char *buf) -{ - U32 a,b,c,d,e,W[80],i; - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) { - LOAD32H(W[i], buf + (4*i)); - } - - /* copy state */ - a = state->state[0]; - b = state->state[1]; - c = state->state[2]; - d = state->state[3]; - e = state->state[4]; - - /* expand it */ - for (i = 16; i < 80; i++) { - W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); - } - - /* compress */ - /* round one */ -#define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30); -#define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30); -#define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30); -#define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30); - -#ifdef LTC_SMALL_CODE - - for (i = 0; i < 20; ) { - FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; - } - - for (; i < 40; ) { - FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; - } - - for (; i < 60; ) { - FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; - } - - for (; i < 80; ) { - FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; - } - -#else - - for (i = 0; i < 20; ) { - FF0(a,b,c,d,e,i++); - FF0(e,a,b,c,d,i++); - FF0(d,e,a,b,c,i++); - FF0(c,d,e,a,b,i++); - FF0(b,c,d,e,a,i++); - } - - /* round two */ - for (; i < 40; ) { - FF1(a,b,c,d,e,i++); - FF1(e,a,b,c,d,i++); - FF1(d,e,a,b,c,i++); - FF1(c,d,e,a,b,i++); - FF1(b,c,d,e,a,i++); - } - - /* round three */ - for (; i < 60; ) { - FF2(a,b,c,d,e,i++); - FF2(e,a,b,c,d,i++); - FF2(d,e,a,b,c,i++); - FF2(c,d,e,a,b,i++); - FF2(b,c,d,e,a,i++); - } - - /* round four */ - for (; i < 80; ) { - FF3(a,b,c,d,e,i++); - FF3(e,a,b,c,d,i++); - FF3(d,e,a,b,c,i++); - FF3(c,d,e,a,b,i++); - FF3(b,c,d,e,a,i++); - } -#endif - -#undef FF0 -#undef FF1 -#undef FF2 -#undef FF3 - - /* store */ - state->state[0] = state->state[0] + a; - state->state[1] = state->state[1] + b; - state->state[2] = state->state[2] + c; - state->state[3] = state->state[3] + d; - state->state[4] = state->state[4] + e; - - return CRYPT_OK; -} - -/** - Initialize the hash state - @param md The hash state you wish to initialize - @return CRYPT_OK if successful -*/ -int sha1_init(SHA1State *state) -{ - state->state[0] = 0x67452301UL; - state->state[1] = 0xefcdab89UL; - state->state[2] = 0x98badcfeUL; - state->state[3] = 0x10325476UL; - state->state[4] = 0xc3d2e1f0UL; - state->curlen = 0; - state->length = 0; - return CRYPT_OK; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful -*/ -// HASH_PROCESS(sha1_process, s_sha1_compress, sha1, 64) -int sha1_process(SHA1State *state, const unsigned char *in, unsigned long inlen) -{ - unsigned long n; - int err; - int block_size = 64; - if(state->curlen > sizeof(state->buf)) - { - return 0; // CRYPT_INVALID_ARG - } - if(((state->length + inlen * 8) < state->length) || ((inlen * 8) < inlen)) - { - return 0; // CRYPT_HASH_OVERFLOW - } - while(inlen > 0) - { - if(state->curlen == 0 && inlen >= block_size) - { - if ((err = s_sha1_compress(state, in)) != CRYPT_OK) - { - return err; - } - state->length += block_size * 8; - in += block_size; - inlen -= block_size; - } else { - n = MIN(inlen, (block_size - state->curlen)); - MemoryCopy(state->buf + state->curlen, in, (size_t)n); - state->curlen += n; - in += n; - inlen -= n; - if(state->curlen == block_size) - { - if((err = s_sha1_compress(state, state->buf)) != CRYPT_OK) - { - return err; - } - state->length += 8*block_size; - state->curlen = 0; - } - } - } - return CRYPT_OK; -} - - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (20 bytes) - @return CRYPT_OK if successful -*/ -int sha1_done(SHA1State *state, unsigned char *out) -{ - int i; - - if (state->curlen >= sizeof(state->buf)) { - return 0; // CRYPT_INVALID_ARG; - } - - /* increase the length of the message */ - state->length += state->curlen * 8; - - /* append the '1' bit */ - state->buf[state->curlen++] = (unsigned char)0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (state->curlen > 56) { - while (state->curlen < 64) { - state->buf[state->curlen++] = (unsigned char)0; - } - s_sha1_compress(state, state->buf); - state->curlen = 0; - } - - /* pad upto 56 bytes of zeroes */ - while (state->curlen < 56) { - state->buf[state->curlen++] = (unsigned char)0; - } - - /* store length */ - STORE64H(state->length, state->buf+56); - s_sha1_compress(state, state->buf); - - /* copy output */ - for (i = 0; i < 5; i++) { - STORE32H(state->state[i], out+(4*i)); - } - return CRYPT_OK; -} - -#undef F0 -#undef F1 -#undef F2 -#undef F3 -#undef FF0 -#undef FF1 -#undef FF2 -#undef FF3 - -#endif // TOMCRYPT_HASH_H From 4268c1de76a5d179c6a7e0f62a18a13a93d89898 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 8 Oct 2025 15:59:15 -0700 Subject: [PATCH 082/133] bump load gen on dbgi close also --- src/dbg_info/dbg_info.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 077a7686..5d3b7b9a 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -369,6 +369,7 @@ di_close(DI_Key key) if(node_released) { ins_atomic_u64_dec_eval(&di_shared->load_count); + ins_atomic_u64_inc_eval(&di_shared->load_gen); os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); os_file_map_close(file_map); os_file_close(file); From fe6eff9d3ba9ed9198347fd005285d995574df72 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 9 Oct 2025 10:40:31 -0700 Subject: [PATCH 083/133] pass requested gen to artifact creation hooks, use to retry ctrl memory reads on many successive mem gen bumps - prevents spurious duplicate hashes in content store history --- src/artifact_cache/artifact_cache.c | 4 ++-- src/artifact_cache/artifact_cache.h | 2 +- src/ctrl/ctrl_core.c | 17 ++++++++++------- src/ctrl/ctrl_core.h | 6 +++--- src/dbg_info/dbg_info.c | 4 ++-- src/dbg_info/dbg_info.h | 4 ++-- src/disasm/disasm.c | 2 +- src/disasm/disasm.h | 2 +- src/file_stream/file_stream.c | 2 +- src/file_stream/file_stream.h | 2 +- src/raddbg/raddbg_views.c | 10 +++++----- src/text/text.c | 2 +- src/text/text.h | 2 +- 13 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 535c28d5..3cf7c265 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -361,7 +361,7 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - AC_Artifact val = r->create(r->key, r->cancel_signal, &retry); + AC_Artifact val = r->create(r->key, r->gen, r->cancel_signal, &retry); // rjf: retry? -> resubmit request if(retry && lane_idx() == 0) @@ -466,7 +466,7 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - AC_Artifact val = r->create(r->key, r->cancel_signal, &retry); + AC_Artifact val = r->create(r->key, r->gen, r->cancel_signal, &retry); // rjf: restore wide lane ctx lane_ctx(lane_ctx_restore); diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index eab90c4e..b7ebf5c4 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -16,7 +16,7 @@ struct AC_Artifact //////////////////////////////// //~ rjf: Artifact Computation Function Types -typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out); +typedef AC_Artifact AC_CreateFunctionType(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); typedef void AC_DestroyFunctionType(AC_Artifact artifact); typedef U32 AC_Flags; diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 9bc20a44..7312b1d3 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -5977,7 +5977,7 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //~ rjf: Process Memory Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +ctrl_memory_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { AC_Artifact artifact = {0}; { @@ -6007,7 +6007,7 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) U64 zero_terminated_size = 0; U64 pre_read_mem_gen = ctrl_mem_gen(); B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); - if(range_size != 0) + if(pre_read_mem_gen == gen && range_size != 0) { // rjf: set up arena U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process @@ -6099,10 +6099,13 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) { hash = c_submit_data(content_key, &range_arena, str8((U8 *)range_base, zero_terminated_size)); } - else if(range_arena != 0) + else { - arena_release(range_arena); - if(pre_read_mem_gen != post_read_mem_gen && range_size != 0) + if(range_arena != 0) + { + arena_release(range_arena); + } + if((pre_read_mem_gen != gen || pre_read_mem_gen != post_read_mem_gen) && range_size != 0) { retry_out[0] = 1; } @@ -6365,7 +6368,7 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) //~ rjf: Call Stack Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +ctrl_call_stack_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { AC_Artifact artifact = {0}; { @@ -6561,7 +6564,7 @@ ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_ //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { Temp scratch = scratch_begin(0, 0); Access *access = access_open(); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 93ed7dc9..f220c30a 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1002,7 +1002,7 @@ internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact ctrl_memory_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale); @@ -1017,14 +1017,14 @@ internal B32 ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src); //////////////////////////////// //~ rjf: Call Stack Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); internal void ctrl_call_stack_artifact_destroy(AC_Artifact artifact); internal CTRL_CallStack ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); //////////////////////////////// //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); internal void ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact); internal CTRL_CallStackTree ctrl_call_stack_tree(Access *access, U64 endt_us); diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 5d3b7b9a..f2d92e58 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -1023,7 +1023,7 @@ di_conversion_completion_signal_receiver_thread_entry_point(void *p) //~ rjf: Search Artifact Cache Hooks / Lookups internal AC_Artifact -di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +di_search_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); Access *access = access_open(); @@ -1451,7 +1451,7 @@ di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, S //~ rjf: Match Artifact Cache Hooks / Lookups internal AC_Artifact -di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +di_match_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/dbg_info/dbg_info.h b/src/dbg_info/dbg_info.h index 9d00cf7f..4090003b 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -352,14 +352,14 @@ internal void di_conversion_completion_signal_receiver_thread_entry_point(void * //////////////////////////////// //~ rjf: Search Artifact Cache Hooks / Lookups -internal AC_Artifact di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact di_search_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); internal void di_search_artifact_destroy(AC_Artifact artifact); internal DI_SearchItemArray di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us, B32 *stale_out); //////////////////////////////// //~ rjf: Match Artifact Cache Hooks / Lookups -internal AC_Artifact di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact di_match_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); internal DI_Match di_match_from_string(String8 string, U64 index, DI_Key preferred_dbgi_key, U64 endt_us); #endif // DBG_INFO_H diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index 126fd52c..c5af5ab1 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -266,7 +266,7 @@ struct DASM_Artifact }; internal AC_Artifact -dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +dasm_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { DASM_Artifact *artifact = 0; if(lane_idx() == 0) diff --git a/src/disasm/disasm.h b/src/disasm/disasm.h index 0001693c..b1cda3fa 100644 --- a/src/disasm/disasm.h +++ b/src/disasm/disasm.h @@ -197,7 +197,7 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal AC_Artifact dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact dasm_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); internal void dasm_artifact_destroy(AC_Artifact artifact); internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index aa29c8c2..7d3f12d0 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -32,7 +32,7 @@ fs_change_gen(void) //~ rjf: Cache Interaction internal AC_Artifact -fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +fs_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 132debf5..8b0fb1f5 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -55,7 +55,7 @@ internal U64 fs_change_gen(void); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Accessing API -internal AC_Artifact fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact fs_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); internal void fs_artifact_destroy(AC_Artifact artifact); internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index ec71f5b0..b1a9648d 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1934,7 +1934,7 @@ RD_VIEW_UI_FUNCTION_DEF(null) {} //~ rjf: text @view_hook_impl internal AC_Artifact -rd_md5_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) +rd_md5_artifact_create(String8 key, U64 gen, B32 *cancel_out, B32 *retry_out) { AC_Artifact result = {0}; { @@ -1951,7 +1951,7 @@ rd_md5_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) } internal AC_Artifact -rd_sha1_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) +rd_sha1_artifact_create(String8 key, U64 gen, B32 *cancel_out, B32 *retry_out) { AC_Artifact result = {0}; { @@ -1968,7 +1968,7 @@ rd_sha1_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) } internal AC_Artifact -rd_sha256_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out) +rd_sha256_artifact_create(String8 key, U64 gen, B32 *cancel_out, B32 *retry_out) { AC_Artifact result = {0}; { @@ -3843,7 +3843,7 @@ struct RD_BitmapCanvasBoxDrawData }; internal AC_Artifact -rd_bitmap_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +rd_bitmap_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { Access *access = access_open(); @@ -4469,7 +4469,7 @@ struct RD_Geo3DBoxDrawData }; internal AC_Artifact -rd_geo3d_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +rd_geo3d_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { Access *access = access_open(); U128 hash = {0}; diff --git a/src/text/text.c b/src/text/text.c index c81d1e08..401e5e63 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -1970,7 +1970,7 @@ struct TXT_ArtifactCreateShared }; internal AC_Artifact -txt_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out) +txt_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/text/text.h b/src/text/text.h index 06e69bd4..532a4631 100644 --- a/src/text/text.h +++ b/src/text/text.h @@ -203,7 +203,7 @@ internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal AC_Artifact txt_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact txt_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); internal void txt_artifact_destroy(AC_Artifact artifact); internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); From 28bb158c61be7e693823c84c8157f443cb89d163 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 9 Oct 2025 11:10:14 -0700 Subject: [PATCH 084/133] revert last change - that will forever-retry those reads! need a slightly different retry mechanism --- src/ctrl/ctrl_core.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 7312b1d3..9134b2ed 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6007,7 +6007,7 @@ ctrl_memory_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry U64 zero_terminated_size = 0; U64 pre_read_mem_gen = ctrl_mem_gen(); B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); - if(pre_read_mem_gen == gen && range_size != 0) + if(range_size != 0) { // rjf: set up arena U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process @@ -6099,19 +6099,8 @@ ctrl_memory_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry { hash = c_submit_data(content_key, &range_arena, str8((U8 *)range_base, zero_terminated_size)); } - else - { - if(range_arena != 0) - { - arena_release(range_arena); - } - if((pre_read_mem_gen != gen || pre_read_mem_gen != post_read_mem_gen) && range_size != 0) - { - retry_out[0] = 1; - } - } - //- rjf: wakeup on new reads + //- rjf: wakeup on new submissions if(!u128_match(u128_zero(), hash)) { if(ctrl_state->wakeup_hook != 0) @@ -6120,6 +6109,18 @@ ctrl_memory_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry } } + //- rjf: always release leftover arenas + if(range_arena != 0) + { + arena_release(range_arena); + } + + //- rjf: retry on mem gen "tearing", and if the range is non-empty + if(pre_read_mem_gen != post_read_mem_gen && range_size != 0) + { + retry_out[0] = 1; + } + //- rjf: bundle content key as artifact StaticAssert(sizeof(content_key) == sizeof(artifact), artifact_key_size_check); MemoryCopyStruct(&artifact, &content_key); From 9022efd3ab35dc42b039120f73b1dd357594b569 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 9 Oct 2025 11:24:48 -0700 Subject: [PATCH 085/133] new strategy - allow artifact creation to report a completed generation which differs from the requested generation, thus preventing duplicate gen requests (in the case of ctrl process memory) --- src/artifact_cache/artifact_cache.c | 10 ++++++---- src/artifact_cache/artifact_cache.h | 2 +- src/ctrl/ctrl_core.c | 7 ++++--- src/ctrl/ctrl_core.h | 6 +++--- src/dbg_info/dbg_info.c | 4 ++-- src/dbg_info/dbg_info.h | 4 ++-- src/disasm/disasm.c | 2 +- src/disasm/disasm.h | 2 +- src/file_stream/file_stream.c | 2 +- src/file_stream/file_stream.h | 2 +- src/raddbg/raddbg_views.c | 10 +++++----- src/text/text.c | 2 +- src/text/text.h | 2 +- 13 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 3cf7c265..16f7a221 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -361,7 +361,8 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - AC_Artifact val = r->create(r->key, r->gen, r->cancel_signal, &retry); + U64 gen = r->gen; + AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen); // rjf: retry? -> resubmit request if(retry && lane_idx() == 0) @@ -411,7 +412,7 @@ ac_async_tick(void) { if(str8_match(n->key, r->key, 0)) { - n->last_completed_gen = r->gen; + n->last_completed_gen = gen; n->val = val; ins_atomic_u64_dec_eval(&n->working_count); ins_atomic_u64_inc_eval(&n->completion_count); @@ -466,7 +467,8 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - AC_Artifact val = r->create(r->key, r->gen, r->cancel_signal, &retry); + U64 gen = r->gen; + AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen); // rjf: restore wide lane ctx lane_ctx(lane_ctx_restore); @@ -519,7 +521,7 @@ ac_async_tick(void) { if(str8_match(n->key, r->key, 0)) { - n->last_completed_gen = r->gen; + n->last_completed_gen = gen; n->val = val; ins_atomic_u64_dec_eval(&n->working_count); ins_atomic_u64_inc_eval(&n->completion_count); diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index b7ebf5c4..1f5bf00c 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -16,7 +16,7 @@ struct AC_Artifact //////////////////////////////// //~ rjf: Artifact Computation Function Types -typedef AC_Artifact AC_CreateFunctionType(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); typedef void AC_DestroyFunctionType(AC_Artifact artifact); typedef U32 AC_Flags; diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 9134b2ed..3ef242a7 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -5977,7 +5977,7 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //~ rjf: Process Memory Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_memory_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { AC_Artifact artifact = {0}; { @@ -6098,6 +6098,7 @@ ctrl_memory_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry if((zero_terminated_size > 0 || !key_has_history) && range_size != 0 && pre_read_mem_gen == post_read_mem_gen) { hash = c_submit_data(content_key, &range_arena, str8((U8 *)range_base, zero_terminated_size)); + gen_out[0] = pre_read_mem_gen; } //- rjf: wakeup on new submissions @@ -6369,7 +6370,7 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) //~ rjf: Call Stack Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_call_stack_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { AC_Artifact artifact = {0}; { @@ -6565,7 +6566,7 @@ ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_ //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +ctrl_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { Temp scratch = scratch_begin(0, 0); Access *access = access_open(); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index f220c30a..49cf7b78 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1002,7 +1002,7 @@ internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_memory_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale); @@ -1017,14 +1017,14 @@ internal B32 ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src); //////////////////////////////// //~ rjf: Call Stack Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal void ctrl_call_stack_artifact_destroy(AC_Artifact artifact); internal CTRL_CallStack ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); //////////////////////////////// //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal void ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact); internal CTRL_CallStackTree ctrl_call_stack_tree(Access *access, U64 endt_us); diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index f2d92e58..aaa6f86f 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -1023,7 +1023,7 @@ di_conversion_completion_signal_receiver_thread_entry_point(void *p) //~ rjf: Search Artifact Cache Hooks / Lookups internal AC_Artifact -di_search_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { ProfBeginFunction(); Access *access = access_open(); @@ -1451,7 +1451,7 @@ di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, S //~ rjf: Match Artifact Cache Hooks / Lookups internal AC_Artifact -di_match_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/dbg_info/dbg_info.h b/src/dbg_info/dbg_info.h index 4090003b..0002088a 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -352,14 +352,14 @@ internal void di_conversion_completion_signal_receiver_thread_entry_point(void * //////////////////////////////// //~ rjf: Search Artifact Cache Hooks / Lookups -internal AC_Artifact di_search_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal void di_search_artifact_destroy(AC_Artifact artifact); internal DI_SearchItemArray di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us, B32 *stale_out); //////////////////////////////// //~ rjf: Match Artifact Cache Hooks / Lookups -internal AC_Artifact di_match_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal DI_Match di_match_from_string(String8 string, U64 index, DI_Key preferred_dbgi_key, U64 endt_us); #endif // DBG_INFO_H diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index c5af5ab1..43874135 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -266,7 +266,7 @@ struct DASM_Artifact }; internal AC_Artifact -dasm_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { DASM_Artifact *artifact = 0; if(lane_idx() == 0) diff --git a/src/disasm/disasm.h b/src/disasm/disasm.h index b1cda3fa..11356b8a 100644 --- a/src/disasm/disasm.h +++ b/src/disasm/disasm.h @@ -197,7 +197,7 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal AC_Artifact dasm_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal void dasm_artifact_destroy(AC_Artifact artifact); internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 7d3f12d0..88383adb 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -32,7 +32,7 @@ fs_change_gen(void) //~ rjf: Cache Interaction internal AC_Artifact -fs_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 8b0fb1f5..579f68cc 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -55,7 +55,7 @@ internal U64 fs_change_gen(void); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Accessing API -internal AC_Artifact fs_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal void fs_artifact_destroy(AC_Artifact artifact); internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index b1a9648d..e2786c58 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1934,7 +1934,7 @@ RD_VIEW_UI_FUNCTION_DEF(null) {} //~ rjf: text @view_hook_impl internal AC_Artifact -rd_md5_artifact_create(String8 key, U64 gen, B32 *cancel_out, B32 *retry_out) +rd_md5_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out) { AC_Artifact result = {0}; { @@ -1951,7 +1951,7 @@ rd_md5_artifact_create(String8 key, U64 gen, B32 *cancel_out, B32 *retry_out) } internal AC_Artifact -rd_sha1_artifact_create(String8 key, U64 gen, B32 *cancel_out, B32 *retry_out) +rd_sha1_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out) { AC_Artifact result = {0}; { @@ -1968,7 +1968,7 @@ rd_sha1_artifact_create(String8 key, U64 gen, B32 *cancel_out, B32 *retry_out) } internal AC_Artifact -rd_sha256_artifact_create(String8 key, U64 gen, B32 *cancel_out, B32 *retry_out) +rd_sha256_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out) { AC_Artifact result = {0}; { @@ -3843,7 +3843,7 @@ struct RD_BitmapCanvasBoxDrawData }; internal AC_Artifact -rd_bitmap_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +rd_bitmap_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { Access *access = access_open(); @@ -4469,7 +4469,7 @@ struct RD_Geo3DBoxDrawData }; internal AC_Artifact -rd_geo3d_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +rd_geo3d_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { Access *access = access_open(); U128 hash = {0}; diff --git a/src/text/text.c b/src/text/text.c index 401e5e63..7b4ef0f8 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -1970,7 +1970,7 @@ struct TXT_ArtifactCreateShared }; internal AC_Artifact -txt_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out) +txt_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/text/text.h b/src/text/text.h index 532a4631..c34eb64b 100644 --- a/src/text/text.h +++ b/src/text/text.h @@ -203,7 +203,7 @@ internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal AC_Artifact txt_artifact_create(String8 key, U64 gen, B32 *cancel_signal, B32 *retry_out); +internal AC_Artifact txt_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal void txt_artifact_destroy(AC_Artifact artifact); internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); From da44e89a92c008e96a89e60f1ac4597d72caa6a8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 9 Oct 2025 13:57:41 -0700 Subject: [PATCH 086/133] fix clang build --- build.bat | 2 +- src/third_party/stb/stb_image.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.bat b/build.bat index 77784200..d3d2e6a4 100644 --- a/build.bat +++ b/build.bat @@ -72,7 +72,7 @@ set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf set cl_out= /out: set cl_linker= -set clang_common= -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 +set clang_common= -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 -msha set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf diff --git a/src/third_party/stb/stb_image.h b/src/third_party/stb/stb_image.h index a2f44c8d..6859e01c 100644 --- a/src/third_party/stb/stb_image.h +++ b/src/third_party/stb/stb_image.h @@ -724,7 +724,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #define STBI_SSE2 #include -#ifdef _MSC_VER +#if !defined(__clang__) && defined(_MSC_VER) #if _MSC_VER >= 1400 // not VC6 #include // __cpuid From c738768e41153b8e598ef51aa57530cf71c19880 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 9 Oct 2025 16:05:13 -0700 Subject: [PATCH 087/133] demon/win32: do not assume `actual_read` is valid after a failed process memory read --- src/ctrl/ctrl_core.c | 2 +- src/demon/win32/demon_core_win32.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 3ef242a7..4f922e78 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6095,7 +6095,7 @@ ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 //- rjf: read successful, OR we have no history -> submit to hash store U128 hash = {0}; - if((zero_terminated_size > 0 || !key_has_history) && range_size != 0 && pre_read_mem_gen == post_read_mem_gen) + if((zero_terminated_size > 0 || !key_has_history) && range_base != 0 && range_size != 0 && pre_read_mem_gen == post_read_mem_gen) { hash = c_submit_data(content_key, &range_arena, str8((U8 *)range_base, zero_terminated_size)); gen_out[0] = pre_read_mem_gen; diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index ea1f3118..8ccf1fa7 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -322,7 +322,9 @@ dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst) { DWORD error = GetLastError(); log_infof("'Win32 ReadProcessMemory failure': { [0x%I64x, 0x%I64x), code: %i }\n", range.min, range.max, error); - bytes_read += actual_read; + // NOTE(rjf): I have discovered that `actual_read` is *NOT* guaranteed to have + // a usable value if `ReadProcessMemory` fails! + // bytes_read += actual_read; (void)error; break; } From 061b5c59557b31d3e412c48809776e95ecd2f3e2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 10 Oct 2025 10:09:46 -0700 Subject: [PATCH 088/133] added CFA instruction parser, interpreter, and a dumper --- src/dwarf/dwarf.c | 99 ++- src/dwarf/dwarf.h | 117 ++-- src/dwarf/dwarf_dump.c | 275 ++++---- src/dwarf/dwarf_dump.h | 4 +- src/dwarf/dwarf_parse.c | 351 +++++++++- src/dwarf/dwarf_parse.h | 72 ++- src/dwarf/dwarf_unwind.c | 1314 ++++++++------------------------------ src/dwarf/dwarf_unwind.h | 178 ++---- src/eh/eh_frame.c | 157 +++++ src/eh/eh_frame.h | 7 + 10 files changed, 1198 insertions(+), 1376 deletions(-) diff --git a/src/dwarf/dwarf.c b/src/dwarf/dwarf.c index 6063f0d7..508c2594 100644 --- a/src/dwarf/dwarf.c +++ b/src/dwarf/dwarf.c @@ -69,6 +69,31 @@ dw_reg_pos_from_code(Arch arch, DW_Reg reg_code) return max_U64; } +internal U64 +dw_reg_count_from_arch(Arch arch) +{ + switch (arch) { + default: { NotImplemented; } // fall-through + case Arch_Null: return 0; + case Arch_x86: return DW_RegX86_Last; + case Arch_x64: return DW_RegX64_Last; + } +} + +internal U64 +dw_reg_max_size_from_arch(Arch arch) +{ + local_persist U64 max_size = 0; + if (max_size == 0) { + U64 max_idx = dw_reg_count_from_arch(arch); + for EachIndex(reg_idx, max_idx) { + U64 reg_size = dw_reg_size_from_code(arch, reg_idx); + max_size = Max(max_size, reg_size); + } + } + return max_size; +} + internal DW_AttribClass dw_attrib_class_from_attrib_v2(DW_AttribKind k) { @@ -431,6 +456,71 @@ dw_push_count_from_expr_op(DW_ExprOp op) return 0; } +internal U64 +dw_operand_count_from_cfa_opcode(DW_CFA_Opcode opcode) +{ + switch (opcode) { +#define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return ArrayCount(t)-1; } + DW_CFA_Kind_XList(X) +#undef X + default: { NotImplemented; } break; + } + return 0; +} + +internal B32 +dw_is_cfa_expr_opcode_invalid(DW_ExprOp opcode) +{ + B32 is_invalid = 0; + switch (opcode) { + case DW_ExprOp_Addrx: + case DW_ExprOp_Call2: + case DW_ExprOp_Call4: + case DW_ExprOp_CallRef: + case DW_ExprOp_ConstType: + case DW_ExprOp_Constx: + case DW_ExprOp_Convert: + case DW_ExprOp_DerefType: + case DW_ExprOp_RegvalType: + case DW_ExprOp_Reinterpret: + case DW_ExprOp_PushObjectAddress: + case DW_ExprOp_CallFrameCfa: { + is_invalid = 1; + } break; + default: break; + } + return is_invalid; +} + +internal B32 +dw_is_new_row_cfa_opcode(DW_CFA_Opcode opcode) +{ + B32 is_new_row_op = 0; + switch (opcode) { + case DW_CFA_SetLoc: + case DW_CFA_AdvanceLoc: + case DW_CFA_AdvanceLoc1: + case DW_CFA_AdvanceLoc2: + case DW_CFA_AdvanceLoc4: { + is_new_row_op = 1; + } break; + default: break; + } + return is_new_row_op; +} + +internal DW_CFA_OperandType * +dw_operand_types_from_cfa_op(DW_CFA_Opcode opcode) +{ + switch (opcode) { +#define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return &t[0] + 1; } + DW_CFA_Kind_XList(X) +#undef X + default: { NotImplemented; } break; + } + return 0; +} + //////////////////////////////// //~ rjf: String <=> Enum @@ -717,12 +807,11 @@ dw_string_from_register(Arena *arena, Arch arch, U64 reg_id) } internal String8 -dw_string_from_cfa_opcode(DW_CFA cfa_opcode) +dw_string_from_cfa_opcode(DW_CFA_Opcode opcode) { - switch (cfa_opcode) { -#define X(_NAME, _ID) case _ID: return str8_lit(Stringify(_NAME)); - DW_CFA_Kind1_XList(X) - DW_CFA_Kind2_XList(X) + switch (opcode) { +#define X(_NAME, _ID, ...) case _ID: return str8_lit(Stringify(_NAME)); + DW_CFA_Kind_XList(X) #undef X default: InvalidPath; break; } diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index a0515bcc..4e844e75 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -1337,56 +1337,57 @@ typedef enum DW_LNCTEnum DW_LNCT_UserHi = 0x3fff } DW_LNCTEnum; -#define DW_CFA_Kind1_XList(X) \ -X(Nop, 0x0) \ -X(SetLoc, 0x1) \ -X(AdvanceLoc1, 0x2) \ -X(AdvanceLoc2, 0x3) \ -X(AdvanceLoc4, 0x4) \ -X(OffsetExt, 0x5) \ -X(RestoreExt, 0x6) \ -X(Undefined, 0x7) \ -X(SameValue, 0x8) \ -X(Register, 0x9) \ -X(RememberState, 0xA) \ -X(RestoreState, 0xB) \ -X(DefCfa, 0xC) \ -X(DefCfaRegister, 0xD) \ -X(DefCfaOffset, 0xE) \ -X(DefCfaExpr, 0xF) \ -X(Expr, 0x10) \ -X(OffsetExtSf, 0x11) \ -X(DefCfaSf, 0x12) \ -X(DefCfaOffsetSf, 0x13) \ -X(ValOffset, 0x14) \ -X(ValOffsetSf, 0x15) \ -X(ValExpr, 0x16) +//////////////////////////////// +// CFA -#define DW_CFA_Kind2_XList(X) \ -X(AdvanceLoc, 0x40) \ -X(Offset, 0x80) \ -X(Restore, 0xC0) - -typedef U8 DW_CFA; -typedef enum DW_CFAEnum +typedef enum { -#define X(_N, _ID) DW_CFA_##_N = _ID, - DW_CFA_Kind1_XList(X) - DW_CFA_Kind2_XList(X) + DW_CFA_OperandType_Null, + DW_CFA_OperandType_Value, + DW_CFA_OperandType_Register, + DW_CFA_OperandType_Expression, +} DW_CFA_OperandType; + +// (opcode name, opcode id, operand count, operand types) +#define DW_CFA_Kind_XList(X) \ +X(Nop, 0x0) \ +X(SetLoc, 0x1, DW_CFA_OperandType_Value) \ +X(AdvanceLoc1, 0x2, DW_CFA_OperandType_Value) \ +X(AdvanceLoc2, 0x3, DW_CFA_OperandType_Value) \ +X(AdvanceLoc4, 0x4, DW_CFA_OperandType_Value) \ +X(OffsetExt, 0x5, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \ +X(RestoreExt, 0x6) \ +X(Undefined, 0x7, DW_CFA_OperandType_Register) \ +X(SameValue, 0x8, DW_CFA_OperandType_Register) \ +X(Register, 0x9, DW_CFA_OperandType_Register) \ +X(RememberState, 0xa) \ +X(RestoreState, 0xb) \ +X(DefCfa, 0xc, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \ +X(DefCfaRegister, 0xd, DW_CFA_OperandType_Register) \ +X(DefCfaOffset, 0xe, DW_CFA_OperandType_Value) \ +X(DefCfaExpr, 0xf, DW_CFA_OperandType_Expression) \ +X(Expr, 0x10, DW_CFA_OperandType_Expression) \ +X(OffsetExtSf, 0x11, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \ +X(DefCfaSf, 0x12, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \ +X(DefCfaOffsetSf, 0x13, DW_CFA_OperandType_Value) \ +X(ValOffset, 0x14, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \ +X(ValOffsetSf, 0x15, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \ +X(ValExpr, 0x16, DW_CFA_OperandType_Register, DW_CFA_OperandType_Expression) \ +X(AdvanceLoc, 0x40, DW_CFA_OperandType_Value) \ +X(Offset, 0x80, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \ +X(Restore, 0xc0, DW_CFA_OperandType_Register) + +#define DW_CFA_OperandMax 2 +#define DW_CFA_Mask_OpcodeHi 0xc0 +#define DW_CFA_Mask_Operand 0x3f + +typedef U8 DW_CFA_Opcode; +typedef enum DW_CFA_Enum +{ +#define X(_N, _ID, ...) DW_CFA_##_N = _ID, + DW_CFA_Kind_XList(X) #undef X - - DW_CFA_OplKind1 = DW_CFA_ValExpr, - DW_CFA_OplKind2 = DW_CFA_Restore, -} DW_CFAEnum; - -typedef U8 DW_CFAMask; -enum -{ - // kind1: opcode: [0,5] zeroes:[6,7]; kind2: operand:[0,5] opcode:[6,7] - DW_CFAMask_OpcodeHi = 0xC0, - DW_CFAMask_Operand = 0x3F, - DW_CFAMask_Count = 2 -}; +} DW_CFA_Enum; //////////////////////////////// // Expression Opcodes @@ -1561,7 +1562,7 @@ X(RegvalType, 0xa5, 2, 0, 1) \ X(DerefType, 0xa6, 2, 1, 1) \ X(XDerefType, 0xa7, 2, 2, 1) \ X(Convert, 0xa8, 1, 1, 1) \ -X(ReInterpret, 0xa9, 1, 1, 1) +X(Reinterpret, 0xa9, 1, 1, 1) #define DW_Expr_GNU_XList(X) \ X(GNU_PushTlsAddress, 0xe0, 0, 0, 1) \ @@ -1589,7 +1590,7 @@ typedef enum DW_ExprOpEnum //- Regs -#define DW_Regs_X86_XList(X) \ +#define DW_Regs_X86_XList(X) \ X(Eax, 0, eax, 0, 4) \ X(Ecx, 1, ecx, 0, 4) \ X(Edx, 2, edx, 0, 4) \ @@ -1637,7 +1638,7 @@ X(Gs, 45, gs, 0, 2) \ X(Tr, 48, nil, 0, 0) \ X(Ldtr, 49, nil, 0, 0) -#define DW_Regs_X64_XList(X) \ +#define DW_Regs_X64_XList(X) \ X(Rax, 0, rax, 0, 8) \ X(Rdx, 1, rdx, 0, 8) \ X(Rcx, 2, rcx, 0, 8) \ @@ -1723,6 +1724,7 @@ typedef enum DW_RegX86Enum #define X(_N,_ID,...) DW_RegX86_##_N = _ID, DW_Regs_X86_XList(X) #undef X + DW_RegX86_Last } DW_RegX86Enum; typedef DW_Reg DW_RegX64; @@ -1731,6 +1733,7 @@ typedef enum DW_RegX64Enum #define X(_N,_ID,...) DW_RegX64_##_N = _ID, DW_Regs_X64_XList(X) #undef X + DW_RegX64_Last } DW_RegX64Enum; //////////////////////////////// @@ -1741,6 +1744,8 @@ internal U64 dw_reg_size_from_code_x64(DW_Reg reg_code); internal U64 dw_reg_pos_from_code_x64(DW_Reg reg_code); internal U64 dw_reg_size_from_code(Arch arch, DW_Reg reg_code); internal U64 dw_reg_pos_from_code(Arch arch, DW_Reg reg_code); +internal U64 dw_reg_max_size_from_arch(Arch arch); +internal U64 dw_reg_count_from_arch(Arch arch); //- Attrib Class Encodings @@ -1781,6 +1786,16 @@ internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, B internal U64 dw_pick_default_lower_bound(DW_Language lang); internal U64 dw_operand_count_from_expr_op(DW_ExprOp op); +internal U64 dw_pop_count_from_expr_op(DW_ExprOp op); +internal U64 dw_push_count_from_expr_op(DW_ExprOp op); + +//////////////////////////////// +//~ CFA + +internal U64 dw_operand_count_from_cfa_opcode(DW_CFA_Opcode opcode); +internal B32 dw_is_cfa_expr_opcode_invalid(DW_ExprOp opcode); +internal B32 dw_is_new_row_cfa_opcode(DW_CFA_Opcode opcode); +internal DW_CFA_OperandType * dw_operand_types_from_cfa_op(DW_CFA_Opcode opcode); //////////////////////////////// //~ rjf: String <=> Enum @@ -1801,6 +1816,6 @@ internal String8 dw_string_from_loc_list_entry_kind(Arena *arena, DW_LLE kind); internal String8 dw_string_from_section_kind(Arena *arena, DW_SectionKind kind); internal String8 dw_string_from_rng_list_entry_kind(Arena *arena, DW_RLE kind); internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id); -internal String8 dw_string_from_cfa_opcode(DW_CFA cfa_opcode); +internal String8 dw_string_from_cfa_opcode(DW_CFA_Opcodecfa_opcode); #endif // DWARF_H diff --git a/src/dwarf/dwarf_dump.c b/src/dwarf/dwarf_dump.c index 08f586a9..d18da87d 100644 --- a/src/dwarf/dwarf_dump.c +++ b/src/dwarf/dwarf_dump.c @@ -5,7 +5,7 @@ //~ rjf: Stringification Helpers internal String8 -dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off) +dw_string_from_reg_off(Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off) { Temp scratch = scratch_begin(&arena, 1); String8 reg_str = dw_string_from_register(scratch.arena, arch, reg_idx); @@ -19,6 +19,12 @@ dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off) return result; } +internal String8 +dw_string_from_reg(Arena *arena, Arch arch, DW_Reg reg_idx) +{ + return dw_string_from_reg_off(arena, arch, reg_idx, 0); +} + internal String8List dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) { @@ -337,166 +343,153 @@ dw_string_list_from_cfi_program(Arena *arena, DW_Ext ext, DW_Format format, U64 pc_begin, - DW_UnpackedCIE *cie, - DW_ReadCfiPtrFunc *read_cfi_ptr_func, - void *read_cfi_ptr_ud, + DW_CIE *cie, + DW_DecodePtr *decode_ptr_func, + void *deocde_ptr_ud, String8 program) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; + U64 reg_max = dw_reg_count_from_arch(arch); U64 pc = pc_begin; - for (U64 cursor = 0; cursor < program.size; ) { - DW_CFA opcode = 0; - cursor += str8_deserial_read_struct(program, cursor, &opcode); - - U64 operand = 0; - if ((opcode & DW_CFAMask_OpcodeHi) != 0) { - operand = opcode & DW_CFAMask_Operand; - opcode = opcode & DW_CFAMask_OpcodeHi; + for (U64 cursor = 0, inst_size; cursor < program.size; cursor += inst_size) { + // unpack instruction + DW_CFA_Inst inst = {0}; + DW_CFA_ParseErrorCode error_code = dw_parse_cfa_inst(str8_skip(program, cursor), cie->code_align_factor, cie->data_align_factor, 0, 0, &inst_size, &inst); + if (error_code == DW_CFA_ParseErrorCode_End) { break; } + if (error_code != DW_CFA_ParseErrorCode_NewInst) { + str8_list_pushf(arena, &list, "ERROR: failed to unpack CFA instruction @ 0x%I64", cursor); + break; } + // error check operands + DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst.opcode); + U64 operand_count = dw_operand_count_from_cfa_opcode(inst.opcode); + for EachIndex(operand_idx, operand_count) { + switch (operand_types[operand_idx]) { + case DW_CFA_OperandType_Null: break; + case DW_CFA_OperandType_Value: break; + case DW_CFA_OperandType_Register: { + if (inst.operands[operand_idx].u64 >= reg_max) { + str8_list_pushf(arena, &list, "ERROR: DW_CFA_%S @ 0x%I64x has an invalid register", + dw_string_from_cfa_opcode(inst.opcode), + cursor); + } + } break; + case DW_CFA_OperandType_Expression: { + DW_Expr expr = dw_expr_from_data(scratch.arena, format, cie->address_size, inst.operands[operand_idx].block); + for EachNode(inst, DW_ExprInst, expr.first) { + if (dw_is_cfa_expr_opcode_invalid(inst->opcode)) { + String8 expr_opcode_str = dw_string_from_expr_op(scratch.arena, ver, ext, inst->opcode); + str8_list_pushf(arena, &list, "ERROR: Exrepssion in DW_CFA_%S @ 0x%I64x has an invalid opcode DW_ExprOp_%S", expr_opcode_str); + } + } + } break; + default: { InvalidPath; } break; + } + } + + // format operands String8 operand_str = str8_lit("???"); - switch (opcode) { + switch (inst.opcode) { case DW_CFA_Nop: { operand_str = str8_zero(); } break; case DW_CFA_SetLoc: { - U64 address = 0; - cursor += read_cfi_ptr_func(program, cursor, read_cfi_ptr_ud, &address); - operand_str = str8f(arena, "0x%X", address); + operand_str = str8f(arena, "0x%X", inst.operands[0].u64); + pc = inst.operands[0].u64; } break; case DW_CFA_AdvanceLoc1: { - U8 delta = 0; - cursor += str8_deserial_read_struct(program, cursor, &delta); - delta *= cie->code_align_factor; + U64 delta = inst.operands[0].u64; pc += delta; - operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc); + operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); } break; case DW_CFA_AdvanceLoc2: { - U16 delta = 0; - cursor += str8_deserial_read_struct(program, cursor, &delta); - delta *= cie->code_align_factor; + U64 delta = inst.operands[0].u64; pc += delta; - operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc); + operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); } break; case DW_CFA_AdvanceLoc4: { - U32 delta = 0; - cursor += str8_deserial_read_struct(program, cursor, &delta); - delta *= cie->code_align_factor; + U64 delta = inst.operands[0].u64; pc += delta; - operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc); + operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); } break; case DW_CFA_OffsetExt: { - U64 reg = 0, offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - cursor += str8_deserial_read_uleb128(program, cursor, &offset); - operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, (S64)offset * cie->data_align_factor)); + U64 reg = inst.operands[0].u64; + S64 offset = (S64)inst.operands[1].u64; + operand_str = dw_string_from_reg_off(arena, arch, reg, offset); } break; case DW_CFA_RestoreExt: { operand_str = str8_zero(); } break; case DW_CFA_Undefined: { - U64 reg = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - operand_str = str8f(arena, "%I64u", reg); + operand_str = str8f(arena, "%I64u", inst.operands[0].u64); } break; case DW_CFA_SameValue: { - U64 reg = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, 0)); + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); } break; case DW_CFA_Register: { - U64 reg = 0, offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - cursor += str8_deserial_read_uleb128(program, cursor, &offset); - operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, (S64)offset)); + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].u64); } break; case DW_CFA_RememberState: { operand_str = str8_zero(); } break; case DW_CFA_RestoreState: { operand_str = str8_zero(); } break; case DW_CFA_DefCfa: { - U64 reg = 0, offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - cursor += str8_deserial_read_uleb128(program, cursor, &offset); - operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, offset)); + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].u64); } break; case DW_CFA_DefCfaRegister: { - U64 reg = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, 0)); + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); } break; case DW_CFA_DefCfaOffset: { - U64 offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, &offset); - operand_str = str8f(arena, "+%I64u", offset); + operand_str = str8f(arena, "+%I64u", inst.operands[0].u64); } break; case DW_CFA_DefCfaExpr: { - U64 expr_size = 0; - cursor += str8_deserial_read_uleb128(program, cursor, &expr_size); - String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size)); - String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format); - operand_str = str8f(arena, "%S", expr_str); + operand_str = dw_string_from_expression(arena, inst.operands[0].block, cu_base, cie->address_size, arch, ver, ext, format); } break; case DW_CFA_Expr: { - U64 reg = 0, expr_size = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - cursor += str8_deserial_read_uleb128(program, cursor, &expr_size); - String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size)); - String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, 0); - String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format); + String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, inst.operands[0].u64, 0); + String8 expr_str = dw_string_from_expression(scratch.arena, inst.operands[1].block, cu_base, cie->address_size, arch, ver, ext, format); operand_str = str8f(arena, "%S expression %S", reg_str, expr_str); } break; case DW_CFA_OffsetExtSf: { - U64 reg = 0; S64 offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - cursor += str8_deserial_read_sleb128(program, cursor, &offset); - String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, offset * cie->data_align_factor); - operand_str = str8f(arena, "%S", reg_str); + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].s64); } break; case DW_CFA_DefCfaSf: { - U64 reg = 0; S64 offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, ®); - cursor += str8_deserial_read_sleb128(program, cursor, &offset); - String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, offset * cie->data_align_factor); - operand_str = str8f(arena, "%S", reg_str); + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].s64); } break; + case DW_CFA_DefCfaOffsetSf: { operand_str = str8_zero(); } break; case DW_CFA_ValOffset: { - U64 val = 0, offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, &val); - cursor += str8_deserial_read_uleb128(program, cursor, &offset); - operand_str = str8f(arena, "value 0x%llx, offset %+I64d", val, offset); + operand_str = str8f(arena, "value 0x%llx, offset %+I64d", inst.operands[0].u64, inst.operands[1].u64); } break; case DW_CFA_ValOffsetSf: { - U64 val = 0; S64 offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, &val); - cursor += str8_deserial_read_sleb128(program, cursor, &offset); - operand_str = str8f(arena, "value %llu, offset %+I64d", val, offset); + operand_str = str8f(arena, "value %llu, offset %+I64d", inst.operands[0].u64, inst.operands[1].s64); } break; case DW_CFA_ValExpr: { - U64 val = 0; U64 expr_size = 0; - cursor += str8_deserial_read_uleb128(program, cursor, &val); - cursor += str8_deserial_read_uleb128(program, cursor, &expr_size); - String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size)); - String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format); - operand_str = str8f(arena, "value +%I64u, expression %S", val, expr_str); + String8 expr_str = dw_string_from_expression(scratch.arena, inst.operands[1].block, cu_base, cie->address_size, arch, ver, ext, format); + operand_str = str8f(arena, "value +%I64u, expression %S", inst.operands[0].u64, expr_str); } break; case DW_CFA_AdvanceLoc: { - U64 delta = operand * cie->code_align_factor; + U64 delta = inst.operands[0].u64; pc += delta; - operand_str = str8f(arena, "+%I64u; PC 0x%I64x", delta, pc); + operand_str = str8f(arena, "+%I64u `PC 0x%I64x`", delta, pc); } break; case DW_CFA_Offset: { - U64 offset = 0; - cursor += str8_deserial_read_uleb128(program, cursor, &offset); - S64 v = (S64)offset * cie->data_align_factor; - operand_str = dw_string_from_reg_off(scratch.arena, arch, operand, v); + U64 reg = inst.operands[0].u64; + S64 offset = (S64)inst.operands[1].u64; + operand_str = dw_string_from_reg_off(arena, arch, reg, offset); } break; case DW_CFA_Restore: { - String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, operand, 0); - operand_str = str8f(arena, "%S", reg_str); + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); } break; - default: { NotImplemented; } break; + default: { + str8_list_pushf(arena, &list, "ERROR: unknown CFA opcode 0x%I64u", inst.opcode); + } goto exit; } - str8_list_pushf(arena, &list, "DW_CFA_%S: %S", dw_string_from_cfa_opcode(opcode), operand_str); + if (operand_str.size) { + str8_list_pushf(arena, &list, "DW_CFA_%S: %S", dw_string_from_cfa_opcode(inst.opcode), operand_str); + } else { + str8_list_pushf(arena, &list, "DW_CFA_%S", dw_string_from_cfa_opcode(inst.opcode)); + } } +exit:; scratch_end(scratch); return list; } @@ -514,7 +507,7 @@ dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_bas #if 0 internal String8 -dw_string_from_eh_ptr_enc(Arena *arena, EH_PtrEnc enc) +w_string_from_eh_ptr_enc(Arena *arena, EH_PtrEnc enc) { U8 type = enc & EH_PtrEnc_TypeMask; String8 type_str = str8_lit("NULL"); @@ -549,7 +542,7 @@ internal void dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx) { Temp scratch = scratch_begin(&arena, 1); - DW_UnpackedCIE cie = {0}; + DW_CIE cie = {0}; for (U64 cursor = 0; cursor < raw_eh_frame.size; ) { U64 header_offset = cursor; @@ -592,7 +585,7 @@ dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh } // FDE else { - DW_UnpackedFDE fde = {0}; + DW_FDE fde = {0}; dw_unwind_parse_fde_x64(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), ptr_ctx, &cie, 0, &fde); cfi_range = fde.cfi_range; @@ -2166,11 +2159,11 @@ dw_dump_list_from_sections(Arena *arena, if (desc.type == DW_DescriptorEntryType_CIE) { String8 raw_cie = str8_substr(debug_frame, desc.entry_range); U64 restore_pos = arena_pos(scratch.arena); - DW_UnpackedCIE *cie = push_array(scratch.arena, DW_UnpackedCIE, 1); - if (dw_unpack_cie(raw_cie, desc.format, arch, cie)) { + DW_CIE *cie = push_array(scratch.arena, DW_CIE, 1); + if (dw_parse_cie(raw_cie, desc.format, arch, cie)) { hash_table_push_u64_raw(scratch.arena, cie_ht, cursor, cie); } else { - arena_pop_to(arena, restore_pos); + arena_pop_to(scratch.arena, restore_pos); } } } @@ -2182,9 +2175,9 @@ dw_dump_list_from_sections(Arena *arena, switch (desc.type) { case DW_DescriptorEntryType_Null: {} break; case DW_DescriptorEntryType_CIE: { - DW_UnpackedCIE cie = {0}; - if (dw_unpack_cie(raw_desc, desc.format, arch, &cie)) { - String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, cie.format, 0, &cie, dw_read_cfi_ptr, &cie, cie.init_insts); + DW_CIE cie = {0}; + if (dw_parse_cie(raw_desc, desc.format, arch, &cie)) { + String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, cie.format, 0, &cie, dw_decode_ptr_debug_frame, &cie, cie.insts); dumpf("CIE: // entry range: %r\n", desc.entry_range); dumpf("{\n"); @@ -2193,7 +2186,7 @@ dw_dump_list_from_sections(Arena *arena, dumpf(" Aug string: %S\n", cie.aug_string.size ? cie.aug_string : str8_lit("None")); dumpf(" Code align: %I64u\n", cie.code_align_factor); dumpf(" Data align: %I64d\n", cie.data_align_factor); - dumpf(" Return addr reg: %S\n", dw_string_from_register(scratch.arena, arch, cie.ret_addr_reg)); + dumpf(" Return addr reg: %u\n", cie.ret_addr_reg); if (cie.version > DW_Version_3) { dumpf(" Address size: %u\n", cie.address_size); dumpf(" Segment selector size: %u\n", cie.segment_selector_size); @@ -2208,10 +2201,13 @@ dw_dump_list_from_sections(Arena *arena, } } break; case DW_DescriptorEntryType_FDE: { - DW_UnpackedFDE fde = {0}; - if (dw_unpack_fde(raw_desc, desc.format, dwarf_dump_cie_from_offset, cie_ht, &fde)) { - DW_UnpackedCIE *cie = hash_table_search_u64_raw(cie_ht, fde.cie_pointer); - String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, fde.format, fde.pc_range.min, cie, dw_read_cfi_ptr, cie, fde.insts); + DW_FDE fde = {0}; + if (dw_parse_fde(raw_desc, desc.format, dwarf_dump_cie_from_offset, cie_ht, &fde)) { + DW_Version version = DW_Version_5; + DW_Ext ext = DW_Ext_All; + + DW_CIE *cie = hash_table_search_u64_raw(cie_ht, fde.cie_pointer); + String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, version, ext, fde.format, fde.pc_range.min, cie, dw_decode_ptr_debug_frame, cie, fde.insts); dumpf("FDE: // entry range: %r\n", desc.entry_range, dw_string_from_format(fde.format), fde.cie_pointer, fde.pc_range); dumpf("{\n"); @@ -2224,6 +2220,63 @@ dw_dump_list_from_sections(Arena *arena, for EachNode(n, String8Node, insts_str_list.first) { dumpf(" %S\n", n->string); } dumpf(" }\n"); } + + dumpf(" Unwind:\n"); + dumpf(" {\n"); + DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, cie, &fde, dw_decode_ptr_debug_frame, cie); + do { + String8 cfa_str = str8_lit("???"); + DW_CFA cfa = cfi_unwind->row->cfa; + switch (cfa.rule) { + case DW_CFA_Rule_Null: {} break; + case DW_CFA_Rule_RegOff: { cfa_str = dw_string_from_reg_off(scratch.arena, arch, cfa.reg, cfa.off); } break; + case DW_CFA_Rule_Expression: { cfa_str = dw_string_from_expression(scratch.arena, cfa.expr, max_U64, cie->address_size, arch, version, ext, fde.format); } break; + default: { InvalidPath; } break; + } + + String8 cfi_regs_str = {0}; + { + String8List cfi_regs_list = {0}; + for EachIndex(reg_idx, cfi_unwind->reg_count) { + DW_CFI_Register *cfi_reg = &cfi_unwind->row->regs[reg_idx]; + String8 rule_str = str8_lit("???"); + switch (cfi_reg->rule) { + case DW_CFI_RegisterRule_Undefined: { + rule_str = str8f(scratch.arena, "Undefined(%S)", dw_string_from_reg(scratch.arena, arch, cfi_reg->n)); + } break; + case DW_CFI_RegisterRule_SameValue: { + rule_str = str8_zero(); + } break; + case DW_CFI_RegisterRule_Offset: { + rule_str = str8f(scratch.arena, "[CFA%+I64d]", cfi_reg->n); + } break; + case DW_CFI_RegisterRule_ValOffset: { + rule_str = str8f(scratch.arena, "Val(CFA%+I64d)", cfi_reg->n); + } break; + case DW_CFI_RegisterRule_Expression: { + rule_str = str8f(scratch.arena, "Expression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, cie->address_size, arch, version, ext, fde.format)); + } break; + case DW_CFI_RegisterRule_ValExpression: { + rule_str = str8f(scratch.arena, "ValExpression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, cie->address_size, arch, version, ext, fde.format)); + } break; + case DW_CFI_RegisterRule_Architectural: { + rule_str = str8_lit("???"); + } break; + default: { InvalidPath; } break; + } + + if (rule_str.size) { + str8_list_pushf(scratch.arena, &cfi_regs_list, "%S: %S", dw_string_from_reg(scratch.arena, arch, reg_idx), rule_str); + } + } + + cfi_regs_str = str8_list_join(scratch.arena, &cfi_regs_list, &(StringJoin){.sep=str8_lit(", ")}); + } + + dumpf(" { PC: 0x%I64x, CFA: %-7S, Rules: { %S }\n", cfi_unwind->pc, cfa_str, cfi_regs_str); + } while (dw_cfi_next_row(scratch.arena, cfi_unwind)); + dumpf(" }\n"); + dumpf("}\n"); } else { dumpf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min); diff --git a/src/dwarf/dwarf_dump.h b/src/dwarf/dwarf_dump.h index 9e673a71..0882061b 100644 --- a/src/dwarf/dwarf_dump.h +++ b/src/dwarf/dwarf_dump.h @@ -58,13 +58,13 @@ read_only global String8 dw_name_title_from_dump_subset_table[] = //////////////////////////////// //~ rjf: Stringification Helpers -internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off); +internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off); internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); internal String8 dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); internal String8 dw_string_from_eh_ptr_enc (Arena *arena, EH_PtrEnc enc); #if 0 -internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_UnpackedCIE *cie, EH_PtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); +internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIE *cie, EH_PtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx); internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index 89cf0292..ae6d8741 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -3323,15 +3323,30 @@ dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data) return expr; } -internal -DW_READ_CFI_PTR(dw_read_cfi_ptr) +internal void +dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n) +{ + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal DW_CFA_InstNode * +dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v) +{ + DW_CFA_InstNode *n = push_array(arena, DW_CFA_InstNode, 1); + n->v = v; + dw_cfa_inst_list_push_node(list, n); + return n; +} + +internal U64 +dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out) { - DW_UnpackedCIE *cie = ud; U64 read_size = 0; if (cie->segment_selector_size) { NotImplemented; } else { - read_size = str8_deserial_read(data, off, ptr_out, cie->address_size, cie->address_size); + read_size = str8_deserial_read(data, 0, ptr_out, cie->address_size, cie->address_size); } return read_size; } @@ -3347,10 +3362,10 @@ dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc U64 length_size = str8_deserial_read_dwarf_packed_size(data, off, &length); if (length_size == 0) { goto exit; } - Rng1U64 entry_range = rng_1u64(off + length_size, off + length_size + length); + Rng1U64 entry_range = rng_1u64(off, off + length_size + length); String8 entry_data = str8_substr(data, entry_range); U64 id = 0; - U64 id_size = str8_deserial_read_dwarf_uint(entry_data, 0, format, &id); + U64 id_size = str8_deserial_read_dwarf_uint(entry_data, length_size, format, &id); if (id_size == 0) { goto exit; } U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64; @@ -3363,10 +3378,10 @@ exit:; } internal B32 -dw_unpack_cie(String8 data, DW_Format format, Arch arch, DW_UnpackedCIE *cie_out) +dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out) { B32 is_parsed = 0; - U64 cursor = 0; + U64 cursor = format == DW_Format_32Bit ? 4 : 12; U64 cie_id = 0; U64 cie_id_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id); @@ -3416,11 +3431,12 @@ dw_unpack_cie(String8 data, DW_Format format, Arch arch, DW_UnpackedCIE *cie_out if (aug_string.size > 0) { goto exit; } - cie_out->init_insts = str8_skip(data, cursor); + cie_out->insts = str8_skip(data, cursor); cie_out->aug_string = aug_string; cie_out->code_align_factor = code_align_factor; cie_out->data_align_factor = data_align_factor; cie_out->ret_addr_reg = ret_addr_reg; + cie_out->format = format; cie_out->version = version; cie_out->address_size = address_size; cie_out->segment_selector_size = segment_selector_size; @@ -3431,14 +3447,14 @@ exit:; } internal B32 -dw_unpack_fde(String8 data, +dw_parse_fde(String8 data, DW_Format format, DW_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, - DW_UnpackedFDE *fde_out) + DW_FDE *fde_out) { B32 is_parsed = 0; - U64 cursor = 0; + U64 cursor = format == DW_Format_32Bit ? 4 : 12; // extract CIE pointer U64 cie_pointer = 0; @@ -3447,18 +3463,18 @@ dw_unpack_fde(String8 data, cursor += cie_pointer_size; // map offset -> CIE - DW_UnpackedCIE *cie = cie_from_offset_func(cie_from_offset_ud, cie_pointer); + DW_CIE *cie = cie_from_offset_func(cie_from_offset_ud, cie_pointer); if (cie == 0) { goto exit; } // extract address of first instruction U64 pc_begin = 0; - U64 pc_begin_size = dw_read_cfi_ptr(data, cursor, cie, &pc_begin); + U64 pc_begin_size = dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_begin); if (pc_begin_size == 0) { goto exit; } cursor += pc_begin_size; // extract instruction range size U64 pc_range = 0; - U64 pc_range_size = dw_read_cfi_ptr(data, cursor, cie, &pc_range); + U64 pc_range_size = dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_range); if (pc_range_size == 0) { goto exit; } cursor += pc_range_size; @@ -3477,3 +3493,308 @@ exit:; return is_parsed; } +internal DW_CFA_ParseErrorCode +dw_parse_cfa_inst(String8 data, + U64 code_align_factor, + S64 data_align_factor, + DW_DecodePtr *decode_ptr_func, + void *decode_ptr_ud, + U64 *bytes_read_out, + DW_CFA_Inst *inst_out) +{ + *bytes_read_out = 0; + + DW_CFA_ParseErrorCode error_code = DW_CFA_ParseErrorCode_End; + U64 cursor = 0; + + // read opcode + DW_CFA_Opcode raw_opcode = 0; + U64 raw_opcode_size = str8_deserial_read_struct(data, cursor, &raw_opcode); + if (raw_opcode_size == 0) { goto exit; } + cursor += raw_opcode_size; + + // decode opcode implicit operand + U64 opcode = raw_opcode & ~DW_CFA_Mask_OpcodeHi; + U64 implicit_operand = 0; + if ((raw_opcode & DW_CFA_Mask_OpcodeHi) != 0) { + opcode = raw_opcode & DW_CFA_Mask_OpcodeHi; + implicit_operand = raw_opcode & DW_CFA_Mask_Operand; + } + + // decode operands + DW_CFA_Operand operands[DW_CFA_OperandMax] = {0}; + switch (opcode) { + case DW_CFA_SetLoc: { + U64 address_size = decode_ptr_func(str8_skip(data, cursor), decode_ptr_ud, &operands[0].u64); + if (address_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += address_size; + } break; + case DW_CFA_AdvanceLoc: { + operands[0].u64 = implicit_operand * code_align_factor; + } break; + case DW_CFA_AdvanceLoc1: { + U8 delta = 0; + U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); + if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += delta_size; + operands[0].u64 = delta * code_align_factor; + } break; + case DW_CFA_AdvanceLoc2: { + U16 delta = 0; + U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); + if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += delta_size; + operands[0].u64 = delta * code_align_factor; + } break; + case DW_CFA_AdvanceLoc4: { + U32 delta = 0; + U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); + if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + operands[0].u64 = delta * code_align_factor; + } break; + case DW_CFA_DefCfa: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = reg; + operands[1].u64 = offset; + } break; + case DW_CFA_DefCfaSf: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + S64 offset = 0; + U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = reg; + operands[1].s64 = offset * data_align_factor; + } break; + case DW_CFA_DefCfaRegister: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + operands[0].u64 = reg; + } break; + case DW_CFA_DefCfaOffset: { + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = offset; + } break; + case DW_CFA_DefCfaOffsetSf: { + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = offset * data_align_factor; + } break; + case DW_CFA_DefCfaExpr: { + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); + if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += expr_size_size; + + if (cursor + expr_size > data.size) { goto exit; } + String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); + + operands[0].block = expr; + cursor += expr_size; + } break; + case DW_CFA_Undefined: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + operands[0].u64 = reg; + } break; + case DW_CFA_SameValue: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + operands[0].u64 = reg; + } break; + case DW_CFA_Offset: { + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = implicit_operand; + operands[1].s64 = (S64)offset * data_align_factor; + } break; + case DW_CFA_OffsetExt: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = reg; + operands[1].u64 = offset * data_align_factor; + } break; + case DW_CFA_OffsetExtSf: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + S64 offset = 0; + U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = reg; + operands[1].s64 = offset * data_align_factor; + } break; + case DW_CFA_ValOffset: { + U64 val = 0; + U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); + if (val_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += val_size; + + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = val; + operands[1].u64 = offset * data_align_factor; + } break; + case DW_CFA_ValOffsetSf: { + U64 val = 0; + U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); + if (val_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += val_size; + + S64 offset = 0; + U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = val; + operands[1].s64 = offset; + } break; + case DW_CFA_Register: { + U64 dst_reg = 0; + U64 dst_reg_size = str8_deserial_read_uleb128(data, cursor, &dst_reg); + if (dst_reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += dst_reg_size; + + U64 src_reg = 0; + U64 src_reg_size = str8_deserial_read_uleb128(data, cursor, &src_reg); + if (src_reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += src_reg_size; + + operands[0].u64 = dst_reg; + operands[1].u64 = src_reg; + } break; + case DW_CFA_Expr: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); + if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += expr_size_size; + + if (cursor + expr_size > data.size) { goto exit; } + String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); + cursor += expr_size; + + operands[0].block = expr; + } break; + case DW_CFA_ValExpr: { + U64 val = 0; + U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); + if (val_size == 0) { goto exit; } + cursor += val_size; + + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); + if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += expr_size_size; + + if (cursor + expr_size > data.size) { goto exit; } + String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); + cursor += expr_size; + + operands[0].u64 = val; + operands[1].block = expr; + } break; + case DW_CFA_Restore: { + operands[0].u64 = implicit_operand; + } break; + case DW_CFA_RestoreExt: {} break; + case DW_CFA_RememberState: {} break; + case DW_CFA_RestoreState: {} break; + case DW_CFA_Nop: {} break; + default: { NotImplemented; goto exit; } break; + } + + // fill out output + inst_out->opcode = opcode; + MemoryCopyTyped(&inst_out->operands[0], &operands[0], DW_CFA_OperandMax); + + *bytes_read_out = cursor; + + error_code = DW_CFA_ParseErrorCode_NewInst; + +exit:; + return error_code; +} + +internal DW_CFA_InstList +dw_parse_cfa_inst_list(Arena *arena, + String8 data, + U64 code_align_factor, + S64 data_align_factor, + DW_DecodePtr *decode_ptr_func, + void *decode_ptr_ud) +{ + U64 pos = arena_pos(arena); + DW_CFA_InstList list = {0}; + for (U64 cursor = 0, inst_size;; cursor += inst_size) { + DW_CFA_Inst inst = {0}; + DW_CFA_ParseErrorCode error_code = dw_parse_cfa_inst(str8_skip(data, cursor), code_align_factor, data_align_factor, decode_ptr_func, decode_ptr_ud, &inst_size, &inst); + if (error_code == DW_CFA_ParseErrorCode_End) { break; } + if (error_code != DW_CFA_ParseErrorCode_NewInst) { + MemoryZeroStruct(&list); + arena_pop_to(arena, pos); + break; + } + dw_cfa_inst_list_push(arena, &list, inst); + } + return list; +} + +internal +DW_DECODE_PTR(dw_decode_ptr_debug_frame) +{ + return dw_read_debug_frame_ptr(data, ud, ptr_out); +} + diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index b22ac96f..c691c38b 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -370,9 +370,9 @@ typedef struct DW_DescriptorEntry Rng1U64 entry_range; } DW_DescriptorEntry; -typedef struct DW_UnpackedCIE +typedef struct DW_CIE { - String8 init_insts; + String8 insts; String8 aug_string; String8 aug_data; U64 code_align_factor; @@ -382,25 +382,55 @@ typedef struct DW_UnpackedCIE U8 version; U8 address_size; U8 segment_selector_size; - Rng1U64 cfi_range; -} DW_UnpackedCIE; +} DW_CIE; -typedef struct DW_UnpackedFDE +typedef struct DW_FDE { - DW_Format format; - U64 cie_pointer; - Rng1U64 pc_range; - String8 insts; - Rng1U64 cfi_range; -} DW_UnpackedFDE; + DW_Format format; + U64 cie_pointer; + Rng1U64 pc_range; + String8 insts; +} DW_FDE; -#define DW_READ_CFI_PTR(name) U64 name(String8 data, U64 off, void *ud, U64 *ptr_out) -typedef DW_READ_CFI_PTR(DW_ReadCfiPtrFunc); +typedef union DW_CFA_Operand +{ + U64 u64; + S64 s64; + String8 block; +} DW_CFA_Operand; -#define DW_CIE_FROM_OFFSET_FUNC(name) DW_UnpackedCIE * name(void *ud, U64 offset) +typedef enum +{ + DW_CFA_ParseErrorCode_NewInst, + DW_CFA_ParseErrorCode_End, + DW_CFA_ParseErrorCode_OutOfData +} DW_CFA_ParseErrorCode; + +typedef struct DW_CFA_Inst +{ + DW_CFA_Opcode opcode; + DW_CFA_Operand operands[DW_CFA_OperandMax]; +} DW_CFA_Inst; + +typedef struct DW_CFA_InstNode +{ + DW_CFA_Inst v; + struct DW_CFA_InstNode *next; +} DW_CFA_InstNode; + +typedef struct DW_CFA_InstList +{ + U64 count; + DW_CFA_InstNode *first; + DW_CFA_InstNode *last; +} DW_CFA_InstList; + +#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out) +typedef DW_DECODE_PTR(DW_DecodePtr); + +#define DW_CIE_FROM_OFFSET_FUNC(name) DW_CIE * name(void *ud, U64 offset) typedef DW_CIE_FROM_OFFSET_FUNC(DW_CIEFromOffsetFunc); - // hasher internal U64 dw_hash_from_string(String8 string); @@ -520,8 +550,16 @@ internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size // debug frame +internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n); +internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v); + +internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out); + internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out); -internal B32 dw_unpack_cie(String8 data, DW_Format format, Arch arch, DW_UnpackedCIE *cie_out); -internal B32 dw_unpack_fde(String8 data, DW_Format format, DW_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, DW_UnpackedFDE *fde_out); +internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out); +internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, DW_FDE *fde_out); + +internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out); +internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud); #endif // DWARF_PARSE_H diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index 5165da1f..6946d114 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -1,1072 +1,274 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal U64 dw_based_range_read(void *base, Rng1U64 range, U64 off, U64 size, void *out) { return 0; } -internal U64 dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 off, U64 *out) { return 0; } -internal U64 dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 off, S64 *out) { return 0; } -internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 off, U64 *out) { return 0; } - -//////////////////////////////// -// x64 Unwind Function - -internal DW_UnwindResult -dw_unwind_x64(String8 raw_text, - String8 raw_eh_frame, - String8 raw_eh_frame_hdr, - Rng1U64 text_vrange, - Rng1U64 eh_frame_vrange, - Rng1U64 eh_frame_hdr_vrange, - U64 default_image_base, - U64 image_base, - U64 stack_pointer, - DW_RegsX64 *regs, - DW_ReadMemorySig *read_memory, - void *read_memory_ud) +internal DW_CFA_Row * +dw_make_cfa_row(Arena *arena, U64 reg_count) { - // TODO: What if ELF has two sections with instructions and pointer is ecnoded relative to .text2? - Temp scratch = scratch_begin(0, 0); - - DW_UnwindResult result = {0}; - - dw_unwind_init_x64(); - - // rebase - U64 rebase_voff_to_vaddr = (image_base - default_image_base); - - // get ip register values - U64 ip_value = regs->rip; - U64 ip_voff = ip_value - rebase_voff_to_vaddr; - - // check sections - B32 has_needed_sections = (raw_text.size > 0 && raw_eh_frame.size > 0); - if (!has_needed_sections) { - result.is_invalid = 1; + DW_CFA_Row *row = push_array(arena, DW_CFA_Row, 1); + row->regs = push_array(arena, DW_CFI_Register, reg_count); + for EachIndex(reg_idx, reg_count) { + row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue; } - - //- get frame info range - void *frame_base = raw_eh_frame.str; - Rng1U64 frame_range = rng_1u64(0, raw_eh_frame.size); - - //- section vaddrs - U64 text_base_vaddr = text_vrange.min + rebase_voff_to_vaddr; - U64 frame_base_voff = text_vrange.min; - U64 data_base_vaddr = eh_frame_hdr_vrange.min + rebase_voff_to_vaddr; - - //- find cfi records - DW_CFIRecords cfi_recs = {0}; - if (has_needed_sections) { - EH_PtrCtx ptr_ctx = {0}; - ptr_ctx.raw_base_vaddr = frame_base_voff; - ptr_ctx.text_vaddr = text_base_vaddr; - ptr_ctx.data_vaddr = data_base_vaddr; - ptr_ctx.func_vaddr = 0; - if (raw_eh_frame_hdr.size) { - cfi_recs = dw_unwind_eh_frame_hdr_from_ip_fast_x64(raw_eh_frame, raw_eh_frame_hdr, &ptr_ctx, ip_voff); - } else { - cfi_recs = dw_unwind_eh_frame_cfi_from_ip_slow_x64(raw_eh_frame, &ptr_ctx, ip_voff); - } - } - - //- check cfi records - if (!cfi_recs.valid) { - result.is_invalid = 1; - } - - //- cfi machine setup - DW_CFIMachine machine = {0}; - if (cfi_recs.valid) { - EH_PtrCtx ptr_ctx = {0}; - ptr_ctx.raw_base_vaddr = frame_base_voff; - ptr_ctx.text_vaddr = text_base_vaddr; - ptr_ctx.data_vaddr = data_base_vaddr; - ptr_ctx.func_vaddr = cfi_recs.fde.pc_range.min + rebase_voff_to_vaddr; // TODO: it's not super clear how to set up this member, need more test cases - machine = dw_unwind_make_machine_x64(DW_UNWIND_X64__REG_SLOT_COUNT, &cfi_recs.cie, &ptr_ctx); - } - - // initial row - DW_CFIRow *init_row = 0; - if (cfi_recs.valid) { - Rng1U64 init_cfi_range = cfi_recs.cie.cfi_range; - DW_CFIRow *row = dw_unwind_row_alloc_x64(scratch.arena, machine.cells_per_row); - if (dw_unwind_machine_run_to_ip_x64(frame_base, init_cfi_range, &machine, max_U64, row)) { - init_row = row; - } - if (init_row == 0) { - result.is_invalid = 1; - } - } - - // main row - DW_CFIRow *main_row = 0; - if (init_row != 0) { - // upgrade machine with new equipment - dw_unwind_machine_equip_initial_row_x64(&machine, init_row); - dw_unwind_machine_equip_fde_ip_x64(&machine, cfi_recs.fde.pc_range.min); - - // decode main row - Rng1U64 main_cfi_range = cfi_recs.fde.cfi_range; - DW_CFIRow *row = dw_unwind_row_alloc_x64(scratch.arena, machine.cells_per_row); - if (dw_unwind_machine_run_to_ip_x64(frame_base, main_cfi_range, &machine, ip_value, row)) { - main_row = row; - } - if (main_row == 0) { - result.is_invalid = 1; - } - } - - // apply main row to modify the registers - if (main_row != 0) { - result = dw_unwind_x64__apply_frame_rules(raw_eh_frame, main_row, text_base_vaddr, read_memory, read_memory_ud, stack_pointer, regs); - } - + return row; +} + +internal DW_CFA_Row * +dw_copy_cfa_row(Arena *arena, U64 reg_count, DW_CFA_Row *row) +{ + DW_CFA_Row *new_row = dw_make_cfa_row(arena, reg_count); + new_row->cfa = row->cfa; + MemoryCopyTyped(new_row->regs, row->regs, reg_count); + return new_row; +} + +internal DW_CFI_Unwind * +dw_cfi_unwind_init(Arena *arena, + Arch arch, + DW_CIE *cie, + DW_FDE *fde, + DW_DecodePtr *decode_ptr_func, + void *decode_ptr_ud) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1); + uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud); + uw->cie = cie; + uw->fde = fde; + uw->reg_count = dw_reg_count_from_arch(arch); + uw->pc = fde->pc_range.min; + uw->arch = arch; + + // setup initial register rules + DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud); + uw->row = dw_make_cfa_row(arena, uw->reg_count); + uw->curr_inst = initial_insts.first; + dw_cfi_next_row(arena, uw); + + // make first row from initial rules + uw->initial_row = uw->row; + uw->row = dw_copy_cfa_row(arena, uw->reg_count, uw->initial_row); + uw->curr_inst = uw->insts.first; + scratch_end(scratch); - return result; -} - -internal DW_UnwindResult -dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, - DW_CFIRow *row, - U64 text_base_vaddr, - DW_ReadMemorySig *read_memory, - void *read_memory_ud, - U64 stack_pointer, - DW_RegsX64 *regs) -{ - DW_UnwindResult result = {0}; - - U64 missed_read_addr = 0; - - //- setup a dwarf expression machine - DW_ExprMachineConfig dwexpr_config = {0}; - dwexpr_config.max_step_count = 0xFFFF; - dwexpr_config.read_memory = read_memory; - dwexpr_config.read_memory_ud = read_memory_ud; - dwexpr_config.regs = regs; - dwexpr_config.text_section_base = &text_base_vaddr; - - //- compute cfa - U64 cfa = 0; - switch (row->cfa_cell.rule) { - case DW_CFI_CFA_Rule_RegOff: { - // TODO: have we done anything to gaurantee reg_idx here? - U64 reg_idx = row->cfa_cell.reg_idx; - - // is this a roll-over CFA? - B32 is_roll_over_cfa = 0; - if (reg_idx == DW_RegX64_Rsp) { - DW_CFIRegisterRule rule = row->cells[reg_idx].rule; - if (rule == DW_CFIRegisterRule_Undefined || rule == DW_CFIRegisterRule_SameValue) { - is_roll_over_cfa = 1; - } - } - - // compute cfa - if (is_roll_over_cfa) { - cfa = stack_pointer + row->cfa_cell.offset; - } else { - cfa = regs->r[reg_idx] + row->cfa_cell.offset; - } - } break; - - case DW_CFI_CFA_Rule_Expr: { - Rng1U64 expr_range = row->cfa_cell.expr; - DW_Location location = dw_expr__eval(0, raw_eh_frame.str, expr_range, &dwexpr_config); - if (location.non_piece_loc.kind == DW_SimpleLocKind_Fail && location.non_piece_loc.fail_kind == DW_LocFailKind_MissingMemory) { - missed_read_addr = location.non_piece_loc.fail_data; - goto error_out; - } - if (location.non_piece_loc.kind == DW_SimpleLocKind_Address) { - cfa = location.non_piece_loc.addr; - } - } break; - } - - // compute registers - { - DW_CFICell *cell = row->cells; - DW_RegsX64 new_regs = {0}; - for (U64 i = 0; i < DW_UNWIND_X64__REG_SLOT_COUNT; ++i, ++cell) { - // compute value - U64 v = 0; - switch (cell->rule) { - default: - { - Assert(!"UNEXPECTED-RULE"); - } break; - - case DW_CFIRegisterRule_Undefined: - { - Assert(!"UNDEFINED"); - } break; - - case DW_CFIRegisterRule_SameValue: - { - v = regs->r[i]; - } break; - - case DW_CFIRegisterRule_Offset: - { - U64 addr = cfa + cell->n; - U64 read_size = read_memory(addr, sizeof(v), &v, read_memory_ud); - if (read_size != sizeof(v)) { - missed_read_addr = addr; - goto error_out; - } - } break; - - case DW_CFIRegisterRule_ValOffset: - { - v = cfa + cell->n; - } break; - - case DW_CFIRegisterRule_Register: - { - v = regs->r[i]; - } break; - - case DW_CFIRegisterRule_Expression: - { - Rng1U64 expr_range = cell->expr; - U64 addr = 0; - DW_Location location = dw_expr__eval(0, raw_eh_frame.str, expr_range, &dwexpr_config); - if (location.non_piece_loc.kind == DW_SimpleLocKind_Fail && location.non_piece_loc.fail_kind == DW_LocFailKind_MissingMemory) { - missed_read_addr = location.non_piece_loc.fail_data; - goto error_out; - } - if (location.non_piece_loc.kind == DW_SimpleLocKind_Address) { - addr = location.non_piece_loc.addr; - } - U64 read_size = read_memory(addr, sizeof(v), &v, read_memory_ud); - if (read_size != sizeof(v)) { - missed_read_addr = addr; - goto error_out; - } - } break; - - case DW_CFIRegisterRule_ValExpression: - { - Rng1U64 expr_range = cell->expr; - DW_Location location = dw_expr__eval(0, raw_eh_frame.str, expr_range, &dwexpr_config); - if (location.non_piece_loc.kind == DW_SimpleLocKind_Fail && location.non_piece_loc.fail_kind == DW_LocFailKind_MissingMemory) { - missed_read_addr = location.non_piece_loc.fail_data; - goto error_out; - } - if (location.non_piece_loc.kind == DW_SimpleLocKind_Address) { - v = location.non_piece_loc.addr; - } - } break; - } - - // commit value to output slot - new_regs.r[i] = v; - } - - // commit all new regs - MemoryCopy(regs, &new_regs, sizeof(new_regs)); - } - - //- save new stack pointer - result.stack_pointer = cfa; - - error_out:; - if (missed_read_addr) { - result.is_invalid = 1; - result.missed_read = 1; - result.missed_read_addr = missed_read_addr; - } - - return result; -} - -//////////////////////////////// -// Helper Functions - -internal void -dw_unwind_init_x64(void) -{ - local_persist B32 did_init = 0; - - if (!did_init) { - did_init = 1; - - // control bits tables - dw_unwind__cfa_control_bits_kind1[DW_CFA_Nop ] = 0x000; - dw_unwind__cfa_control_bits_kind1[DW_CFA_SetLoc ] = 0x809; - dw_unwind__cfa_control_bits_kind1[DW_CFA_AdvanceLoc1 ] = 0x801; - dw_unwind__cfa_control_bits_kind1[DW_CFA_AdvanceLoc2 ] = 0x802; - dw_unwind__cfa_control_bits_kind1[DW_CFA_AdvanceLoc4 ] = 0x804; - dw_unwind__cfa_control_bits_kind1[DW_CFA_OffsetExt ] = 0x2AA; - dw_unwind__cfa_control_bits_kind1[DW_CFA_RestoreExt ] = 0x20A; - dw_unwind__cfa_control_bits_kind1[DW_CFA_Undefined ] = 0x20A; - dw_unwind__cfa_control_bits_kind1[DW_CFA_SameValue ] = 0x20A; - dw_unwind__cfa_control_bits_kind1[DW_CFA_Register ] = 0x6AA; - dw_unwind__cfa_control_bits_kind1[DW_CFA_RememberState ] = 0x000; - dw_unwind__cfa_control_bits_kind1[DW_CFA_RestoreState ] = 0x000; - dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfa ] = 0x2AA; - dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaRegister ] = 0x20A; - dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaOffset ] = 0x00A; - dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaExpr ] = 0x00A; - dw_unwind__cfa_control_bits_kind1[DW_CFA_Expr ] = 0x2AA; - dw_unwind__cfa_control_bits_kind1[DW_CFA_OffsetExtSf ] = 0x2BA; - dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaSf ] = 0x2BA; - dw_unwind__cfa_control_bits_kind1[DW_CFA_DefCfaOffsetSf ] = 0x00B; - dw_unwind__cfa_control_bits_kind1[DW_CFA_ValOffset ] = 0x2AA; - dw_unwind__cfa_control_bits_kind1[DW_CFA_ValOffsetSf ] = 0x2BA; - dw_unwind__cfa_control_bits_kind1[DW_CFA_ValExpr ] = 0x2AA; - - dw_unwind__cfa_control_bits_kind2[DW_CFA_AdvanceLoc >> 6] = 0x800; - dw_unwind__cfa_control_bits_kind2[DW_CFA_Offset >> 6] = 0x10A; - dw_unwind__cfa_control_bits_kind2[DW_CFA_Restore >> 6] = 0x100; - } -} - -//- eh_frame parsing - -internal void -dw_unwind_parse_cie_x64(void *base, Rng1U64 range, EH_PtrCtx *ptr_ctx, U64 off, DW_UnpackedCIE *cie_out) -{ - NotImplemented; -#if 0 - MemoryZeroStruct(cie_out); - - // get version - U64 version_off = off; - U8 version = 0; - dw_based_range_read(base, range, version_off, 1, &version); - - // check version - if (version == 1 || version == 3) { - - // read augmentation - U64 augmentation_off = version_off + 1; - String8 augmentation = dw_based_range_read_string(base, range, augmentation_off); - - // read code align - U64 code_align_factor_off = augmentation_off + augmentation.size + 1; - U64 code_align_factor = 0; - U64 code_align_factor_size = dw_based_range_read_uleb128(base, range, code_align_factor_off, &code_align_factor); - - // read data align - U64 data_align_factor_off = code_align_factor_off + code_align_factor_size; - S64 data_align_factor = 0; - U64 data_align_factor_size = dw_based_range_read_sleb128(base, range, data_align_factor_off, &data_align_factor); - - // return address register - U64 ret_addr_reg_off = data_align_factor_off + data_align_factor_size; - U64 after_ret_addr_reg_off = 0; - U64 ret_addr_reg = 0; - if (version == 1) { - dw_based_range_read(base, range, ret_addr_reg_off, 1, &ret_addr_reg); - after_ret_addr_reg_off = ret_addr_reg_off + 1; - } else { - U64 ret_addr_reg_size = dw_based_range_read_uleb128(base, range, ret_addr_reg_off, &ret_addr_reg); - after_ret_addr_reg_off = ret_addr_reg_off + ret_addr_reg_size; - } - - // TODO: - // Handle "eh" param, it indicates presence of EH Data field. - // On 32bit arch it is a 4-byte and on 64-bit 8-byte value. - // Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html - // Reference doc doesn't clarify structure for EH Data though - - // check for augmentation data - U64 aug_size_off = after_ret_addr_reg_off; - U64 after_aug_size_off = after_ret_addr_reg_off; - B32 has_augmentation_size = 0; - U64 augmentation_size = 0; - if (augmentation.size > 0 && augmentation.str[0] == 'z') { - has_augmentation_size = 1; - U64 aug_size_size = dw_based_range_read_uleb128(base, range, aug_size_off, &augmentation_size); - after_aug_size_off += aug_size_size; - } - - // read augmentation data - U64 aug_data_off = after_aug_size_off; - U64 after_aug_data_off = after_aug_size_off; - - EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit; - U64 handler_ip = 0; - EH_PtrEnc addr_encoding = EH_PtrEnc_UData8; - - if (has_augmentation_size > 0) { - U64 aug_data_cursor = aug_data_off; - for (U8 *ptr = augmentation.str + 1, *opl = augmentation.str + augmentation.size; ptr < opl; ++ptr) { - switch (*ptr) { - case 'L': { - dw_based_range_read_struct(base, range, aug_data_cursor, &lsda_encoding); - aug_data_cursor += sizeof(lsda_encoding); - } break; - case 'P': { - EH_PtrEnc handler_encoding = EH_PtrEnc_Omit; - dw_based_range_read_struct(base, range, aug_data_cursor, &handler_encoding); - - U64 ptr_off = aug_data_cursor + sizeof(handler_encoding); - U64 ptr_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, handler_encoding, ptr_off, &handler_ip); - aug_data_cursor = ptr_off + ptr_size; - } break; - case 'R': { - dw_based_range_read_struct(base, range, aug_data_cursor, &addr_encoding); - aug_data_cursor += sizeof(addr_encoding); - } break; - default: { - goto dbl_break_aug; - } break; - } - } - dbl_break_aug:; - after_aug_data_off = aug_data_cursor; - } - - // cfi range - U64 cfi_off = range.min + after_aug_data_off; - U64 cfi_size = 0; - if (range.max > cfi_off) { - cfi_size = range.max - cfi_off; - } - - // commit values to out - cie_out->version = version; - - cie_out->lsda_encoding = lsda_encoding; - cie_out->addr_encoding = addr_encoding; - cie_out->has_augmentation_size = has_augmentation_size; - cie_out->augmentation_size = augmentation_size; - cie_out->augmentation = augmentation; - cie_out->code_align_factor = code_align_factor; - cie_out->data_align_factor = data_align_factor; - cie_out->ret_addr_reg = ret_addr_reg; - cie_out->handler_ip = handler_ip; - cie_out->cfi_range.min = cfi_off; - cie_out->cfi_range.max = cfi_off + cfi_size; - } -#endif -} - -internal DW_CFIRecords -dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, EH_PtrCtx *ptr_ctx, U64 ip_voff) -{ - Temp scratch = scratch_begin(0, 0); - - DW_CFIRecords result = {0}; - - DW_UnpackedCIENode *cie_first = 0; - DW_UnpackedCIENode *cie_last = 0; - - U64 cursor = 0; - for (;;) { - // CIE/FDE size - U64 rec_off = cursor; - U64 after_rec_size_off = 0; - U64 rec_size = 0; - - { - str8_deserial_read(raw_eh_frame, rec_off, &rec_size, 4, 1); - after_rec_size_off = 4; - if (rec_size == max_U32) { - str8_deserial_read(raw_eh_frame, rec_off + 4, &rec_size, 8, 1); - after_rec_size_off = 12; - } - } - - // zero size is the end of the loop - if (rec_size == 0) { - break; - } - - // compute end offset - U64 rec_opl = rec_off + after_rec_size_off + rec_size; - - // sub-range the rest of the reads - Rng1U64 rec_range = rng_1u64(rec_off, rec_opl); - String8 raw_rec = str8_substr(raw_eh_frame, rec_range); - - - // discriminator - U64 discrim_off = after_rec_size_off; - U32 discrim = 0; - str8_deserial_read(raw_rec, discrim_off, &discrim, 4, 1); - - U64 after_discrim_off = discrim_off + 4; - - // CIE - if (discrim == 0) { - DW_UnpackedCIE cie = {0}; - dw_unwind_parse_cie_x64(raw_rec.str, rng_1u64(0, raw_rec.size), ptr_ctx, after_discrim_off, &cie); - if (cie.version != 0) { - DW_UnpackedCIENode *node = push_array(scratch.arena, DW_UnpackedCIENode, 1); - node->cie = cie; - node->offset = rec_off; - SLLQueuePush(cie_first, cie_last, node); - } - } - // FDE - else { - // compute cie offset - U64 cie_offset = rec_range.min + discrim_off - discrim; - - // get cie node - DW_UnpackedCIENode *cie_node = 0; - for (DW_UnpackedCIENode *node = cie_first; node != 0; node = node->next) { - if (node->offset == cie_offset) { - cie_node = node; - break; - } - } - - // parse fde - DW_UnpackedFDE fde = {0}; - if (cie_node != 0) { - NotImplemented; - //dw_unwind_parse_fde_x64(raw_rec.str, rng_1u64(0,raw_rec.size), ptr_ctx, &cie_node->cie, after_discrim_off, &fde); - } - - if (contains_1u64(fde.pc_range, ip_voff)) { - result.valid = 1; - result.cie = cie_node->cie; - result.fde = fde; - break; - } - } - - // advance cursor - cursor = rec_opl; - } - - scratch_end(scratch); - - return(result); -} - -internal U64 -dw_search_eh_frame_hdr_linear_x64(String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 location) -{ - // Table contains only addresses for first instruction in a function and we cannot - // guarantee that result is FDE that corresponds to the input location. - // So input location must be cheked against range from FDE header again. - - U64 closest_location = max_U64; - U64 closest_address = max_U64; - - U64 cursor = 0; - - U8 version = 0; - cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &version); - - if (version == 1) { -#if 0 - EH_PtrCtx ptr_ctx = {0}; - // Set this to base address of .eh_frame_hdr. Entries are relative - // to this section for some reason. - ptr_ctx.data_vaddr = range.min; - // If input location is VMA then set this to address of .text. - // Pointer parsing function will adjust "init_location" to correct VMA. - ptr_ctx.text_vaddr = 0; -#endif - - EH_PtrEnc eh_frame_ptr_enc = 0, fde_count_enc = 0, table_enc = 0; - cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &eh_frame_ptr_enc); - cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &fde_count_enc); - cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &table_enc); - - U64 eh_frame_ptr = 0, fde_count = 0; - NotImplemented; - //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, eh_frame_ptr_enc, cursor, &eh_frame_ptr); - //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, fde_count_enc, cursor, &fde_count); - - for (U64 fde_idx = 0; fde_idx < fde_count; ++fde_idx) { - U64 init_location = 0, address = 0; - NotImplemented; - //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &init_location); - //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &address); - - S64 current_delta = (S64)(location - init_location); - S64 closest_delta = (S64)(location - closest_location); - if (0 <= current_delta && current_delta < closest_delta) { - closest_location = init_location; - closest_address = address; - } - } - } - - // address where to find corresponding FDE, this is an absolute offset - // into the image file. - return closest_address; -} - -internal DW_CFIRecords -dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 ip_voff) -{ - DW_CFIRecords result = {0}; - - // find FDE offset - void *eh_frame_hdr = raw_eh_frame.str; - U64 fde_offset = dw_search_eh_frame_hdr_linear_x64(raw_eh_frame_hdr, ptr_ctx, ip_voff); - - B32 is_fde_offset_valid = (fde_offset != max_U64); - if (is_fde_offset_valid) { - U64 fde_read_offset = (fde_offset - ptr_ctx->raw_base_vaddr); - - // read FDE size - U64 fde_size = 0; - fde_read_offset += dw_based_range_read_length(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), fde_read_offset, &fde_size); - - // read FDE discriminator - U32 fde_discrim = 0; - fde_read_offset += str8_deserial_read_struct(raw_eh_frame, fde_read_offset, &fde_discrim); - - // compute parent CIE offset - U64 cie_read_offset = fde_read_offset - (fde_discrim + sizeof(fde_discrim)); - - // read CIE size - U64 cie_size = 0; - cie_read_offset += dw_based_range_read_length(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), cie_read_offset, &cie_size); - - // read CIE discriminator - U32 cie_discrim = max_U32; - cie_read_offset += str8_deserial_read_struct(raw_eh_frame, cie_read_offset, &cie_discrim); - - B32 is_fde = (fde_discrim != 0); - B32 is_cie = (cie_discrim == 0); - if (is_fde && is_cie) { - Rng1U64 cie_range = rng_1u64(0, cie_read_offset + (cie_size - sizeof(cie_discrim))); - Rng1U64 fde_range = rng_1u64(0, fde_read_offset + (fde_size - sizeof(fde_discrim))); - - // parse CIE - DW_UnpackedCIE cie = {0}; - dw_unwind_parse_cie_x64(raw_eh_frame.str, cie_range, ptr_ctx, cie_read_offset, &cie); - - // parse FDE - DW_UnpackedFDE fde = {0}; - NotImplemented; - //dw_unwind_parse_fde_x64(raw_eh_frame.str, fde_range, ptr_ctx, &cie, fde_read_offset, &fde); - - // range check instruction pointer - if (contains_1u64(fde.pc_range, ip_voff)) { - result.valid = 1; - result.cie = cie; - result.fde = fde; - } - } - } - - return result; -} - -//- cfi machine - -internal DW_CFIMachine -dw_unwind_make_machine_x64(U64 cells_per_row, DW_UnpackedCIE *cie, EH_PtrCtx *ptr_ctx) -{ - DW_CFIMachine result = {0}; - result.cells_per_row = cells_per_row; - result.cie = cie; - result.ptr_ctx = ptr_ctx; - return result; -} - -internal void -dw_unwind_machine_equip_initial_row_x64(DW_CFIMachine *machine, DW_CFIRow *initial_row) -{ - machine->initial_row = initial_row; -} - -internal void -dw_unwind_machine_equip_fde_ip_x64(DW_CFIMachine *machine, U64 fde_ip) -{ - machine->fde_ip = fde_ip; -} - -internal DW_CFIRow* -dw_unwind_row_alloc_x64(Arena *arena, U64 cells_per_row) -{ - DW_CFIRow *result = push_array(arena, DW_CFIRow, 1); - result->cells = push_array(arena, DW_CFICell, cells_per_row); - return result; -} - -internal void -dw_unwind_row_zero_x64(DW_CFIRow *row, U64 cells_per_row) { - MemorySet(row->cells, 0, sizeof(*row->cells)*cells_per_row); - MemoryZeroStruct(&row->cfa_cell); -} - -internal void -dw_unwind_row_copy_x64(DW_CFIRow *dst, DW_CFIRow *src, U64 cells_per_row) -{ - MemoryCopy(dst->cells, src->cells, sizeof(*src->cells)*cells_per_row); - dst->cfa_cell = src->cfa_cell; + return uw; } internal B32 -dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machine, U64 target_ip, DW_CFIRow *row) +dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw) { - Temp scratch = scratch_begin(0, 0); - - B32 result = 0; - - // pull out machine's equipment - DW_UnpackedCIE *cie = machine->cie; - EH_PtrCtx *ptr_ctx = machine->ptr_ctx; - U64 cells_per_row = machine->cells_per_row; - DW_CFIRow *initial_row = machine->initial_row; - - // start with an empty stack - DW_CFIRow *stack = 0; - DW_CFIRow *free_rows = 0; - - // initialize the row - if (initial_row != 0) { - dw_unwind_row_copy_x64(row, initial_row, cells_per_row); - } else { - dw_unwind_row_zero_x64(row, cells_per_row); + B32 is_row_valid = 0; + + while (uw->curr_inst) { + DW_CFA_Inst *inst = &uw->curr_inst->v; + + // validate register operands + DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode); + U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode); + for EachIndex(operand_idx, operand_count) { + if (operand_types[operand_idx] == DW_CFA_OperandType_Register) { + if (inst->operands[operand_idx].u64 >= uw->reg_count) { + goto exit; + } + } + } + + switch (inst->opcode) { + // Row Creation Instructions + case DW_CFA_SetLoc: { + uw->pc = inst->operands[0].u64; + } break; + case DW_CFA_AdvanceLoc: + case DW_CFA_AdvanceLoc1: + case DW_CFA_AdvanceLoc2: + case DW_CFA_AdvanceLoc4: { + uw->pc += inst->operands[0].u64; + } break; + + // CFA Definition Instructions + case DW_CFA_DefCfa: + case DW_CFA_DefCfaSf: { + U64 reg = inst->operands[0].u64; + S64 off = inst->operands[1].s64; + uw->row->cfa.rule = DW_CFA_Rule_RegOff; + uw->row->cfa.reg = reg; + uw->row->cfa.off = off; + } break; + case DW_CFA_DefCfaRegister: { + // TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset + if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; } + U64 reg = inst->operands[0].u64; + uw->row->cfa.reg = reg; + } break; + case DW_CFA_DefCfaOffset: + case DW_CFA_DefCfaOffsetSf: { + // TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset + if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; } + uw->row->cfa.off = inst->operands[0].s64; + } break; + case DW_CFA_DefCfaExpr: { + uw->row->cfa.rule = DW_CFA_Rule_Expression; + uw->row->cfa.expr = inst->operands[0].block; + } break; + + // Register Rule Instructions + case DW_CFA_Undefined: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined; + } break; + case DW_CFA_SameValue: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue; + } break; + case DW_CFA_Offset: + case DW_CFA_OffsetExt: + case DW_CFA_OffsetExtSf: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset; + uw->row->regs[reg].n = inst->operands[1].s64; + } break; + case DW_CFA_ValOffset: + case DW_CFA_ValOffsetSf: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset; + uw->row->regs[reg].n = inst->operands[1].s64; + } break; + case DW_CFA_Register: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register; + uw->row->regs[reg].n = inst->operands[1].s64; + } break; + case DW_CFA_Expr: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression; + uw->row->regs[reg].expr = inst->operands[1].block; + } break; + case DW_CFA_ValExpr: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression; + uw->row->regs[reg].expr = inst->operands[1].block; + } break; + case DW_CFA_Restore: + case DW_CFA_RestoreExt: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg] = uw->initial_row->regs[reg]; + } break; + + // Row State Instructions + case DW_CFA_RememberState: { + DW_CFA_Row *new_row = dw_copy_cfa_row(arena, uw->reg_count, uw->row); + SLLStackPush(uw->row, new_row); + } break; + case DW_CFA_RestoreState: { + if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops + DW_CFA_Row *free_row = uw->row; + SLLStackPop(uw->row); + SLLStackPush(uw->free_rows, free_row); + } break; + + case DW_CFA_Nop: {} break; + + default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode + } + + is_row_valid = 1; + + uw->curr_inst = uw->curr_inst->next; + if (uw->curr_inst) { + if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; } + } } - U64 table_ip = machine->fde_ip; - - // loop - U64 cfi_off = 0; - for (;;) { - // op variables - DW_CFA opcode = 0; - U64 operand0 = 0; - U64 operand1 = 0; - U64 operand2 = 0; - DW_CFAControlBits control_bits = 0; - - // decode opcode/operand0 - if (!dw_based_range_read(base, range, cfi_off, 1, &opcode)) { - result = 1; - goto done; - } - if ((opcode & DW_CFAMask_OpcodeHi) != 0) { - operand0 = (opcode & DW_CFAMask_Operand); - opcode = (opcode & DW_CFAMask_OpcodeHi); - control_bits = dw_unwind__cfa_control_bits_kind2[opcode >> 6]; - } else { - if (opcode < DW_CFA_OplKind1) { - control_bits = dw_unwind__cfa_control_bits_kind1[opcode]; - } - } - - // decode operand1/operand2 - U64 decode_cursor = cfi_off + 1; - { - // setup loop ins/outs - U64 o[2]; - DW_CFADecode dec[2] = {0}; - dec[0] = (control_bits & 0xF); - dec[1] = ((control_bits >> 4) & 0xF); - - // loop - U64 *out = o; - for (U64 i = 0; i < 2; i += 1, out += 1) { - DW_CFADecode d = dec[i]; - U64 o_size = 0; - switch (d) { - case 0: { - *out = 0; - } break; - default: { - if (d <= 8) { - dw_based_range_read(base, range, decode_cursor, d, out); - o_size = d; - } - } break; - case DW_CFADecode_Address: { - // TODO: - NotImplemented; - //o_size = dw_unwind_parse_pointer_x64(base, range, ptr_ctx, cie->addr_encoding, decode_cursor, out); - } break; - case DW_CFADecode_ULEB128: { - o_size = dw_based_range_read_uleb128(base, range, decode_cursor, out); - } break; - case DW_CFADecode_SLEB128: { - o_size = dw_based_range_read_sleb128(base, range, decode_cursor, (S64*)out); - } break; - } - decode_cursor += o_size; - } - - // commit out values - operand1 = o[0]; - operand2 = o[1]; - } - U64 after_decode_off = decode_cursor; - - // register checks - if (control_bits & DW_CFAControlBits_IsReg0) { - if (operand0 >= cells_per_row) { - goto done; - } - } - if (control_bits & DW_CFAControlBits_IsReg1) { - if (operand1 >= cells_per_row) { - goto done; - } - } - if (control_bits & DW_CFAControlBits_IsReg2) { - if (operand2 >= cells_per_row) { - goto done; - } - } - - // values for deferred work - U64 new_table_ip = table_ip; - - // step - U64 step_cursor = after_decode_off; - switch (opcode) { - default: goto done; - case DW_CFA_Nop:break; - - //// new row/IP opcodes //// - - case DW_CFA_SetLoc: { - new_table_ip = operand1; - } break; - case DW_CFA_AdvanceLoc: { - new_table_ip = table_ip + operand0*cie->code_align_factor; - } break; - case DW_CFA_AdvanceLoc1: - case DW_CFA_AdvanceLoc2: - case DW_CFA_AdvanceLoc4: { - U64 advance = operand1*cie->code_align_factor; - new_table_ip = table_ip + advance; - } break; - - //// change CFA (canonical frame address) opcodes //// - - case DW_CFA_DefCfa: { - row->cfa_cell.rule = DW_CFI_CFA_Rule_RegOff; - row->cfa_cell.reg_idx = operand1; - row->cfa_cell.offset = operand2; - } break; - - case DW_CFA_DefCfaSf: { - row->cfa_cell.rule = DW_CFI_CFA_Rule_RegOff; - row->cfa_cell.reg_idx = operand1; - row->cfa_cell.offset = ((S64)operand2)*cie->data_align_factor; - } break; - - case DW_CFA_DefCfaRegister: { - // check rule - if (row->cfa_cell.rule != DW_CFI_CFA_Rule_RegOff) { - goto done; - } - // commit new cfa - row->cfa_cell.reg_idx = operand1; - } break; - - case DW_CFA_DefCfaOffset: { - // check rule - if (row->cfa_cell.rule != DW_CFI_CFA_Rule_RegOff) { - goto done; - } - // commit new cfa - row->cfa_cell.offset = operand1; - } break; - - case DW_CFA_DefCfaOffsetSf: { - // check rule - if (row->cfa_cell.rule != DW_CFI_CFA_Rule_RegOff) { - goto done; - } - // commit new cfa - row->cfa_cell.offset = ((S64)operand1)*cie->data_align_factor; - } break; - - case DW_CFA_DefCfaExpr: { - // setup expr range - U64 expr_first = range.min + after_decode_off; - U64 expr_size = operand1; - step_cursor += expr_size; - - // commit new cfa - row->cfa_cell.rule = DW_CFI_CFA_Rule_Expr; - row->cfa_cell.expr.min = expr_first; - row->cfa_cell.expr.max = expr_first + expr_size; - } break; - - - //// change register rules //// - - case DW_CFA_Undefined: { - row->cells[operand1].rule = DW_CFIRegisterRule_Undefined; - } break; - - case DW_CFA_SameValue: { - row->cells[operand1].rule = DW_CFIRegisterRule_SameValue; - } break; - - case DW_CFA_Offset: { - DW_CFICell *cell = &row->cells[operand0]; - cell->rule = DW_CFIRegisterRule_Offset; - cell->n = operand1*cie->data_align_factor; - } break; - - case DW_CFA_OffsetExt: { - DW_CFICell *cell = &row->cells[operand1]; - cell->rule = DW_CFIRegisterRule_Offset; - cell->n = operand2*cie->data_align_factor; - } break; - - case DW_CFA_OffsetExtSf: { - DW_CFICell *cell = &row->cells[operand1]; - cell->rule = DW_CFIRegisterRule_Offset; - cell->n = ((S64)operand2)*cie->data_align_factor; - } break; - - case DW_CFA_ValOffset: { - DW_CFICell *cell = &row->cells[operand1]; - cell->rule = DW_CFIRegisterRule_ValOffset; - cell->n = operand2*cie->data_align_factor; - } break; - - case DW_CFA_ValOffsetSf: { - DW_CFICell *cell = &row->cells[operand1]; - cell->rule = DW_CFIRegisterRule_ValOffset; - cell->n = ((S64)operand2)*cie->data_align_factor; - } break; - - case DW_CFA_Register: { - DW_CFICell *cell = &row->cells[operand1]; - cell->rule = DW_CFIRegisterRule_Register; - cell->n = operand2; - } break; - - case DW_CFA_Expr: { - // setup expr range - U64 expr_first = range.min + after_decode_off; - U64 expr_size = operand2; - step_cursor += expr_size; - - // commit new rule - DW_CFICell *cell = &row->cells[operand1]; - cell->rule = DW_CFIRegisterRule_Expression; - cell->expr.min = expr_first; - cell->expr.max = expr_first + expr_size; - } break; - - case DW_CFA_ValExpr: { - // setup expr range - U64 expr_first = range.min + after_decode_off; - U64 expr_size = operand2; - step_cursor += expr_size; - - // commit new rule - DW_CFICell *cell = &row->cells[operand1]; - cell->rule = DW_CFIRegisterRule_ValExpression; - cell->expr.min = expr_first; - cell->expr.max = expr_first + expr_size; - } break; - - case DW_CFA_Restore: { - // check initial row - if (initial_row == 0) { - goto done; - } - // commit new rule - row->cells[operand0] = initial_row->cells[operand0]; - } break; - - case DW_CFA_RestoreExt: { - // check initial row - if (initial_row == 0) { - goto done; - } - // commit new rule - row->cells[operand1] = initial_row->cells[operand1]; - } break; - - - //// row stack //// - - case DW_CFA_RememberState: { - DW_CFIRow *stack_row = free_rows; - if (stack_row != 0) { - SLLStackPop(free_rows); - } else { - stack_row = dw_unwind_row_alloc_x64(scratch.arena, cells_per_row); - } - dw_unwind_row_copy_x64(stack_row, row, cells_per_row); - SLLStackPush(stack, stack_row); - } break; - - case DW_CFA_RestoreState: { - if (stack != 0) { - DW_CFIRow *stack_row = stack; - SLLStackPop(stack); - dw_unwind_row_copy_x64(row, stack_row, cells_per_row); - SLLStackPush(free_rows, stack_row); - } else { - dw_unwind_row_zero_x64(row, cells_per_row); - } - } break; - } - - // apply location change - if (control_bits & DW_CFAControlBits_NewRow) { - // new ip should always grow the ip - if (new_table_ip <= table_ip) { - goto done; - } - // stop if this encloses the target ip - if (table_ip <= target_ip && target_ip < new_table_ip) { - result = 1; - goto done; - } - // commit new ip - table_ip = new_table_ip; - } - - // advance - cfi_off = step_cursor; + +exit:; + return is_row_valid; +} + +internal DW_UnwindStatus +dw_cfi_apply_register_rules(DW_CFI_Unwind *uw, + DW_MemRead *mem_read_func, void *mem_read_ud, + DW_RegRead *reg_read_func, void *reg_read_ud, + DW_RegWrite *reg_write_func, void *reg_write_ud) +{ + Temp scratch = scratch_begin(0,0); + DW_UnwindStatus unwind_status = DW_UnwindStatus_Ok; + + DW_CFA_Row *row = uw->row; + + // establish CFA + U64 cfa = 0; + switch (row->cfa.rule) { + case DW_CFA_Rule_Null: break; + case DW_CFA_Rule_RegOff: { + // TODO: report error (invalid register read) + U64 cfa_reg_value = 0; + U64 reg_size = dw_reg_size_from_code(uw->arch, row->cfa.reg); + AssertAlawys(reg_size <= sizeof(cfa_reg_value)); + unwind_status = reg_read_func(row->cfa.reg, &cfa_reg_value, reg_size, reg_read_ud); + if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } + cfa = cfa_reg_value + row->cfa.off; + } break; + case DW_CFA_Rule_Expression: { + // TODO: evaluate expression + } break; + } + + U64 max_reg_size = dw_max_reg_size_from_arch(uw->arch); + void *reg_buffer = push_array(scratch.arena, U8, max_reg_size); + + for EachIndex(reg_idx, uw->reg_count) { + DW_CFI_Register *reg = &uw->row->regs[reg_idx]; + switch (reg->rule) { + case DW_CFI_RegisterRule_Undefined: { + // TODO: ??? + Assert(!"undefined"); + } break; + case DW_CFI_RegisterRule_SameValue: {} break; + case DW_CFI_RegisterRule_Offset: { + // read register value from memory + U64 addr = cfa + reg->n; + U64 reg_size = dw_reg_size_from_code(uw->arch, reg_idx); + unwind_status = mem_read_func(addr, reg_size, reg_buffer, mem_read_ud); + if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } + + // write register value to the thread context + unwind_status = reg_write(reg_idx, reg_buffer, reg_size, reg_write_ud); + if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } + } break; + case DW_CFI_RegisterRule_ValOffset: { + // compute register value + U64 reg_value = cfa + reg->n; + + // write register value to the thread context + U64 reg_size = dw_reg_size_from_code(uw->arch, reg_idx); + unwind_status = reg_write(reg_idx, ®_value, reg_size, reg_write_ud); + if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } + } break; + case DW_CFI_RegisterRule_Register: { + // read register value from another register + U64 reg_size = dw_reg_size_from_code(uw->arch, reg_idx); + unwind_status = reg_read(reg->n, reg_buffer, reg_size, reg_read_ud); + if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } + + // write register value to the thread context + unwind_status = reg_write(reg_idx, reg_buffer, reg_size, reg_write_ud); + if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } + } break; + case DW_CFI_RegisterRule_Expression: { + // TODO: evaluate expression + NotImplemented; + } break; + case DW_CFI_RegisterRule_ValExpression: { + // TODO: evaluate expression + NotImplemented; + } break; + case DW_CFI_RegisterRule_Architectural: { + NotImplemented; + } break; + } } - done:; +exit:; scratch_end(scratch); - return result; -} - -//////////////////////////////// - -internal String8 -dw_string_from_eh_ptr_enc_type(EH_PtrEnc type) -{ - switch (type) { - case EH_PtrEnc_Ptr: return str8_lit("Ptr"); - case EH_PtrEnc_ULEB128: return str8_lit("ULEB128"); - case EH_PtrEnc_UData2: return str8_lit("UData2"); - case EH_PtrEnc_UData4: return str8_lit("UData4"); - case EH_PtrEnc_UData8: return str8_lit("UData8"); - case EH_PtrEnc_Signed: return str8_lit("Signed"); - case EH_PtrEnc_SLEB128: return str8_lit("SLEB128"); - case EH_PtrEnc_SData2: return str8_lit("SData2"); - case EH_PtrEnc_SData4: return str8_lit("SData4"); - case EH_PtrEnc_SData8: return str8_lit("SData8"); - } - return str8_zero(); -} - -internal String8 -dw_string_from_eh_ptr_enc_modifier(EH_PtrEnc modifier) -{ - switch (modifier) { - case EH_PtrEnc_PcRel: return str8_lit("PcRel"); - case EH_PtrEnc_TextRel: return str8_lit("TextRel"); - case EH_PtrEnc_DataRel: return str8_lit("DataRel"); - case EH_PtrEnc_FuncRel: return str8_lit("FuncRel"); - case EH_PtrEnc_Aligned: return str8_lit("Aligned"); - } - return str8_zero(); -} - -internal String8 -dw_string_from_eh_ptr_enc(Arena *arena, EH_PtrEnc enc) -{ - String8 type_str = dw_string_from_eh_ptr_enc_type(enc & EH_PtrEnc_TypeMask); - String8 modifer_str = dw_string_from_eh_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask); - String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero(); - String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str); - return result; + return unwind_status; } diff --git a/src/dwarf/dwarf_unwind.h b/src/dwarf/dwarf_unwind.h index 54f7f187..f5fde8c0 100644 --- a/src/dwarf/dwarf_unwind.h +++ b/src/dwarf/dwarf_unwind.h @@ -4,150 +4,90 @@ #ifndef DWARF_UNWIND_H #define DWARF_UNWIND_H -typedef struct DW_UnwindResult +typedef enum DW_CFI_RegisterRule { - B32 is_invalid; - B32 missed_read; - U64 missed_read_addr; - U64 stack_pointer; -} DW_UnwindResult; + DW_CFI_RegisterRule_Undefined, + DW_CFI_RegisterRule_SameValue, + DW_CFI_RegisterRule_Offset, + DW_CFI_RegisterRule_ValOffset, + DW_CFI_RegisterRule_Register, + DW_CFI_RegisterRule_Expression, + DW_CFI_RegisterRule_ValExpression, + DW_CFI_RegisterRule_Architectural +} DW_CFI_RegisterRule; -// EH: Exception Frames - -typedef struct DW_UnpackedCIENode +typedef enum DW_CFA_Rule { - struct DW_UnpackedCIENode *next; - DW_UnpackedCIE cie; - U64 offset; -} DW_UnpackedCIENode; + DW_CFA_Rule_Null, + DW_CFA_Rule_RegOff, + DW_CFA_Rule_Expression +} DW_CFA_Rule; -// CFI: Call Frame Information -typedef struct DW_CFIRecords +typedef struct DW_CFA { - B32 valid; - DW_UnpackedCIE cie; - DW_UnpackedFDE fde; -} DW_CFIRecords; - -typedef enum DW_CFICFARule{ - DW_CFI_CFA_Rule_RegOff, - DW_CFI_CFA_Rule_Expr, -} DW_CFICFARule; - -typedef struct DW_CFICFACell -{ - DW_CFICFARule rule; + DW_CFA_Rule rule; union { struct { - U64 reg_idx; - S64 offset; + DW_Reg reg; + S64 off; }; - Rng1U64 expr; + String8 expr; }; -} DW_CFICFACell; +} DW_CFA; -typedef enum DW_CFIRegisterRule +typedef struct DW_CFI_Register { - DW_CFIRegisterRule_SameValue, - DW_CFIRegisterRule_Undefined, - DW_CFIRegisterRule_Offset, - DW_CFIRegisterRule_ValOffset, - DW_CFIRegisterRule_Register, - DW_CFIRegisterRule_Expression, - DW_CFIRegisterRule_ValExpression, -} DW_CFIRegisterRule; - -typedef struct DW_CFICell -{ - DW_CFIRegisterRule rule; + DW_CFI_RegisterRule rule; union { - S64 n; - Rng1U64 expr; + S64 n; + String8 expr; }; -} DW_CFICell; +} DW_CFI_Register; -typedef struct DW_CFIRow +typedef struct DW_CFA_Row { - struct DW_CFIRow *next; - DW_CFICell *cells; - DW_CFICFACell cfa_cell; -} DW_CFIRow; + DW_CFA cfa; + DW_CFI_Register *regs; + struct DW_CFA_Row *next; +} DW_CFA_Row; -typedef struct DW_CFIMachine +typedef struct DW_CFI_Unwind { - U64 cells_per_row; - DW_UnpackedCIE *cie; - DW_CFIRow *initial_row; - U64 fde_ip; - EH_PtrCtx *ptr_ctx; -} DW_CFIMachine; + DW_CFA_InstList insts; + DW_CIE *cie; + DW_FDE *fde; + DW_CFA_Row *initial_row; + DW_CFA_Row *row; + DW_CFA_InstNode *curr_inst; + DW_CFA_Row *free_rows; + DW_Reg reg_count; + U64 pc; + Arch arch; +} DW_CFI_Unwind; -typedef U8 DW_CFADecode; -enum -{ - DW_CFADecode_Nop = 0x0, - // 1,2,4,8 reserved for literal byte sizes - DW_CFADecode_Address = 0x9, - DW_CFADecode_ULEB128 = 0xA, - DW_CFADecode_SLEB128 = 0xB, -}; +typedef enum { + DW_UnwindStatus_Ok, + DW_UnwindStatus_Fail, + DW_UnwindStatus_Maybe +} DW_UnwindStatus; -typedef U16 DW_CFAControlBits; -enum -{ - DW_CFAControlBits_Dec1Mask = 0x00F, - DW_CFAControlBits_Dec2Mask = 0x0F0, - DW_CFAControlBits_IsReg0 = 0x100, - DW_CFAControlBits_IsReg1 = 0x200, - DW_CFAControlBits_IsReg2 = 0x400, - DW_CFAControlBits_NewRow = 0x800, -}; +#define DW_REG_READ(name) DW_UnwindStatus name(DW_Reg reg_id, void *buffer, U64 buffer_max, void *ud) +typedef DW_REG_READ(DW_RegRead); -global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind1[DW_CFA_OplKind1 + 1]; -global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind2[DW_CFA_OplKind2 + 1]; +#define DW_REG_WRITE(name) DW_UnwindStatus name(DW_Reg reg_id, void *value, U64 value_size, void *ud) +typedef DW_REG_WRITE(DW_RegWrite); -// register codes for unwinding match the DW_RegX64 register codes -#define DW_UNWIND_X64__REG_SLOT_COUNT 17 +#define DW_MEM_READ(name) DW_UnwindStatus name(U64 addr, U64 size, void *buffer, void *ud) +typedef DW_MEM_READ(DW_MemRead); //////////////////////////////// -// x64 Unwind Function -internal DW_UnwindResult -dw_unwind_x64(String8 raw_text, - String8 raw_eh_frame, - String8 raw_eh_frame_header, - Rng1U64 text_vrange, - Rng1U64 eh_frame_vrange, - Rng1U64 eh_frame_header_vrange, - U64 default_image_base, - U64 image_base, - U64 stack_pointer, - DW_RegsX64 *regs, - DW_ReadMemorySig *read_memory, - void *read_memory_ud); +internal DW_CFA_Row * dw_make_cfa_row(Arena *arena, U64 reg_count); +internal DW_CFA_Row * dw_copy_cfa_row(Arena *arena, U64 reg_count, DW_CFA_Row *row); -internal DW_UnwindResult dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, DW_CFIRow *row, U64 text_base_vaddr, DW_ReadMemorySig *read_memory, void *read_memory_ud, U64 stack_pointer, DW_RegsX64 *regs); - -//////////////////////////////// -// x64 Unwind Helper Functions - -internal void dw_unwind_init_x64(void); - -//- eh_frame parsing -internal DW_CFIRecords dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, EH_PtrCtx *ptr_ctx, U64 ip_voff); -internal DW_CFIRecords dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 ip_voff); - -//- cfi machine - -internal DW_CFIMachine dw_unwind_make_machine_x64(U64 cells_per_row, DW_UnpackedCIE *cie, EH_PtrCtx *ptr_ctx); -internal void dw_unwind_machine_equip_initial_row_x64(DW_CFIMachine *machine, DW_CFIRow *initial_row); -internal void dw_unwind_machine_equip_fde_ip_x64(DW_CFIMachine *machine, U64 fde_ip); - -internal DW_CFIRow* dw_unwind_row_alloc_x64(Arena *arena, U64 cells_per_row); -internal void dw_unwind_row_zero_x64(DW_CFIRow *row, U64 cells_per_row); -internal void dw_unwind_row_copy_x64(DW_CFIRow *dst, DW_CFIRow *src, U64 cells_per_row); - -internal B32 dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machine, U64 target_ip, DW_CFIRow *row_out); +internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud); +internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw); +internal DW_UnwindStatus dw_cfi_apply_register_rules(DW_CFI_Unwind *uw, DW_MemRead *mem_read_func, void *mem_read_ud, DW_RegRead *reg_read_func, void *reg_read_ud, DW_RegWrite *reg_write_func, void *reg_write_ud); #endif // DWARF_UNWIND_H diff --git a/src/eh/eh_frame.c b/src/eh/eh_frame.c index fd56a313..0b3f56e3 100644 --- a/src/eh/eh_frame.c +++ b/src/eh/eh_frame.c @@ -122,3 +122,160 @@ eh_size_from_aug_data(String8 aug_string, String8 data, EH_PtrCtx *ptr_ctx) return eh_parse_aug_data(aug_string, data, ptr_ctx, 0); } +internal U64 +eh_frame_hdr_search_linear_x64(String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 location) +{ + // Table contains only addresses for first instruction in a function and we cannot + // guarantee that result is FDE that corresponds to the input location. + // So input location must be cheked against range from FDE header again. + + U64 closest_location = max_U64; + U64 closest_address = max_U64; + + U64 cursor = 0; + + U8 version = 0; + cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &version); + + if (version == 1) { +#if 0 + EH_PtrCtx ptr_ctx = {0}; + // Set this to base address of .eh_frame_hdr. Entries are relative + // to this section for some reason. + ptr_ctx.data_vaddr = range.min; + // If input location is VMA then set this to address of .text. + // Pointer parsing function will adjust "init_location" to correct VMA. + ptr_ctx.text_vaddr = 0; +#endif + + EH_PtrEnc eh_frame_ptr_enc = 0, fde_count_enc = 0, table_enc = 0; + cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &eh_frame_ptr_enc); + cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &fde_count_enc); + cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &table_enc); + + U64 eh_frame_ptr = 0, fde_count = 0; + NotImplemented; + //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, eh_frame_ptr_enc, cursor, &eh_frame_ptr); + //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, fde_count_enc, cursor, &fde_count); + + for (U64 fde_idx = 0; fde_idx < fde_count; ++fde_idx) { + U64 init_location = 0, address = 0; + NotImplemented; + //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &init_location); + //cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &address); + + S64 current_delta = (S64)(location - init_location); + S64 closest_delta = (S64)(location - closest_location); + if (0 <= current_delta && current_delta < closest_delta) { + closest_location = init_location; + closest_address = address; + } + } + } + + // address where to find corresponding FDE, this is an absolute offset + // into the image file. + return closest_address; +} + +#if 0 +internal DW_CFIRecords +dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 ip_voff) +{ + DW_CFIRecords result = {0}; + + // find FDE offset + void *eh_frame_hdr = raw_eh_frame.str; + U64 fde_offset = dw_search_eh_frame_hdr_linear_x64(raw_eh_frame_hdr, ptr_ctx, ip_voff); + + B32 is_fde_offset_valid = (fde_offset != max_U64); + if (is_fde_offset_valid) { + U64 fde_read_offset = (fde_offset - ptr_ctx->raw_base_vaddr); + + // read FDE size + U64 fde_size = 0; + fde_read_offset += str8_deserial_read_dwarf_packed_size(raw_eh_frame, fde_read_offset, &fde_size); + + // read FDE discriminator + U32 fde_discrim = 0; + fde_read_offset += str8_deserial_read_struct(raw_eh_frame, fde_read_offset, &fde_discrim); + + // compute parent CIE offset + U64 cie_read_offset = fde_read_offset - (fde_discrim + sizeof(fde_discrim)); + + // read CIE size + U64 cie_size = 0; + cie_read_offset += str8_deserial_read_dwarf_packed_size(raw_eh_frame, cie_read_offset, &cie_size); + + // read CIE discriminator + U32 cie_discrim = max_U32; + cie_read_offset += str8_deserial_read_struct(raw_eh_frame, cie_read_offset, &cie_discrim); + + B32 is_fde = (fde_discrim != 0); + B32 is_cie = (cie_discrim == 0); + if (is_fde && is_cie) { + Rng1U64 cie_range = rng_1u64(0, cie_read_offset + (cie_size - sizeof(cie_discrim))); + Rng1U64 fde_range = rng_1u64(0, fde_read_offset + (fde_size - sizeof(fde_discrim))); + + // parse CIE + DW_CIE cie = {0}; + dw_unwind_parse_cie_x64(raw_eh_frame.str, cie_range, ptr_ctx, cie_read_offset, &cie); + + // parse FDE + DW_FDE fde = {0}; + NotImplemented; + //dw_unwind_parse_fde_x64(raw_eh_frame.str, fde_range, ptr_ctx, &cie, fde_read_offset, &fde); + + // range check instruction pointer + if (contains_1u64(fde.pc_range, ip_voff)) { + result.valid = 1; + result.cie = cie; + result.fde = fde; + } + } + } + + return result; +} +#endif + +internal String8 +eh_string_from_ptr_enc_type(EH_PtrEnc type) +{ + switch (type) { + case EH_PtrEnc_Ptr: return str8_lit("Ptr"); + case EH_PtrEnc_ULEB128: return str8_lit("ULEB128"); + case EH_PtrEnc_UData2: return str8_lit("UData2"); + case EH_PtrEnc_UData4: return str8_lit("UData4"); + case EH_PtrEnc_UData8: return str8_lit("UData8"); + case EH_PtrEnc_Signed: return str8_lit("Signed"); + case EH_PtrEnc_SLEB128: return str8_lit("SLEB128"); + case EH_PtrEnc_SData2: return str8_lit("SData2"); + case EH_PtrEnc_SData4: return str8_lit("SData4"); + case EH_PtrEnc_SData8: return str8_lit("SData8"); + } + return str8_zero(); +} + +internal String8 +eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier) +{ + switch (modifier) { + case EH_PtrEnc_PcRel: return str8_lit("PcRel"); + case EH_PtrEnc_TextRel: return str8_lit("TextRel"); + case EH_PtrEnc_DataRel: return str8_lit("DataRel"); + case EH_PtrEnc_FuncRel: return str8_lit("FuncRel"); + case EH_PtrEnc_Aligned: return str8_lit("Aligned"); + } + return str8_zero(); +} + +internal String8 +eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc) +{ + String8 type_str = eh_string_from_ptr_enc_type(enc & EH_PtrEnc_TypeMask); + String8 modifer_str = eh_string_from_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask); + String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero(); + String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str); + return result; +} diff --git a/src/eh/eh_frame.h b/src/eh/eh_frame.h index f4ee576c..ac5840e5 100644 --- a/src/eh/eh_frame.h +++ b/src/eh/eh_frame.h @@ -70,5 +70,12 @@ internal U64 eh_read_ptr(String8 frame_base, U64 off, EH_PtrCtx *ptr_ctx, EH_Ptr internal U64 eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out); internal U64 eh_size_from_aug_data(String8 aug_string, String8 data, EH_PtrCtx *ptr_ctx); +//////////////////////////////// +//~ Enum -> String + +internal String8 eh_string_from_ptr_enc_type(EH_PtrEnc type); +internal String8 eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier); +internal String8 eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc); + #endif // EH_FRAME_H From 3bd89b1fad98904920b701d2812046cbecb018ab Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 10 Oct 2025 10:15:22 -0700 Subject: [PATCH 089/133] switch over to new MD5 hash lib --- src/linker/base_ext/base_inc.c | 1 - src/linker/base_ext/base_inc.h | 1 - src/linker/base_ext/base_md5.c | 12 -- src/linker/base_ext/base_md5.h | 12 -- src/linker/lnk.c | 11 +- src/third_party/md5/md5.c | 293 --------------------------------- src/third_party/md5/md5.h | 49 ------ 7 files changed, 4 insertions(+), 375 deletions(-) delete mode 100644 src/linker/base_ext/base_md5.c delete mode 100644 src/linker/base_ext/base_md5.h delete mode 100644 src/third_party/md5/md5.c delete mode 100644 src/third_party/md5/md5.h diff --git a/src/linker/base_ext/base_inc.c b/src/linker/base_ext/base_inc.c index 8a99d53d..e4b83f1e 100644 --- a/src/linker/base_ext/base_inc.c +++ b/src/linker/base_ext/base_inc.c @@ -7,5 +7,4 @@ #include "base_arrays.c" #include "base_bit_array.c" #include "base_crc32.c" -#include "base_md5.c" diff --git a/src/linker/base_ext/base_inc.h b/src/linker/base_ext/base_inc.h index 2074a32d..37877be1 100644 --- a/src/linker/base_ext/base_inc.h +++ b/src/linker/base_ext/base_inc.h @@ -10,5 +10,4 @@ #include "base_blake3.h" #include "base_bit_array.h" #include "base_crc32.h" -#include "base_md5.h" diff --git a/src/linker/base_ext/base_md5.c b/src/linker/base_ext/base_md5.c deleted file mode 100644 index 5e77bd7b..00000000 --- a/src/linker/base_ext/base_md5.c +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -internal MD5Hash -md5_hash_from_string(String8 data) -{ - MD5_CTX ctx; MD5_Init(&ctx); - MD5_Update(&ctx, (void*)data.str, safe_cast_u32(data.size)); - MD5Hash hash; MD5_Final((unsigned char*)&hash, &ctx); - return hash; -} - diff --git a/src/linker/base_ext/base_md5.h b/src/linker/base_ext/base_md5.h deleted file mode 100644 index 288cddc4..00000000 --- a/src/linker/base_ext/base_md5.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#pragma once - -typedef struct MD5Hash -{ - U8 value[16]; -} MD5Hash; - -internal MD5Hash md5_hash_from_string(String8 data); - diff --git a/src/linker/lnk.c b/src/linker/lnk.c index aa13ab29..1a1c9b19 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -14,9 +14,6 @@ #include "base_ext/base_blake3.h" #include "base_ext/base_blake3.c" -#define MD5_API static -#include "third_party/md5/md5.c" -#include "third_party/md5/md5.h" #define XXH_INLINE_ALL #define XXH_IMPLEMENTATION #define XXH_STATIC_LINKING_ONLY @@ -667,7 +664,7 @@ lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer, String8 exe_path, CV_Arch arch, String8List res_file_list, - MD5Hash *res_hash_array) + MD5 *res_hash_array) { ProfBeginFunction(); Temp scratch = scratch_begin(0,0); @@ -686,7 +683,7 @@ lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer, for (String8Node *n = res_file_list.first; n != NULL; n = n->next, ++node_idx) { CV_C13Checksum checksum = {0}; checksum.name_off = string_srl.total_size; - checksum.len = sizeof(MD5Hash); + checksum.len = sizeof(MD5); checksum.kind = CV_C13ChecksumKind_MD5; str8_serial_push_struct(scratch.arena, &file_srl, &checksum); str8_serial_push_struct(scratch.arena, &file_srl, &res_hash_array[node_idx]); @@ -779,10 +776,10 @@ lnk_make_res_obj(Arena *arena, // load res files PE_ResourceDir *root_dir = push_array(scratch.arena, PE_ResourceDir, 1); - MD5Hash *res_hash_array = push_array(scratch.arena, MD5Hash, res_data_list.node_count); + MD5 *res_hash_array = push_array(scratch.arena, MD5, res_data_list.node_count); U64 node_idx = 0; for (String8Node *node = res_data_list.first; node != 0; node = node->next, node_idx += 1) { - res_hash_array[node_idx] = md5_hash_from_string(node->string); + res_hash_array[node_idx] = md5_from_data(node->string); pe_resource_dir_push_res_file(scratch.arena, root_dir, node->string); } diff --git a/src/third_party/md5/md5.c b/src/third_party/md5/md5.c deleted file mode 100644 index c31e1c82..00000000 --- a/src/third_party/md5/md5.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. - * MD5 Message-Digest Algorithm (RFC 1321). - * - * Homepage: - * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 - * - * Author: - * Alexander Peslyak, better known as Solar Designer - * - * This software was written by Alexander Peslyak in 2001. No copyright is - * claimed, and the software is hereby placed in the public domain. - * In case this attempt to disclaim copyright and place the software in the - * public domain is deemed null and void, then the software is - * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the - * general public under the following terms: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted. - * - * There's ABSOLUTELY NO WARRANTY, express or implied. - * - * (This is a heavily cut-down "BSD license".) - * - * This differs from Colin Plumb's older public domain implementation in that - * no exactly 32-bit integer data type is required (any 32-bit or wider - * unsigned integer data type will do), there's no compile-time endianness - * configuration, and the function prototypes match OpenSSL's. No code from - * Colin Plumb's implementation has been reused; this comment merely compares - * the properties of the two independent implementations. - * - * The primary goals of this implementation are portability and ease of use. - * It is meant to be fast, but not as fast as possible. Some known - * optimizations are not included to reduce source code size and avoid - * compile-time configuration. - */ - -#ifndef HAVE_OPENSSL - -#include - -#include "md5.h" - -/* - * The basic MD5 functions. - * - * F and G are optimized compared to their RFC 1321 definitions for - * architectures that lack an AND-NOT instruction, just like in Colin Plumb's - * implementation. - */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) -#define H(x, y, z) (((x) ^ (y)) ^ (z)) -#define H2(x, y, z) ((x) ^ ((y) ^ (z))) -#define I(x, y, z) ((y) ^ ((x) | ~(z))) - -/* - * The MD5 transformation for all four rounds. - */ -#define STEP(f, a, b, c, d, x, t, s) \ - (a) += f((b), (c), (d)) + (x) + (t); \ - (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ - (a) += (b); - -/* - * SET reads 4 input bytes in little-endian byte order and stores them in a - * properly aligned word in host byte order. - * - * The check for little-endian architectures that tolerate unaligned memory - * accesses is just an optimization. Nothing will break if it fails to detect - * a suitable architecture. - * - * Unfortunately, this optimization may be a C strict aliasing rules violation - * if the caller's data buffer has effective type that cannot be aliased by - * MD5_u32plus. In practice, this problem may occur if these MD5 routines are - * inlined into a calling function, or with future and dangerously advanced - * link-time optimizations. For the time being, keeping these MD5 routines in - * their own translation unit avoids the problem. - */ -#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) -#define SET(n) \ - (*(MD5_u32plus *)&ptr[(n) * 4]) -#define GET(n) \ - SET(n) -#else -#define SET(n) \ - (ctx->block[(n)] = \ - (MD5_u32plus)ptr[(n) * 4] | \ - ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ - ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ - ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) -#define GET(n) \ - (ctx->block[(n)]) -#endif - -/* - * This processes one or more 64-byte data blocks, but does NOT update the bit - * counters. There are no alignment requirements. - */ -static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) -{ - const unsigned char *ptr; - MD5_u32plus a, b, c, d; - MD5_u32plus saved_a, saved_b, saved_c, saved_d; - - ptr = (const unsigned char *)data; - - a = ctx->a; - b = ctx->b; - c = ctx->c; - d = ctx->d; - - do { - saved_a = a; - saved_b = b; - saved_c = c; - saved_d = d; - -/* Round 1 */ - STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) - STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) - STEP(F, c, d, a, b, SET(2), 0x242070db, 17) - STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) - STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) - STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) - STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) - STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) - STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) - STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) - STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) - STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) - STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) - STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) - STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) - STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) - -/* Round 2 */ - STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) - STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) - STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) - STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) - STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) - STEP(G, d, a, b, c, GET(10), 0x02441453, 9) - STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) - STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) - STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) - STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) - STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) - STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) - STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) - STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) - STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) - STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) - -/* Round 3 */ - STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) - STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) - STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) - STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) - STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) - STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) - STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) - STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) - STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) - STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) - STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) - STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) - STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) - STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) - STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) - STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) - -/* Round 4 */ - STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) - STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) - STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) - STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) - STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) - STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) - STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) - STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) - STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) - STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) - STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) - STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) - STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) - STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) - STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) - STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) - - a += saved_a; - b += saved_b; - c += saved_c; - d += saved_d; - - ptr += 64; - } while (size -= 64); - - ctx->a = a; - ctx->b = b; - ctx->c = c; - ctx->d = d; - - return ptr; -} - -MD5_API void MD5_Init(MD5_CTX *ctx) -{ - ctx->a = 0x67452301; - ctx->b = 0xefcdab89; - ctx->c = 0x98badcfe; - ctx->d = 0x10325476; - - ctx->lo = 0; - ctx->hi = 0; -} - -MD5_API void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) -{ - MD5_u32plus saved_lo; - unsigned long used, available; - - saved_lo = ctx->lo; - if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) - ctx->hi++; - ctx->hi += size >> 29; - - used = saved_lo & 0x3f; - - if (used) { - available = 64 - used; - - if (size < available) { - memcpy(&ctx->buffer[used], data, size); - return; - } - - memcpy(&ctx->buffer[used], data, available); - data = (const unsigned char *)data + available; - size -= available; - body(ctx, ctx->buffer, 64); - } - - if (size >= 64) { - data = body(ctx, data, size & ~(unsigned long)0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - -#define MD5_OUT(dst, src) \ - (dst)[0] = (unsigned char)(src); \ - (dst)[1] = (unsigned char)((src) >> 8); \ - (dst)[2] = (unsigned char)((src) >> 16); \ - (dst)[3] = (unsigned char)((src) >> 24); - -MD5_API void MD5_Final(unsigned char *result, MD5_CTX *ctx) -{ - unsigned long used, available; - - used = ctx->lo & 0x3f; - - ctx->buffer[used++] = 0x80; - - available = 64 - used; - - if (available < 8) { - memset(&ctx->buffer[used], 0, available); - body(ctx, ctx->buffer, 64); - used = 0; - available = 64; - } - - memset(&ctx->buffer[used], 0, available - 8); - - ctx->lo <<= 3; - MD5_OUT(&ctx->buffer[56], ctx->lo) - MD5_OUT(&ctx->buffer[60], ctx->hi) - - body(ctx, ctx->buffer, 64); - - MD5_OUT(&result[0], ctx->a) - MD5_OUT(&result[4], ctx->b) - MD5_OUT(&result[8], ctx->c) - MD5_OUT(&result[12], ctx->d) - - memset(ctx, 0, sizeof(*ctx)); -} - -#undef MD5_OUT - -#endif diff --git a/src/third_party/md5/md5.h b/src/third_party/md5/md5.h deleted file mode 100644 index ce5e0c92..00000000 --- a/src/third_party/md5/md5.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. - * MD5 Message-Digest Algorithm (RFC 1321). - * - * Homepage: - * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 - * - * Author: - * Alexander Peslyak, better known as Solar Designer - * - * This software was written by Alexander Peslyak in 2001. No copyright is - * claimed, and the software is hereby placed in the public domain. - * In case this attempt to disclaim copyright and place the software in the - * public domain is deemed null and void, then the software is - * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the - * general public under the following terms: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted. - * - * There's ABSOLUTELY NO WARRANTY, express or implied. - * - * See md5.c for more information. - */ - -#ifndef MD5_API -# define MD5_API -#endif - -#ifdef HAVE_OPENSSL -#include -#elif !defined(_MD5_H) -#define _MD5_H - -/* Any 32-bit or wider unsigned integer data type will do */ -typedef unsigned int MD5_u32plus; - -typedef struct { - MD5_u32plus lo, hi; - MD5_u32plus a, b, c, d; - unsigned char buffer[64]; - MD5_u32plus block[16]; -} MD5_CTX; - -MD5_API void MD5_Init(MD5_CTX *ctx); -MD5_API void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); -MD5_API void MD5_Final(unsigned char *result, MD5_CTX *ctx); - -#endif From 43fcc214901f384197c24c1accdce3520b730516 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 10 Oct 2025 10:19:47 -0700 Subject: [PATCH 090/133] clang build fixes --- src/dwarf/dwarf.h | 2 +- src/dwarf/dwarf_unwind.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index 4e844e75..7f9e9c61 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -1816,6 +1816,6 @@ internal String8 dw_string_from_loc_list_entry_kind(Arena *arena, DW_LLE kind); internal String8 dw_string_from_section_kind(Arena *arena, DW_SectionKind kind); internal String8 dw_string_from_rng_list_entry_kind(Arena *arena, DW_RLE kind); internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id); -internal String8 dw_string_from_cfa_opcode(DW_CFA_Opcodecfa_opcode); +internal String8 dw_string_from_cfa_opcode(DW_CFA_Opcode opcode); #endif // DWARF_H diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index 6946d114..e899d676 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -202,7 +202,7 @@ dw_cfi_apply_register_rules(DW_CFI_Unwind *uw, // TODO: report error (invalid register read) U64 cfa_reg_value = 0; U64 reg_size = dw_reg_size_from_code(uw->arch, row->cfa.reg); - AssertAlawys(reg_size <= sizeof(cfa_reg_value)); + AssertAlways(reg_size <= sizeof(cfa_reg_value)); unwind_status = reg_read_func(row->cfa.reg, &cfa_reg_value, reg_size, reg_read_ud); if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } cfa = cfa_reg_value + row->cfa.off; @@ -212,7 +212,7 @@ dw_cfi_apply_register_rules(DW_CFI_Unwind *uw, } break; } - U64 max_reg_size = dw_max_reg_size_from_arch(uw->arch); + U64 max_reg_size = dw_reg_max_size_from_arch(uw->arch); void *reg_buffer = push_array(scratch.arena, U8, max_reg_size); for EachIndex(reg_idx, uw->reg_count) { @@ -231,7 +231,7 @@ dw_cfi_apply_register_rules(DW_CFI_Unwind *uw, if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } // write register value to the thread context - unwind_status = reg_write(reg_idx, reg_buffer, reg_size, reg_write_ud); + unwind_status = reg_write_func(reg_idx, reg_buffer, reg_size, reg_write_ud); if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } } break; case DW_CFI_RegisterRule_ValOffset: { @@ -240,17 +240,17 @@ dw_cfi_apply_register_rules(DW_CFI_Unwind *uw, // write register value to the thread context U64 reg_size = dw_reg_size_from_code(uw->arch, reg_idx); - unwind_status = reg_write(reg_idx, ®_value, reg_size, reg_write_ud); + unwind_status = reg_write_func(reg_idx, ®_value, reg_size, reg_write_ud); if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } } break; case DW_CFI_RegisterRule_Register: { // read register value from another register U64 reg_size = dw_reg_size_from_code(uw->arch, reg_idx); - unwind_status = reg_read(reg->n, reg_buffer, reg_size, reg_read_ud); + unwind_status = reg_read_func(reg->n, reg_buffer, reg_size, reg_read_ud); if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } // write register value to the thread context - unwind_status = reg_write(reg_idx, reg_buffer, reg_size, reg_write_ud); + unwind_status = reg_write_func(reg_idx, reg_buffer, reg_size, reg_write_ud); if (unwind_status != DW_UnwindStatus_Ok) { goto exit; } } break; case DW_CFI_RegisterRule_Expression: { From bd9372f07c3bb2371ad7b6dee2ff6d935d776712 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 10 Oct 2025 12:56:24 -0700 Subject: [PATCH 091/133] use current working directory as working directory for command line targets --- src/raddbg/raddbg_core.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index e9ca65a1..902fc001 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -11093,15 +11093,9 @@ rd_init(CmdLine *cmdln) executable_name_string = exe_name; } - // rjf: unpack working directory - if(target_args.first->string.size != 0) + // rjf: get current directory, use as working directory { - String8 path_part_of_arg = str8_chop_last_slash(target_args.first->string); - if(path_part_of_arg.size != 0) - { - String8 path = push_str8f(scratch.arena, "%S/", path_part_of_arg); - working_directory_string = path; - } + working_directory_string = path_normalized_from_string(scratch.arena, os_get_current_path(scratch.arena)); } // rjf: unpack arguments From 7fcba83282a8b37602493ba3b18065f6c7fb3202 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 10 Oct 2025 13:08:43 -0700 Subject: [PATCH 092/133] use debug info to infer language for files from including-unit language, if we cannot deduce it from extensions / settings (e.g. C++ .inl files) --- src/raddbg/raddbg_views.c | 53 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index e2786c58..5db18c39 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2082,6 +2082,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) if(rd_regs()->cursor.column == 0) { rd_regs()->cursor.column = 1; } if(rd_regs()->mark.line == 0) { rd_regs()->mark.line = 1; } if(rd_regs()->mark.column == 0) { rd_regs()->mark.column = 1; } + String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, rd_regs()->file_path); Rng1U64 range = rd_space_range_from_eval(eval); rd_regs()->text_key = rd_key_from_eval_space_range(eval.space, range, 1); String8 lang = rd_view_setting_from_name(str8_lit("lang")); @@ -2093,6 +2094,55 @@ RD_VIEW_UI_FUNCTION_DEF(text) { rd_regs()->lang_kind = txt_lang_kind_from_extension(lang); } + if(rd_regs()->lang_kind == TXT_LangKind_Null) + { + Access *access = access_open(); + CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); + if(rdi != &rdi_parsed_nil) + { + for EachNode(override_n, String8Node, overrides.first) + { + String8 file_path = override_n->string; + String8 file_path_normalized = lower_from_str8(scratch.arena, path_normalized_from_string(scratch.arena, file_path)); + B32 good_src_id = 0; + U32 src_id = 0; + RDI_NameMap *mapptr = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_NormalSourcePaths); + RDI_ParsedNameMap map = {0}; + rdi_parsed_from_name_map(rdi, mapptr, &map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, file_path_normalized.str, file_path_normalized.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); + if(id_count > 0) + { + U32 src_id = ids[0]; + RDI_SourceFile *src = rdi_element_from_name_idx(rdi, SourceFiles, src_id); + RDI_SourceLineMap *src_line_map = rdi_element_from_name_idx(rdi, SourceLineMaps, src->source_line_map_idx); + RDI_ParsedSourceLineMap parsed_src_line_map = {0}; + rdi_parsed_from_source_line_map(rdi, src_line_map, &parsed_src_line_map); + if(src_line_map->voff_count != 0) + { + RDI_Unit *unit = rdi_unit_from_voff(rdi, parsed_src_line_map.voffs[0]); + switch((RDI_LanguageEnum)unit->language) + { + case RDI_Language_NULL: + case RDI_Language_COUNT: + case RDI_Language_Masm: + {}break; + case RDI_Language_C: {rd_regs()->lang_kind = TXT_LangKind_C;}break; + case RDI_Language_CPlusPlus:{rd_regs()->lang_kind = TXT_LangKind_CPlusPlus;}break; + } + } + break; + } + } + } + } + access_close(access); + } U128 hash = {0}; TXT_TextInfo info = txt_text_info_from_key_lang(access, rd_regs()->text_key, rd_regs()->lang_kind, &hash); String8 data = c_data_from_hash(access, hash); @@ -2183,9 +2233,6 @@ RD_VIEW_UI_FUNCTION_DEF(text) { Temp scratch = scratch_begin(0, 0); - // rjf: gather file overrides - String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, rd_regs()->file_path); - // rjf: determine checksum in relevant debug infos RDI_ChecksumKind checksum_kind = RDI_ChecksumKind_NULL; String8 checksum_expected = {0}; From ac378b0ac22e2fff6c53b4aaeacea21c976cca0a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 10 Oct 2025 13:10:02 -0700 Subject: [PATCH 093/133] switch in file menu --- src/raddbg/raddbg_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 902fc001..13b0455f 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -7612,6 +7612,7 @@ rd_window_frame(void) String8 cmds[] = { rd_cmd_kind_info_table[RD_CmdKind_Open].string, + rd_cmd_kind_info_table[RD_CmdKind_Switch].string, rd_cmd_kind_info_table[RD_CmdKind_OpenPalette].string, rd_cmd_kind_info_table[RD_CmdKind_NewUser].string, rd_cmd_kind_info_table[RD_CmdKind_NewProject].string, @@ -7627,6 +7628,7 @@ rd_window_frame(void) U32 codepoints[] = { 'o', + 'i', 'n', 'w', 'j', From 8e452f10acbd5f3d8c7957cdc48c9a90f6b7ccbc Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 10 Oct 2025 13:50:47 -0700 Subject: [PATCH 094/133] v0.9.22-alpha changelog --- CHANGELOG.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c818c936..a0e53f8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,83 @@ -# Change Log v9.22.0-alpha +# v9.22.0-alpha -## Linker +## Debugger Changes + +- Further improved PDB -> RDI conversion performance. +- Capped the number of additional threads / processes spawned for PDB -> RDI + conversion. +- Prioritize PDB -> RDI conversion based on what is actually found to be + necessary by the debugger, rather than converting all PDBs in the order in + which they're discovered. +- Added preliminary support for DWARF -> RDI conversion on Windows. +- The debugger now relies on source file checksums to determine whether or not + a source file is out-of-date with respect to what was compiled when debug info + was produced, rather than just the modification timestamp. +- The debugger now will rely on debug info to detect the language of source code + files, if it cannot infer from the source file's extension, or view settings. + This will enable features like syntax highlighting and hover evaluation in + cases like `.inl` files being included in C++ projects. +- The debugger now will restore the last focused window when continuing + automatically. (#245, #596) +- Watch tables have been simplified in that they no longer have a separate + column for evaluation types, since this was usually taking a lot more space + than it deserved. The type of evaluations is still displayed in watch table + cells, and it can always be evaluated directly via `typeof`. +- Type evaluations have been simplified in watch tables as well; they no longer + have untitled columns for sizes and offsets, this is instead displayed as + an extra note by default. Similar behavior to the original behavior can still + be obtained using the `columns` view, if needed. +- The debugger no longer uses complex `union` types for most registers, and + instead just displays the register value plainly. +- The hover evaluation UI has been made larger when needed. +- The debugger now prefers matching global, function, and type identifiers to + the most relevant debug info and module in context; this fixes evaluation in + some multi-process debugging contexts. (#581) +- Fixed the debugger unnecessarily stripping `enum` type information when + accessed through array operators. (#634) +- The debugger now understands a standalone `unsigned` keyword as an + `unsigned int` type, to match C rules. +- The debugger now uses the current working directory to form the working + directory for targets specified on the command line, to match behavior when + running a command from the command line without the debugger. +- Improved call stack computation performance. +- Improved debugger memory usage over long periods of time. +- Fixed string-pointer comparison not working with not-equal (`!=`) operations. +- Fixed a bug which was causing bad debuggee performance on some threads after + some interactions with the debugger controller. +- Fixed incorrect results when adding two register values. (#642) +- Fixed the interpretation of register expressions in visualizers. (#649) +- Fixed "forever loading" states in disassembly views in some cases. (#643) +- Fixed jittering on window resizing. (#636) +- Fixed the bitmap visualizer crashing in some circumstances relating to + unsupported bitmap sizes. (#444, #563) +- Fixed a crash when an empty `cast()` expression would be evaluated. (#625) +- Fixed a crash when an invalid expression would be visualized using the `text` + view. (#647) + +## Linker Changes - Changed symbol resolution in libaries to match MSVC behavior. - Optimized image building step to reduce memory usage. -- Linker memory maps all input files by default to lower memory usage. (`/RAD_MEMORY_MAP_FILES`) -- If debug info is available, linker uses it to show file and line number for unresolved relocations. -- Improved base relocation build performance for large images, cutting build time by 70%. -- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability with existing response files +- Linker memory maps all input files by default to lower memory usage. + (`/RAD_MEMORY_MAP_FILES`) +- If debug info is available, linker uses it to show file and line number for + unresolved relocations. +- Improved base relocation build performance for large images, cutting build + time by 70%. +- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability + with existing response files - Implemented section garbage collection (`/OPT:REF`) - Fixed bug where thread local variables pointed to incorrect types. -- Changed rules for weak and undefined symbols, now weak symbol is not allowed to replace an undefined symbol. +- Changed rules for weak and undefined symbols, now weak symbol is not allowed + to replace an undefined symbol. - Linker no longer creates thunks for imports that don't require them. +## Binary Utility Changes +- The binary utility, like the debugger, now can convert DWARF debug info to + RDI files. When both DWARF and PDB info is present, it can now convert both, + and produce a single final RDI file with all information. +- Textual dumping of RDI files is now done in parallel, massively improving + dumping performance. +- PDB -> Breakpad conversion performance has now been parallelized to a greater + degree, improving performance. From b09e539534898cd830a5476d761138b6774811df Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 10 Oct 2025 14:35:13 -0700 Subject: [PATCH 095/133] fix build script for pgo --- build.bat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.bat b/build.bat index d3d2e6a4..9236ea1f 100644 --- a/build.bat +++ b/build.bat @@ -1,6 +1,7 @@ @echo off setlocal enabledelayedexpansion cd /D "%~dp0" +:restart :: --- Usage Notes (2024/1/10) ------------------------------------------------ :: @@ -168,5 +169,5 @@ if "%pgo_run%"=="1" ( call %~dp0build\radlink @lyra.rsp /rad_alt_pch_dir:%~dp0local\lyra_pgo || exit /b 1 popd ) - call %0 %* + goto restart ) From c934892006e46cbeb9db708753e0e78a8c2291b1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 10 Oct 2025 14:55:07 -0700 Subject: [PATCH 096/133] bump version to v0.9.23 --- CHANGELOG.md | 2 +- src/base/base_context_cracking.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0e53f8c..4c21e4e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v9.22.0-alpha +# v0.9.22-alpha ## Debugger Changes diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h index 50cb84a5..4065b166 100644 --- a/src/base/base_context_cracking.h +++ b/src/base/base_context_cracking.h @@ -159,7 +159,7 @@ #endif #if !defined(BUILD_VERSION_PATCH) -# define BUILD_VERSION_PATCH 22 +# define BUILD_VERSION_PATCH 23 #endif #define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH) From b9be24a17d556ee0d0dfedfab1e664665b617e28 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 10 Oct 2025 15:53:56 -0700 Subject: [PATCH 097/133] fix releasing of nil gpu buffer handles --- src/render/d3d11/render_d3d11.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/render/d3d11/render_d3d11.c b/src/render/d3d11/render_d3d11.c index c1170ead..6cf22683 100644 --- a/src/render/d3d11/render_d3d11.c +++ b/src/render/d3d11/render_d3d11.c @@ -801,7 +801,10 @@ r_buffer_release(R_Handle handle) MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Buffer *buffer = r_d3d11_buffer_from_handle(handle); - SLLStackPush(r_d3d11_state->first_to_free_buffer, buffer); + if(buffer != &r_d3d11_buffer_nil) + { + SLLStackPush(r_d3d11_state->first_to_free_buffer, buffer); + } } ProfEnd(); } From b41bf5b39efeef7fe6df0fafa62ef4e13eeb15dd Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 10 Oct 2025 16:20:34 -0700 Subject: [PATCH 098/133] update readme --- README.md | 54 ++++++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 84191fd3..64b7ce02 100644 --- a/README.md +++ b/README.md @@ -285,38 +285,45 @@ not depend on any other layers in the codebase. The folders which contain these layers are prefixed with `lib_`, like `lib_rdi`. A list of the layers in the codebase and their associated namespaces is below: -- `async` (`ASYNC_`): Implements a system for asynchronous work to be queued - and executed on a thread pool. +- `artifact_cache` (`AC_`): Implements an asynchronously-filled cache of + computation artifacts, which are automatically evicted when not accessed. Used + for asynchronously streaming and caching process memory and file system + contents, as well as asynchronously preparing visualizer data. - `base` (no namespace): Universal, codebase-wide constructs. Strings, math, memory allocators, helper macros, command-line parsing, and so on. Requires no other codebase layers. - `codeview` (`CV_`): Code for parsing and writing the CodeView format. - `coff` (`COFF_`): Code for parsing and writing the COFF (Common Object File Format) file format. +- `content` (`C_`): Implements a cache for general data blobs, keyed by a + 128-bit hash of the data. Also implements a keying system on top, where keys + refer to a unique identity which corresponds to a history of 128-bit hashes. + Used as a general data store by other layers. - `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements asynchronous process control, stepping, and breakpoints for all attached processes. Runs in lockstep with attached processes. When it runs, attached processes are halted. When attached processes are running, it is halted. Driven by a debugger frontend on another thread. -- `dasm_cache` (`DASM_`): Asynchronous disassembly computation, and a cache to - store asynchronously produced disassembly artifacts. -- `dbgi` (`DI_`): Asynchronous debug info loading, and a cache for loaded - debug info. Loads RAD Debug Info (RDI) files. Launches separate processes for - on-demand conversion to the RDI format if necessary. Also provides various - asynchronous operations for using debug information, like fuzzy searching - across all records in loaded debug information. - `dbg_engine` (`D_`): Implements the core debugger system, without any graphical components. This contains top-level logic for things like stepping, launching, freezing threads, mid-run breakpoint addition, some caches, and so on. +- `dbg_info` (`DI_`): Implements asynchronous debug info conversion and loading. + Maintains a cache for loaded debug info. Loads RAD Debug Info (RDI) files. + Launches separate processes for on-demand conversion to the RDI format if + necessary. Also provides various asynchronous operations for using debug info, + like fuzzy searching across all records in loaded debug info. - `demon` (`DMN_`): An abstraction layer for local-machine, low-level process control. The abstraction is used to provide a common interface for process control on target platforms. Used to implement part of `ctrl`. +- `disasm` (`DASM_`): Implements disassembly generation, including exposing the + ability to compute and cache disassembly asynchronously. - `draw` (`DR_`): Implements a high-level graphics drawing API for the debugger's purposes, using the underlying `render` abstraction layer. Provides high-level APIs for various draw commands, but takes care of batching them, and so on. - `dwarf` (`DW_`): Code for parsing the DWARF format. +- `eh` (`EH_`): Code for parsing the EH frame format. - `elf` (`ELF_`): Code for parsing the ELF format. - `eval` (`E_`): A compiler for an expression language, built for evaluation of variables, registers, types, and more, from debugger-attached processes, @@ -327,23 +334,17 @@ A list of the layers in the codebase and their associated namespaces is below: visualization engine, which can be used to visualize evaluations (provided by the `eval` layer) in a number of ways. Implements core data structures and transforms for watch tables. -- `file_stream` (`FS_`): Provides asynchronous file loading, storing the - artifacts inside of the cache implemented by the `hash_store` layer, and - hot-reloading the contents of files when they change. Allows callers to map - file paths to data hashes, which can then be used to obtain the file's data. +- `file_stream` (`FS_`): Implements asynchronous file streaming, storing the + artifacts inside of the cache implemented by the `content` and + `artifact_cache` layers, hot-reloading the contents of files when they change. + Allows callers to map file paths to data hashes, which can then be used to + obtain the file's data. - `font_cache` (`FNT_`): Implements a cache of rasterized font data, both in CPU-side data for text shaping, and in GPU texture atlases for rasterized glyphs. All cache information is sourced from the `font_provider` abstraction layer. - `font_provider` (`FP_`): An abstraction layer for various font file decoding and font rasterization backends. -- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU - geometry data, filled by data sourced in the `hash_store` layer's cache. Used - for asynchronously preparing data for visualization. -- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a - 128-bit hash of the data. Also implements a keying system on top, where keys - refer to a unique identity which corresponds to a history of 128-bit hashes. - Used as a general data store by other layers. - `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user programs to work with various features in the debugger. Does not depend on `base`, and can be independently relocated to other codebases. @@ -386,9 +387,6 @@ A list of the layers in the codebase and their associated namespaces is below: - `pdb` (`PDB_`): Code for parsing and writing the PDB file format. - `pe` (`PE_`): Code for parsing and writing the PE (Portable Executable) file format. -- `ptr_graph_cache` (`PG_`): An in-progress layer which will supply - asynchronously-computed pointer graphs, used for graph visualization in the - debugger, including structures like trees and linked lists. - `radbin` (`RB_`): The layer implementing the `radbin` binary utility executable. - `raddbg` (`RD_`): The layer which ties everything together for the main @@ -419,13 +417,9 @@ A list of the layers in the codebase and their associated namespaces is below: layer. - `scratch` (no namespace): Scratch space for small and transient test programs. - `tester` (no namespace): A program used for automated testing. -- `texture_cache` (`TEX_`): An asynchronously-filled cache for GPU texture data, - filled by data sourced in the `hash_store` layer's cache. Used for - asynchronously preparing data for visualization. -- `text_cache` (`TXT_`): An asynchronously-filled cache for textual analysis - data (tokens, line ranges, and so on), filled by data sourced in the - `hash_store` layer's cache. Used for asynchronously preparing data for - visualization (like for the source code viewer). +- `text` (`TXT_`): Implements text processing functions, like parsing line + breaks, and lexing and parsing source code. Also offers an API to do this + asynchronously. - `third_party` (no namespace): External code from other projects, which some layers in the codebase depend on. All external code is included and built directly within the codebase. From 6bcbf5909d630570dd7eb6ceb0781975875e160d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 13 Oct 2025 11:23:49 -0700 Subject: [PATCH 099/133] correctly handle bitfield type operators in eval viz string iterator --- src/eval_visualization/eval_visualization_core.c | 12 ++++++++++++ src/mule/mule_main.cpp | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/eval_visualization/eval_visualization_core.c b/src/eval_visualization/eval_visualization_core.c index 6d2c04ac..2451b70f 100644 --- a/src/eval_visualization/eval_visualization_core.c +++ b/src/eval_visualization/eval_visualization_core.c @@ -1769,6 +1769,18 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string) new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); }break; + ////////////////////////// + //- rjf: bitfields + // + case E_TypeKind_Bitfield: + { + need_pop = 1; + need_new_task = 1; + new_task.params = *params; + new_task.eval = e_value_eval_from_eval(eval); + new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); + }break; + ////////////////////////// //- rjf: pointers // diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index 00a60072..19f70cb2 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -523,6 +523,20 @@ type_coverage_eval_tests(void) Has_Enums has_enums = {(Kind)4, (Flag)7}; + struct EnumBitfields + { + Kind k1 : 4; + Kind k2 : 3; + Kind k3 : 1; + Kind k4 : 16; + }; + + EnumBitfields enum_bitfields = {}; + enum_bitfields.k1 = Kind_First; + enum_bitfields.k2 = Kind_Second; + enum_bitfields.k3 = Kind_None; + enum_bitfields.k4 = Kind_Fourth; + Crazy_Union crazy_union = {}; crazy_union.kind = Kind_First; From 87edc583bf81a9e7d5c83ababd47a08c73a21fb8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 13 Oct 2025 12:40:28 -0700 Subject: [PATCH 100/133] define ctrl entity eval spaces once, in ctrl layer - nest in rd layer --- src/ctrl/ctrl_core.c | 8 +--- src/ctrl/ctrl_core.h | 4 +- src/eval/eval_core.h | 4 +- src/eval/eval_interpret.c | 75 ++++++++++++++++++++++++++++-- src/eval/eval_interpret.h | 1 - src/eval/eval_types.c | 53 +++++++++++++++++++++ src/raddbg/raddbg_core.c | 92 +++++++++---------------------------- src/raddbg/raddbg_core.h | 9 ++-- src/raddbg/raddbg_eval.c | 2 +- src/raddbg/raddbg_views.c | 18 ++++---- src/raddbg/raddbg_widgets.c | 2 +- 11 files changed, 166 insertions(+), 102 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 4f922e78..66e3d0c3 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -4201,7 +4201,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, //- rjf: eval helpers internal B32 -ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) +ctrl_eval_space_read(E_Space space, void *out, Rng1U64 range) { B32 result = 0; switch(space.kind) @@ -4235,12 +4235,6 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) }break; } }break; - - //- rjf: meta evaluations - case CTRL_EvalSpaceKind_Meta: - { - - }break; } return result; } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 49cf7b78..9879a71a 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -357,7 +357,7 @@ typedef U64 CTRL_EvalSpaceKind; enum { CTRL_EvalSpaceKind_Entity = E_SpaceKind_FirstUserDefined, - CTRL_EvalSpaceKind_Meta, + CTRL_EvalSpaceKind_FirstUserDefined, }; //////////////////////////////// @@ -981,7 +981,7 @@ internal void ctrl_thread__module_close(CTRL_Handle process, CTRL_Handle module, internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); //- rjf: eval helpers -internal B32 ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 vaddr_range); +internal B32 ctrl_eval_space_read(E_Space space, void *out, Rng1U64 vaddr_range); //- rjf: control thread eval scopes internal CTRL_EvalScope *ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, CTRL_Entity *thread); diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index e658fdff..a0a35717 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -745,8 +745,8 @@ struct E_AutoHookParams //////////////////////////////// //~ rjf: Evaluation Context -typedef U64 E_SpaceGenFunction(void *user_data, E_Space space); -typedef B32 E_SpaceRWFunction(void *user_data, E_Space space, void *out, Rng1U64 offset_range); +typedef U64 E_SpaceGenFunction(E_Space space); +typedef B32 E_SpaceRWFunction(E_Space space, void *out, Rng1U64 offset_range); //- rjf: base context diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index a31993c1..74fffeda 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -61,7 +61,7 @@ e_space_gen(E_Space space) U64 result = 0; if(e_base_ctx->space_gen != 0) { - result = e_base_ctx->space_gen(e_base_ctx->space_rw_user_data, space); + result = e_base_ctx->space_gen(space); } return result; } @@ -71,9 +71,70 @@ e_space_read(E_Space space, void *out, Rng1U64 range) { ProfBeginFunction(); B32 result = 0; - if(e_interpret_ctx->space_read != 0) { - result = e_interpret_ctx->space_read(e_interpret_ctx->space_rw_user_data, space, out, range); + switch(space.kind) + { + //- rjf: reads from hash store key + case E_SpaceKind_HashStoreKey: + { + C_Root root = {space.u64_0}; + C_ID id = {space.u128}; + C_Key key = c_key_make(root, id); + U128 hash = c_hash_from_key(key, 0); + Access *access = access_open(); + { + String8 data = c_data_from_hash(access, hash); + Rng1U64 legal_range = r1u64(0, data.size); + Rng1U64 read_range = intersect_1u64(range, legal_range); + if(read_range.min < read_range.max) + { + result = 1; + MemoryCopy(out, data.str + read_range.min, dim_1u64(read_range)); + } + } + access_close(access); + }break; + + //- rjf: file reads + case E_SpaceKind_File: + { + // rjf: unpack space/path + U64 file_path_string_id = space.u64_0; + String8 file_path = e_string_from_id(file_path_string_id); + + // rjf: find containing chunk range + U64 chunk_size = KB(4); + Rng1U64 containing_range = range; + containing_range.min -= containing_range.min%chunk_size; + containing_range.max += chunk_size-1; + containing_range.max -= containing_range.max%chunk_size; + + // rjf: map to hash + C_Key key = fs_key_from_path_range(file_path, containing_range, 0); + U128 hash = c_hash_from_key(key, 0); + + // rjf: look up from hash store + Access *access = access_open(); + { + String8 data = c_data_from_hash(access, hash); + Rng1U64 legal_range = r1u64(containing_range.min, containing_range.min + data.size); + Rng1U64 read_range = intersect_1u64(range, legal_range); + if(read_range.min < read_range.max) + { + result = 1; + MemoryCopy(out, data.str + read_range.min - containing_range.min, dim_1u64(read_range)); + } + } + access_close(access); + }break; + + //- rjf: default -> use hooks + default: + if(e_interpret_ctx->space_read != 0) + { + result = e_interpret_ctx->space_read(space, out, range); + }break; + } } ProfEnd(); return result; @@ -86,7 +147,13 @@ e_space_write(E_Space space, void *in, Rng1U64 range) B32 result = 0; if(e_interpret_ctx->space_write != 0) { - result = e_interpret_ctx->space_write(e_interpret_ctx->space_rw_user_data, space, in, range); + switch(space.kind) + { + default: + { + result = e_interpret_ctx->space_write(space, in, range); + }break; + } } ProfEnd(); return result; diff --git a/src/eval/eval_interpret.h b/src/eval/eval_interpret.h index cca6cd97..4151a837 100644 --- a/src/eval/eval_interpret.h +++ b/src/eval/eval_interpret.h @@ -10,7 +10,6 @@ typedef struct E_InterpretCtx E_InterpretCtx; struct E_InterpretCtx { - void *space_rw_user_data; E_SpaceRWFunction *space_read; E_SpaceRWFunction *space_write; E_Space primary_space; diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index fb580740..23deef63 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -2570,6 +2570,59 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(array) } } +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `list` lens + +typedef struct E_ListGatherArtifact E_ListGatherArtifact; +struct E_ListGatherArtifact +{ + U64 *node_vaddrs; + U64 node_vaddrs_count; +}; + +internal AC_Artifact +e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) +{ + +} + +internal void +e_list_gather_artifact_destroy(AC_Artifact artifact) +{ + +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(list) +{ + E_Type *type = e_type_from_key(eval.irtree.type_key); + String8 next_link_member_name = str8_lit("next"); + if(type->args != 0 && type->count > 0) + { + next_link_member_name = type->args[0]->string; + } + E_TypeKey node_type_key = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_All); + E_Member next_link_member = e_type_member_from_key_name__cached(node_type_key, next_link_member_name); + if(next_link_member.kind != E_MemberKind_DataField) + { + // TODO(rjf): error reporting + } + else + { + + } + E_TypeExpandInfo info = {0, 0}; + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(list) +{ + U64 read_range_count = dim_1u64(idx_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + evals_out[idx] = e_eval_wrapf(eval, "$[%I64u]", idx_range.min + idx); + } +} + //////////////////////////////// //~ rjf: (Built-In Type Hooks) `slice` lens diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 13b0455f..a5ab4c9b 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1684,7 +1684,7 @@ internal CTRL_Entity * rd_ctrl_entity_from_eval_space(E_Space space) { CTRL_Entity *entity = &ctrl_entity_nil; - if(space.kind == RD_EvalSpaceKind_CtrlEntity || + if(space.kind == CTRL_EvalSpaceKind_Entity || space.kind == RD_EvalSpaceKind_MetaCtrlEntity || space.kind == RD_EvalSpaceKind_MetaUnattachedProcess) { @@ -1721,7 +1721,7 @@ rd_cmd_name_from_eval(E_Eval eval) //- rjf: eval space reads/writes internal U64 -rd_eval_space_gen(void *u, E_Space space) +rd_eval_space_gen(E_Space space) { U64 result = 0; switch(space.kind) @@ -1736,68 +1736,19 @@ rd_eval_space_gen(void *u, E_Space space) } internal B32 -rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) +rd_eval_space_read(E_Space space, void *out, Rng1U64 range) { Temp scratch = scratch_begin(0, 0); B32 result = 0; switch(space.kind) { - //- rjf: reads from hash store key - case E_SpaceKind_HashStoreKey: + default: { - C_Root root = {space.u64_0}; - C_ID id = {space.u128}; - C_Key key = c_key_make(root, id); - U128 hash = c_hash_from_key(key, 0); - Access *access = access_open(); - { - String8 data = c_data_from_hash(access, hash); - Rng1U64 legal_range = r1u64(0, data.size); - Rng1U64 read_range = intersect_1u64(range, legal_range); - if(read_range.min < read_range.max) - { - result = 1; - MemoryCopy(out, data.str + read_range.min, dim_1u64(read_range)); - } - } - access_close(access); - }break; - - //- rjf: file reads - case E_SpaceKind_File: - { - // rjf: unpack space/path - U64 file_path_string_id = space.u64_0; - String8 file_path = e_string_from_id(file_path_string_id); - - // rjf: find containing chunk range - U64 chunk_size = KB(4); - Rng1U64 containing_range = range; - containing_range.min -= containing_range.min%chunk_size; - containing_range.max += chunk_size-1; - containing_range.max -= containing_range.max%chunk_size; - - // rjf: map to hash - C_Key key = fs_key_from_path_range(file_path, containing_range, 0); - U128 hash = c_hash_from_key(key, 0); - - // rjf: look up from hash store - Access *access = access_open(); - { - String8 data = c_data_from_hash(access, hash); - Rng1U64 legal_range = r1u64(containing_range.min, containing_range.min + data.size); - Rng1U64 read_range = intersect_1u64(range, legal_range); - if(read_range.min < read_range.max) - { - result = 1; - MemoryCopy(out, data.str + read_range.min - containing_range.min, dim_1u64(read_range)); - } - } - access_close(access); + result = ctrl_eval_space_read(space, out, range); }break; //- rjf: interior control entity reads (inside process address space or thread register block) - case RD_EvalSpaceKind_CtrlEntity: + case CTRL_EvalSpaceKind_Entity: { CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); switch(entity->kind) @@ -1997,7 +1948,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) } internal B32 -rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range) +rd_eval_space_write(E_Space space, void *in, Rng1U64 range) { B32 result = 0; switch(space.kind) @@ -2006,7 +1957,7 @@ rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range) //- rjf: interior control entity writes (inside process address space or // thread register block) - case RD_EvalSpaceKind_CtrlEntity: + case CTRL_EvalSpaceKind_Entity: { CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); switch(entity->kind) @@ -2082,6 +2033,7 @@ rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range) } }break; + //- rjf: meta-ctrl-entity writes case RD_EvalSpaceKind_MetaCtrlEntity: { Temp scratch = scratch_begin(0, 0); @@ -2154,7 +2106,7 @@ rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated) String8 file_path = e_string_from_id(file_path_string_id); result = fs_key_from_path_range(file_path, range, 0); }break; - case RD_EvalSpaceKind_CtrlEntity: + case CTRL_EvalSpaceKind_Entity: { CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); if(entity->kind == CTRL_EntityKind_Process) @@ -2194,7 +2146,7 @@ rd_whole_range_from_eval_space(E_Space space) FileProperties props = os_properties_from_file_path(file_path); result = r1u64(0, props.size); }break; - case RD_EvalSpaceKind_CtrlEntity: + case CTRL_EvalSpaceKind_Entity: { CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); if(entity->kind == CTRL_EntityKind_Process) @@ -4536,7 +4488,7 @@ rd_view_ui(Rng2F32 rect) //////////////////// //- rjf: draw start of cache lines in expansions // - if(row->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && row_info->view_ui_rule == &rd_nil_view_ui_rule) + if(row->eval.space.kind == CTRL_EvalSpaceKind_Entity && row_info->view_ui_rule == &rd_nil_view_ui_rule) { CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(row->eval.space); if(space_entity->kind == CTRL_EntityKind_Process) @@ -4557,7 +4509,7 @@ rd_view_ui(Rng2F32 rect) ////////////// //- rjf: draw mid-row cache line boundaries in expansions // - if(row->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && row_info->view_ui_rule == &rd_nil_view_ui_rule) + if(row->eval.space.kind == CTRL_EvalSpaceKind_Entity && row_info->view_ui_rule == &rd_nil_view_ui_rule) { CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(row->eval.space); if(space_entity->kind == CTRL_EntityKind_Process && @@ -4639,7 +4591,7 @@ rd_view_ui(Rng2F32 rect) cell_is_rich_hovered = (intersection.max > intersection.min); } CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(cell->eval.space); - if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && space_entity->kind == CTRL_EntityKind_Process) + if(cell->eval.space.kind == CTRL_EvalSpaceKind_Entity && space_entity->kind == CTRL_EntityKind_Process) { CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, space_entity->handle, cell_vaddr_rng, 0, rd_state->frame_eval_memread_endt_us); for(U64 idx = 0; idx < (slice.data.size+63)/64; idx += 1) @@ -5044,7 +4996,7 @@ rd_view_ui(Rng2F32 rect) // rjf: apply type note if(!(cell_info.flags & RD_WatchCellFlag_NoEval) && - cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && + cell->eval.space.kind == CTRL_EvalSpaceKind_Entity && row_info->callstack_thread == &ctrl_entity_nil && e_type_kind_from_key(cell->eval.irtree.type_key) != E_TypeKind_Function) UI_FontSize(ui_top_font_size()*0.9f) @@ -5169,7 +5121,7 @@ rd_view_ui(Rng2F32 rect) case CTRL_EntityKind_Thread:{RD_RegsScope(.thread = cell_info.entity->handle) rd_drag_begin(RD_RegSlot_Thread);}break; } } - else if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity || + else if(cell->eval.space.kind == CTRL_EvalSpaceKind_Entity || cell->eval.space.kind == E_SpaceKind_FileSystem || cell->eval.space.kind == E_SpaceKind_File || cell->eval.space.kind == E_SpaceKind_Null) @@ -5323,7 +5275,7 @@ rd_view_ui(Rng2F32 rect) } // rjf: can't edit, but has address info? -> go to address - else if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity) + else if(cell->eval.space.kind == CTRL_EvalSpaceKind_Entity) { CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(cell->eval.space); CTRL_Entity *process = ctrl_process_from_entity(entity); @@ -7099,7 +7051,7 @@ rd_window_frame(void) build_hover_eval = 0; } else if((hover_eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || - hover_eval.space.kind == RD_EvalSpaceKind_CtrlEntity) && + hover_eval.space.kind == CTRL_EvalSpaceKind_Entity) && rd_ctrl_entity_from_eval_space(hover_eval.space) == &ctrl_entity_nil) { build_hover_eval = 0; @@ -7200,7 +7152,7 @@ rd_window_frame(void) rd_cmd(RD_CmdKind_CancelQuery); } else if((eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || - eval.space.kind == RD_EvalSpaceKind_CtrlEntity) && + eval.space.kind == CTRL_EvalSpaceKind_Entity) && rd_ctrl_entity_from_eval_space(eval.space) == &ctrl_entity_nil) { query_is_open = 0; @@ -11917,7 +11869,7 @@ rd_frame(void) eval_modules[eval_module_idx].dbgi_key = dbgi_key; eval_modules[eval_module_idx].rdi = di_rdi_from_key(rd_state->frame_access, dbgi_key, 0, 0); eval_modules[eval_module_idx].vaddr_range = m->vaddr_range; - eval_modules[eval_module_idx].space = rd_eval_space_from_ctrl_entity(ctrl_entity_ancestor_from_kind(m, CTRL_EntityKind_Process), RD_EvalSpaceKind_CtrlEntity); + eval_modules[eval_module_idx].space = rd_eval_space_from_ctrl_entity(ctrl_entity_ancestor_from_kind(m, CTRL_EntityKind_Process), CTRL_EvalSpaceKind_Entity); if(module == m) { eval_modules_primary = &eval_modules[eval_module_idx]; @@ -11942,7 +11894,7 @@ rd_frame(void) //- rjf: fill instruction pointer info ctx->thread_ip_vaddr = rip_vaddr; ctx->thread_ip_voff = rip_voff; - ctx->thread_reg_space = rd_eval_space_from_ctrl_entity(thread, RD_EvalSpaceKind_CtrlEntity); + ctx->thread_reg_space = rd_eval_space_from_ctrl_entity(thread, CTRL_EvalSpaceKind_Entity); ctx->thread_arch = thread->arch; ctx->thread_unwind_count = unwind_count; @@ -12737,7 +12689,7 @@ rd_frame(void) ctx->space_write = rd_eval_space_write; ctx->primary_space = eval_modules_primary->space; ctx->reg_arch = eval_modules_primary->arch; - ctx->reg_space = rd_eval_space_from_ctrl_entity(thread, RD_EvalSpaceKind_CtrlEntity); + ctx->reg_space = rd_eval_space_from_ctrl_entity(thread, CTRL_EvalSpaceKind_Entity); ctx->reg_unwind_count = unwind_count; ctx->module_base = push_array(scratch.arena, U64, 1); ctx->module_base[0] = module->vaddr_range.min; diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index ad58381e..1f54172d 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -81,8 +81,7 @@ struct RD_KeyMap typedef U64 RD_EvalSpaceKind; enum { - RD_EvalSpaceKind_CtrlEntity = E_SpaceKind_FirstUserDefined, - RD_EvalSpaceKind_MetaQuery, + RD_EvalSpaceKind_MetaQuery = CTRL_EvalSpaceKind_FirstUserDefined, RD_EvalSpaceKind_MetaCfg, RD_EvalSpaceKind_MetaCmd, RD_EvalSpaceKind_MetaTheme, @@ -889,9 +888,9 @@ internal E_Space rd_eval_space_from_ctrl_entity(CTRL_Entity *entity, E_SpaceKind internal String8 rd_cmd_name_from_eval(E_Eval eval); //- rjf: eval space reads/writes -internal U64 rd_eval_space_gen(void *u, E_Space space); -internal B32 rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range); -internal B32 rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range); +internal U64 rd_eval_space_gen(E_Space space); +internal B32 rd_eval_space_read(E_Space space, void *out, Rng1U64 range); +internal B32 rd_eval_space_write(E_Space space, void *in, Rng1U64 range); //- rjf: asynchronous streamed reads -> hashes from spaces internal C_Key rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated); diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index e5b35811..d07597b5 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -978,7 +978,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(call_stack) { CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, accel->process); CTRL_CallStackFrame *f = &call_stack->frames[rhs_value.u64]; - result.root = e_irtree_set_space(arena, rd_eval_space_from_ctrl_entity(process, RD_EvalSpaceKind_CtrlEntity), e_irtree_const_u(arena, regs_rip_from_arch_block(accel->arch, f->regs))); + result.root = e_irtree_set_space(arena, rd_eval_space_from_ctrl_entity(process, CTRL_EvalSpaceKind_Entity), e_irtree_const_u(arena, regs_rip_from_arch_block(accel->arch, f->regs))); result.type_key = e_type_key_cons(.arch = process->arch, .kind = E_TypeKind_Ptr, .direct_key = e_type_key_basic(E_TypeKind_Function), .count = 1, .depth = f->inline_depth); result.mode = E_Mode_Value; } diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 5db18c39..1f832c49 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -993,7 +993,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) //////////////////////////// //- rjf: fill row's module // - if(row->eval.space.kind == RD_EvalSpaceKind_CtrlEntity) + if(row->eval.space.kind == CTRL_EvalSpaceKind_Entity) { CTRL_Entity *row_ctrl_entity = rd_ctrl_entity_from_eval_space(row->eval.space); switch(row_ctrl_entity->kind) @@ -1782,7 +1782,7 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla { string_params.radix = 16; } - if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && + if(cell->eval.space.kind == CTRL_EvalSpaceKind_Entity && rd_ctrl_entity_from_eval_space(cell->eval.space)->kind == CTRL_EntityKind_Thread) { string_params.radix = 16; @@ -2431,13 +2431,13 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) if(dv->temp_look_vaddr != 0 && dv->temp_look_run_gen == ctrl_run_gen()) { auto_selected = 1; - auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, dv->temp_look_process), RD_EvalSpaceKind_CtrlEntity); + auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, dv->temp_look_process), CTRL_EvalSpaceKind_Entity); eval = e_eval_from_stringf("(0x%I64x & (~(0x4000 - 1)))", dv->temp_look_vaddr); } else { auto_selected = 1; - auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); + auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), CTRL_EvalSpaceKind_Entity); eval = e_eval_from_stringf("(reg:rip & (~(0x4000 - 1)))"); } } @@ -2539,7 +2539,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) U128 dasm_text_hash = {0}; TXT_TextInfo dasm_text_info = txt_text_info_from_key_lang(access, rd_regs()->text_key, rd_regs()->lang_kind, &dasm_text_hash); String8 dasm_text_data = c_data_from_hash(access, dasm_text_hash); - B32 is_loading = (dasm_text_info.lines_count == 0 && dim_1u64(range) != 0 && eval.msgs.max_kind == E_MsgKind_Null && (space.kind != RD_EvalSpaceKind_CtrlEntity || space_entity != &ctrl_entity_nil)); + B32 is_loading = (dasm_text_info.lines_count == 0 && dim_1u64(range) != 0 && eval.msgs.max_kind == E_MsgKind_Null && (space.kind != CTRL_EvalSpaceKind_Entity || space_entity != &ctrl_entity_nil)); B32 has_disasm = (dasm_text_info.lines_count != 0 && dasm_info.lines.count != 0); ////////////////////////////// @@ -2670,7 +2670,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) Rng1U64 view_range = rd_space_range_from_eval(eval); if(eval.space.kind == 0) { - eval.space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); + eval.space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), CTRL_EvalSpaceKind_Entity); view_range = rd_whole_range_from_eval_space(eval.space); } @@ -3035,7 +3035,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) { e_space_read(eval.space, visible_memory, viz_range_bytes); } - if(eval.space.kind == RD_EvalSpaceKind_CtrlEntity) + if(eval.space.kind == CTRL_EvalSpaceKind_Entity) { CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); if(entity->kind == CTRL_EntityKind_Process) @@ -3077,7 +3077,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) CTRL_Entity *selected_process = ctrl_entity_ancestor_from_kind(selected_thread, CTRL_EntityKind_Process); CTRL_CallStack selected_call_stack = ctrl_call_stack_from_thread(access, selected_thread->handle, 1, 0); CTRL_Entity *eval_process = &ctrl_entity_nil; - if(eval.space.kind == RD_EvalSpaceKind_CtrlEntity) + if(eval.space.kind == CTRL_EvalSpaceKind_Entity) { eval_process = rd_ctrl_entity_from_eval_space(eval.space); } @@ -3149,7 +3149,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) } //- rjf: fill local variable annotations - if(e_space_match(rd_eval_space_from_ctrl_entity(selected_process, RD_EvalSpaceKind_CtrlEntity), eval.space)) + if(e_space_match(rd_eval_space_from_ctrl_entity(selected_process, CTRL_EvalSpaceKind_Entity), eval.space)) { Vec4F32 local_color = ui_color_from_name(str8_lit("code_local")); Vec4F32 color_gen_table[] = diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 36cbe7f6..95f84b74 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -2565,7 +2565,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { E_Eval eval = e_eval_from_string(mouse_expr); B32 eval_implicit_hover = (eval.irtree.mode != E_Mode_Null && - eval.space.kind == RD_EvalSpaceKind_CtrlEntity); + eval.space.kind == CTRL_EvalSpaceKind_Entity); if(eval.msgs.max_kind == E_MsgKind_Null && (eval_implicit_hover || mouse_expr_is_explicit)) { U64 line_vaddr = 0; From ec39cefc9e5aff06c0cbfaaeca772f2499abdc46 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 13 Oct 2025 12:47:46 -0700 Subject: [PATCH 101/133] correctly decompress rdis in radbin dumping path; do not compress zero-sized sections in rdi make --- src/radbin/radbin.c | 7 +++++++ src/rdi_make/rdi_make_local.c | 7 +------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 9788b5f7..fd3220dc 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -1152,6 +1152,13 @@ rb_thread_entry_point(void *p) { RDI_Parsed rdi = {0}; RDI_ParseStatus rdi_status = rdi_parse(f->data.str, f->data.size, &rdi); + U64 decompressed_size = rdi_decompressed_size_from_parsed(&rdi); + if(decompressed_size > rdi.raw_data_size) + { + U8 *decompressed_data = push_array_no_zero(arena, U8, decompressed_size); + rdi_decompress_parsed(decompressed_data, decompressed_size, &rdi); + rdi_status = rdi_parse(decompressed_data, decompressed_size, &rdi); + } switch(rdi_status) { default:{}break; diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 70ccc333..d6678622 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -2982,12 +2982,7 @@ rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in) RDIM_SerializedSection *src = &in->sections[k]; RDIM_SerializedSection *dst = &out.sections[k]; MemoryCopyStruct(dst, src); - - // rjf: determine if this section should be compressed - B32 should_compress = 1; - - // rjf: compress if needed - if(should_compress) + if(src->encoded_size != 0) { MemoryZero(ctx.m_hashTable, sizeof(U16)*(1<data = push_array_no_zero(arena, U8, src->encoded_size); From b688c69f13ecbbd581843279b70ebaa42c5b2073 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 13 Oct 2025 13:07:37 -0700 Subject: [PATCH 102/133] radbin: compress sections wide, deduplicate work --- src/radbin/radbin.c | 15 ++++++++++----- src/rdi_make/rdi_make_local.c | 17 ++++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index fd3220dc..5424e039 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -775,7 +775,7 @@ rb_thread_entry_point(void *p) //- rjf: bake RDIM_BakeResults bake_results = {0}; - if(convert_done) ProfScope("bake") + ProfScope("bake") { bake_results = rdim_bake(arena, bake_params); } @@ -789,14 +789,19 @@ rb_thread_entry_point(void *p) case OutputKind_RDI: { // rjf: serialize - RDIM_SerializedSectionBundle serialized_section_bundle = {0}; - ProfScope("serialize") serialized_section_bundle = rdim_serialized_section_bundle_from_bake_results(&bake_results); + RDIM_SerializedSectionBundle *serialized_section_bundle = 0; + ProfScope("serialize") if(lane_idx() == 0) + { + serialized_section_bundle = push_array(arena, RDIM_SerializedSectionBundle, 1); + serialized_section_bundle[0] = rdim_serialized_section_bundle_from_bake_results(&bake_results); + } + lane_sync_u64(&serialized_section_bundle, 0); // rjf: compress - RDIM_SerializedSectionBundle serialized_section_bundle__compressed = serialized_section_bundle; + RDIM_SerializedSectionBundle serialized_section_bundle__compressed = serialized_section_bundle[0]; if(cmd_line_has_flag(cmdline, str8_lit("compress"))) ProfScope("compress") { - serialized_section_bundle__compressed = rdim_compress(arena, &serialized_section_bundle); + serialized_section_bundle__compressed = rdim_compress(arena, serialized_section_bundle); } // rjf: serialize diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index d6678622..90eebbcc 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -2969,18 +2969,23 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) internal RDIM_SerializedSectionBundle rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in) { - RDIM_SerializedSectionBundle out = {0}; + Temp scratch = scratch_begin(&arena, 1); + RDIM_SerializedSectionBundle out_ = {0}; + RDIM_SerializedSectionBundle *out = &out_; + lane_sync_u64(&out, 0); //- rjf: set up compression context rr_lzb_simple_context ctx = {0}; ctx.m_tableSizeBits = 14; - ctx.m_hashTable = push_array(arena, U16, 1<sections[k]; - RDIM_SerializedSection *dst = &out.sections[k]; + RDIM_SerializedSection *dst = &out->sections[k]; MemoryCopyStruct(dst, src); if(src->encoded_size != 0) { @@ -2991,6 +2996,8 @@ rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in) dst->encoding = RDI_SectionEncoding_LZB; } } + lane_sync(); - return out; + scratch_end(scratch); + return *out; } From 89be41fda95f7a247ce0f452dbe04593239549e7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 13 Oct 2025 17:00:01 -0700 Subject: [PATCH 103/133] checkpoint: first pass at wide vmap baking --- src/rdi_make/rdi_make_local.c | 214 +++++++++++++++++++++++++++++++++- 1 file changed, 213 insertions(+), 1 deletion(-) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 90eebbcc..44cc2096 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -446,7 +446,6 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) // * we must process _all_ of the changes that apply at this voff before moving on // RDI_U64 voff = key_ptr->key; - for(;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1) { RDIM_VMapMarker *marker = (RDIM_VMapMarker*)key_ptr->val; @@ -537,6 +536,219 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake all vmaps (NEW) + // +#if 0 + ProfScope("bake all vmaps (NEW)") + { + Temp scratch = scratch_begin(&arena, 1); + RDI_U64 count = rdim_shared->scope_vmap_count; + RDIM_SortKey *keys = rdim_shared->scope_vmap_keys; + + //- rjf: do vmap entry generation for portions of the keys array + typedef struct VMapRangeTask VMapRangeTask; + struct VMapRangeTask + { + VMapRangeTask *next; + U32 idx; + }; + Rng1U64 range = lane_range(count); + RDI_U64 lane_vmap_count_cap = dim_1u64(range); + RDI_VMapEntry *lane_vmap = push_array(arena, RDI_VMapEntry, lane_vmap_count_cap); + VMapRangeTask *top_range_task = 0; + RDI_U64 lane_vmap_count_actual = 0; + ProfScope("do vmap entry generation for portions of the keys array") + { + VMapRangeTask *free_range_task = 0; + RDI_VMapEntry *lane_vmap_ptr = lane_vmap; + RDIM_SortKey *key_ptr = keys + range.min; + RDIM_SortKey *key_opl = keys + range.max; + for(;key_ptr < key_opl;) + { + // rjf: get initial range index from range task stack + RDI_U32 initial_idx = (RDI_U32)0xffffffff; + if(top_range_task != 0) + { + initial_idx = top_range_task->idx; + } + + // rjf: update range task stack + // + // * we must process _all_ of the changes that apply at this voff before moving on + // + RDI_U64 voff = key_ptr->key; + B32 failed_pop = 0; + for(;key_ptr < key_opl && key_ptr->key == voff && !failed_pop; key_ptr += 1) + { + RDIM_VMapMarker *marker = (RDIM_VMapMarker *)key_ptr->val; + RDI_U32 idx = marker->idx; + + // rjf: range begin -> push to stack + if(marker->begin_range) + { + VMapRangeTask *task = free_range_task; + if(task != 0) + { + RDIM_SLLStackPop(free_range_task); + } + else + { + task = rdim_push_array(scratch.arena, VMapRangeTask, 1); + } + RDIM_SLLStackPush(top_range_task, task); + task->idx = idx; + } + + // rjf: range ending -> pop matching node from stack (not always the top) + else + { + VMapRangeTask **ptr_in = &top_range_task; + VMapRangeTask *match = 0; + for(VMapRangeTask *node = top_range_task; node != 0;) + { + if(node->idx == idx) + { + match = node; + break; + } + ptr_in = &node->next; + node = node->next; + } + if(match != 0) + { + *ptr_in = match->next; + RDIM_SLLStackPush(free_range_task, match); + } + else + { + failed_pop = 1; + } + } + } + + // rjf: get final map state from tracker stack + RDI_U32 final_idx = 0; + if(top_range_task != 0) + { + final_idx = top_range_task->idx; + } + + // rjf: if final is different from initial - emit new vmap entry + if(failed_pop) + { + lane_vmap_ptr->voff = voff; + lane_vmap_ptr->idx = 0xffffffff; + lane_vmap_ptr += 1; + } + else if(final_idx != initial_idx) + { + lane_vmap_ptr->voff = voff; + lane_vmap_ptr->idx = final_idx; + lane_vmap_ptr += 1; + } + } + lane_vmap_count_actual = (lane_vmap_ptr - lane_vmap); + } + + //- rjf: collect all per-lane artifacts + RDI_U64 *lane_vmaps_counts = 0; + VMapRangeTask **lane_leftover_tasks = 0; + ProfScope("collect all lane vmap counts") + { + if(lane_idx() == 0) + { + lane_vmaps_counts = push_array(scratch.arena, RDI_U64, lane_count()); + lane_leftover_tasks = push_array(arena, VMapRangeTask *, lane_count()); + } + lane_sync_u64(&lane_vmaps_counts, 0); + lane_sync_u64(&lane_leftover_tasks, 0); + lane_vmaps_counts[lane_idx()] = lane_vmap_count_actual; + lane_leftover_tasks[lane_idx()] = top_range_task; + } + lane_sync(); + + //- rjf: apply leftovers to per-lane vmaps + if(lane_idx() > 0) + { + VMapRangeTask *top_leftover_task = lane_leftover_tasks[lane_idx()-1]; + for EachIndex(idx, lane_vmap_count_actual) + { + if(!top_leftover_task) + { + break; + } + if(lane_vmap[idx].idx == 0xffffffff) + { + SLLStackPop(top_leftover_task); + if(top_leftover_task) + { + lane_vmap[idx].idx = top_leftover_task->idx; + } + } + } + } + lane_idx(); + + //- rjf: lay out all lane vmaps into single range + RDI_U64 *lane_vmaps_offs = 0; + RDI_U64 lane_vmap_count_total = 0; + ProfScope("lay out all lane vmaps into single range") + { + if(lane_idx() == 0) + { + lane_vmaps_offs = push_array(scratch.arena, RDI_U64, lane_count()); + RDI_U64 off = 0; + for EachIndex(lidx, lane_count()) + { + lane_vmaps_offs[lidx] = off; + off += lane_vmaps_counts[lidx]; + } + lane_vmap_count_total = off; + } + } + lane_sync_u64(&lane_vmaps_offs, 0); + lane_sync_u64(&lane_vmap_count_total, 0); + + //- rjf: join all lane vmaps + RDI_U64 vmap_count = lane_vmap_count_total + 1; + RDI_VMapEntry *vmap = 0; + ProfScope("join all lane vmaps") + { + if(lane_idx() == 0) + { + vmap = push_array_no_zero(arena, RDI_VMapEntry, vmap_count); + } + lane_sync_u64(&vmap, 0); + MemoryCopy(vmap + lane_vmaps_offs[lane_idx()], lane_vmap, sizeof(lane_vmap[0])*lane_vmaps_counts[lane_idx()]); + } + lane_sync(); + + //- rjf: combine duplicate neighbors + RDI_U64 vmap_count__deduplicated = 0; + ProfScope("combine duplicate neighbors") if(lane_idx() == 0) + { + RDI_VMapEntry *vmap_ptr = vmap; + RDI_VMapEntry *vmap_opl = vmap + vmap_count; + RDI_VMapEntry *vmap_out = vmap; + for(;vmap_ptr < vmap_opl;) + { + RDI_VMapEntry *vmap_range_first = vmap_ptr; + RDI_U64 idx = vmap_ptr->idx; + vmap_ptr += 1; + for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; + rdim_memcpy_struct(vmap_out, vmap_range_first); + vmap_out += 1; + } + vmap_count__deduplicated = (RDI_U64)(vmap_out - vmap); + } + lane_sync_u64(&vmap_count__deduplicated, 0); + + scratch_end(scratch); + } + lane_sync(); +#endif + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build interned path tree // From 010825a0bb1a5a269e9a2d72127cd6c1021cb482 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 13 Oct 2025 17:32:53 -0700 Subject: [PATCH 104/133] checkpoint on attempt at wide vmap baking --- src/rdi_make/rdi_make_local.c | 66 +++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 44cc2096..60ed1861 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -553,10 +553,19 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) VMapRangeTask *next; U32 idx; }; + typedef struct VMapFixupTask VMapFixupTask; + struct VMapFixupTask + { + VMapFixupTask *next; + VMapFixupTask *prev; + U64 idx; + }; Rng1U64 range = lane_range(count); RDI_U64 lane_vmap_count_cap = dim_1u64(range); RDI_VMapEntry *lane_vmap = push_array(arena, RDI_VMapEntry, lane_vmap_count_cap); VMapRangeTask *top_range_task = 0; + VMapFixupTask *first_fixup_task = 0; + VMapFixupTask *last_fixup_task = 0; RDI_U64 lane_vmap_count_actual = 0; ProfScope("do vmap entry generation for portions of the keys array") { @@ -634,13 +643,18 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) final_idx = top_range_task->idx; } - // rjf: if final is different from initial - emit new vmap entry + // rjf: failed pop -> rely on latter pass, need cross-lane information. remember this spot to fixup if(failed_pop) { + VMapFixupTask *fixup_task = push_array(scratch.arena, VMapFixupTask, 1); + fixup_task->idx = (U64)(lane_vmap_ptr - lane_vmap); + DLLPushBack(first_fixup_task, last_fixup_task, fixup_task); lane_vmap_ptr->voff = voff; lane_vmap_ptr->idx = 0xffffffff; lane_vmap_ptr += 1; } + + // rjf: if final is different from initial - emit new vmap entry else if(final_idx != initial_idx) { lane_vmap_ptr->voff = voff; @@ -653,42 +667,64 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: collect all per-lane artifacts RDI_U64 *lane_vmaps_counts = 0; + RDI_VMapEntry **lane_vmaps = 0; VMapRangeTask **lane_leftover_tasks = 0; + VMapFixupTask **lane_first_fixup_tasks = 0; + VMapFixupTask **lane_last_fixup_tasks = 0; ProfScope("collect all lane vmap counts") { if(lane_idx() == 0) { lane_vmaps_counts = push_array(scratch.arena, RDI_U64, lane_count()); - lane_leftover_tasks = push_array(arena, VMapRangeTask *, lane_count()); + lane_vmaps = push_array(scratch.arena, RDI_VMapEntry *, lane_count()); + lane_leftover_tasks = push_array(scratch.arena, VMapRangeTask *, lane_count()); + lane_first_fixup_tasks = push_array(scratch.arena, VMapFixupTask *, lane_count()); + lane_last_fixup_tasks = push_array(scratch.arena, VMapFixupTask *, lane_count()); } lane_sync_u64(&lane_vmaps_counts, 0); + lane_sync_u64(&lane_vmaps, 0); lane_sync_u64(&lane_leftover_tasks, 0); + lane_sync_u64(&lane_first_fixup_tasks, 0); + lane_sync_u64(&lane_last_fixup_tasks, 0); lane_vmaps_counts[lane_idx()] = lane_vmap_count_actual; + lane_vmaps[lane_idx()] = lane_vmap; lane_leftover_tasks[lane_idx()] = top_range_task; + lane_first_fixup_tasks[lane_idx()] = first_fixup_task; + lane_last_fixup_tasks[lane_idx()] = last_fixup_task; } lane_sync(); - //- rjf: apply leftovers to per-lane vmaps - if(lane_idx() > 0) + //- rjf: apply fixups to per-lane vmaps + if(lane_idx() == 0) { - VMapRangeTask *top_leftover_task = lane_leftover_tasks[lane_idx()-1]; - for EachIndex(idx, lane_vmap_count_actual) + VMapRangeTask *top_range_task = 0; + for EachIndex(l_idx, lane_count()) { - if(!top_leftover_task) + VMapFixupTask *first_fixup = lane_first_fixup_tasks[l_idx]; + VMapFixupTask *last_fixup = lane_first_fixup_tasks[l_idx]; + for(VMapFixupTask *f = first_fixup; f != 0; f = f->next) { - break; - } - if(lane_vmap[idx].idx == 0xffffffff) - { - SLLStackPop(top_leftover_task); - if(top_leftover_task) + if(top_range_task) { - lane_vmap[idx].idx = top_leftover_task->idx; + SLLStackPop(top_range_task); + } + if(top_range_task) + { + lane_vmaps[l_idx][f->idx].idx = top_range_task->idx; + } + } + for(VMapRangeTask *lot = lane_leftover_tasks[l_idx]; lot != 0; lot = lot->next) + { + if(lot->next == 0) + { + lot->next = top_range_task; + top_range_task = lane_leftover_tasks[l_idx]; + break; } } } } - lane_idx(); + lane_sync(); //- rjf: lay out all lane vmaps into single range RDI_U64 *lane_vmaps_offs = 0; From 92517ef2d74c9a1dcf8a1a76fce109537db995c1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 14 Oct 2025 10:00:31 -0700 Subject: [PATCH 105/133] re-enable single-step on empty trap net, if no line info is present --- src/dbg_engine/dbg_engine_core.c | 30 ++++++++++++++++-------------- src/dbg_engine/dbg_engine_core.h | 3 ++- src/rdi_make/rdi_make_local.c | 4 +++- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index d5ee726f..960d9a68 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -312,7 +312,7 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread) // rjf: build traps if machine code was read successfully if(machine_code.size != 0) { - result.good = 1; + result.good_read = 1; // rjf: decode instruction DASM_Inst inst = dasm_inst_from_code(scratch.arena, arch, ip_vaddr, machine_code, DASM_Syntax_Intel); @@ -384,7 +384,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) { CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, 0, os_now_microseconds()+50000); machine_code = machine_code_slice.data; - good_machine_code = (machine_code.size == dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad); + good_machine_code = (machine_code.size >= dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad); LogInfoNamedBlockF("machine_code_slice") { log_infof("stale: %i\n", machine_code_slice.stale); @@ -482,10 +482,11 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) ctrl_trap_list_push(arena, &result.traps, &trap); } - // rjf: good if we got machine code + // rjf: store goodness if(good_machine_code) { - result.good = 1; + result.good_line_info = good_line_info; + result.good_read = good_machine_code; } // rjf: log @@ -548,7 +549,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) { CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, 0, os_now_microseconds()+5000); machine_code = machine_code_slice.data; - good_machine_code = (machine_code.size == dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad); + good_machine_code = (machine_code.size >= dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad); } // rjf: machine code => ctrl flow analysis @@ -644,10 +645,10 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) ctrl_trap_list_push(arena, &result.traps, &trap); } - // rjf: good if we got machine code - if(good_machine_code) + // rjf: store goodness { - result.good = 1; + result.good_line_info = good_line_info; + result.good_read = good_machine_code; } scratch_end(scratch); @@ -1810,7 +1811,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P switch(cmd->kind) { default: break; - case D_CmdKind_StepIntoInst: {trap_net.good = 1;}break; + case D_CmdKind_StepIntoInst: {trap_net.good_read = 1;}break; case D_CmdKind_StepOverInst: {trap_net = d_trap_net_from_thread__step_over_inst(scratch.arena, thread);}break; case D_CmdKind_StepIntoLine: {trap_net = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break; case D_CmdKind_StepOverLine: {trap_net = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; @@ -1827,7 +1828,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P U64 vaddr = regs_rip_from_arch_block(thread->arch, callstack.concrete_frames[1]->regs); CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, vaddr}; ctrl_trap_list_push(scratch.arena, &trap_net.traps, &trap); - trap_net.good = 1; + trap_net.good_read = 1; } else { @@ -1837,7 +1838,8 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P access_close(access); }break; } - if(trap_net.good && trap_net.traps.count != 0) + B32 good_trap_net = (trap_net.good_read || !trap_net.good_line_info); + if(good_trap_net && trap_net.traps.count != 0) { need_run = 1; run_kind = D_RunKind_Step; @@ -1845,7 +1847,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P run_flags = 0; run_traps = trap_net.traps; } - else if(trap_net.good && trap_net.traps.count == 0) + else if(good_trap_net && trap_net.traps.count == 0) { need_run = 1; run_kind = D_RunKind_SingleStep; @@ -1853,13 +1855,13 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P run_flags = 0; run_traps = trap_net.traps; } - else if(!trap_net.good && params->retry_idx < 100) + else if(!good_trap_net && params->retry_idx < 100) { D_CmdParams params_copy = *params; params_copy.retry_idx += 1; d_cmd_list_push_new(scratch.arena, &deferred_cmds, cmd->kind, ¶ms_copy); } - else if(!trap_net.good) + else if(!good_trap_net) { log_user_error(str8_lit("Could not successfully step.")); } diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index 3748911b..769c7f6d 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -76,7 +76,8 @@ typedef struct D_TrapNet D_TrapNet; struct D_TrapNet { CTRL_TrapList traps; - B32 good; + B32 good_line_info; + B32 good_read; }; //////////////////////////////// diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 60ed1861..541b78ad 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -539,7 +539,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake all vmaps (NEW) // -#if 0 +#if 1 ProfScope("bake all vmaps (NEW)") { Temp scratch = scratch_begin(&arena, 1); @@ -695,6 +695,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); //- rjf: apply fixups to per-lane vmaps +#if 0 if(lane_idx() == 0) { VMapRangeTask *top_range_task = 0; @@ -725,6 +726,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } } lane_sync(); +#endif //- rjf: lay out all lane vmaps into single range RDI_U64 *lane_vmaps_offs = 0; From 0d06b7d2d2200d25a837b3ac565f1ab0eeafeb0b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 14 Oct 2025 10:13:44 -0700 Subject: [PATCH 106/133] regrel32: interpret rbp-relative offsets as potential parameters as well (this only shows up with /ZI - usually everything is rsp-relative) --- src/rdi_from_pdb/rdi_from_pdb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index ac59bb6f..52939b16 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -3676,8 +3676,8 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) switch(arch) { default:{}break; - case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; - case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; + case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP || cv_reg == CV_Regx86_EBP);}break; + case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP || cv_reg == CV_Regx64_RBP);}break; } if(is_stack_reg) { From feb5249f475828b470b83c1dfe156d8c5881671c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 14 Oct 2025 16:01:51 -0700 Subject: [PATCH 107/133] first pass at faster & simplified vmap baking: sort ranges by both base voff *and* size, generate vmap directly from sorted ranges w/ stack machine; avoid quadratic pop --- src/rdi_make/rdi_make_local.c | 586 +++++++++++++++++++--------------- 1 file changed, 325 insertions(+), 261 deletions(-) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 541b78ad..556a7868 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -21,22 +21,21 @@ internal RDIM_TopLevelInfo rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_BinarySectionList sections) { // convert arch - RDI_Arch arch_rdi; - switch (arch) { - case Arch_Null: arch_rdi = RDI_Arch_NULL; break; - case Arch_x64: arch_rdi = RDI_Arch_X64; break; - case Arch_x86: arch_rdi = RDI_Arch_X86; break; - default: NotImplemented; break; + RDI_Arch arch_rdi = RDI_Arch_NULL; + switch(arch) + { + default:{}break; + case Arch_x64:{arch_rdi = RDI_Arch_X64;}break; + case Arch_x86:{arch_rdi = RDI_Arch_X86;}break; } - // find max VOFF U64 exe_voff_max = 0; - for (RDIM_BinarySectionNode *sect_n = sections.first; sect_n != 0 ; sect_n = sect_n->next) { + for EachNode(sect_n, RDIM_BinarySectionNode, sections.first) + { exe_voff_max = Max(exe_voff_max, sect_n->v.voff_opl); } - // fill out top level info RDIM_TopLevelInfo top_level_info = {0}; top_level_info.arch = arch_rdi; @@ -44,7 +43,6 @@ rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_Binar top_level_info.voff_max = exe_voff_max; top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); - return top_level_info; } @@ -60,6 +58,323 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake vmaps (NEW) + // + ProfScope("bake vmaps (NEW)") + { + Temp scratch = scratch_begin(&arena, 1); +#pragma pack(push, 1) + typedef struct VMapRecord VMapRecord; + struct VMapRecord + { + union + { + struct + { + U32 negative_size; + U64 voff; + }; + U8 digits[12]; + } + key; + U32 idx; + }; +#pragma pack(pop) + + //////////////////////////// + //- rjf: gather unsorted scope vmap records + // + VMapRecord *scope_vmap_records = 0; + U64 scope_vmap_records_count = 0; + ProfScope("gather unsorted scope vmap records") + { + //- rjf: calculate per-lane-chunk counts + U64 *lane_chunk_range_counts = 0; + if(lane_idx() == 0) + { + lane_chunk_range_counts = push_array(scratch.arena, U64, params->scopes.chunk_count * lane_count()); + } + lane_sync_u64(&lane_chunk_range_counts, 0); + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 slot_idx = lane_idx()*params->scopes.chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + lane_chunk_range_counts[slot_idx] += n->v[n_idx].voff_ranges.count; + } + chunk_idx += 1; + } + } + lane_sync(); + + //- rjf: calculate per-lane-chunk offsets + U64 *lane_chunk_range_offs = 0; + U64 total_range_count = 0; + if(lane_idx() == 0) + { + lane_chunk_range_offs = push_array(scratch.arena, U64, params->scopes.chunk_count * lane_count()); + U64 off = 0; + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->scopes.chunk_count + chunk_idx; + lane_chunk_range_offs[slot_idx] = off; + off += lane_chunk_range_counts[slot_idx]; + } + chunk_idx += 1; + } + total_range_count = off; + } + lane_sync_u64(&lane_chunk_range_offs, 0); + lane_sync_u64(&total_range_count, 0); + + //- rjf: allocate records + if(lane_idx() == 0) + { + scope_vmap_records_count = total_range_count; + scope_vmap_records = push_array_no_zero(scratch.arena, VMapRecord, scope_vmap_records_count); + } + lane_sync_u64(&scope_vmap_records, 0); + lane_sync_u64(&scope_vmap_records_count, 0); + + //- rjf: fill records + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 slot_idx = lane_idx()*params->scopes.chunk_count + chunk_idx; + U64 off = lane_chunk_range_offs[slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(&n->v[n_idx]); // TODO(rjf): @u64_to_u32 + for EachNode(rng_n, RDIM_Rng1U64Node, n->v[n_idx].voff_ranges.first) + { + scope_vmap_records[off].key.voff = rng_n->v.min; + scope_vmap_records[off].key.negative_size = -(RDI_U32)(rng_n->v.max - rng_n->v.min); + scope_vmap_records[off].idx = scope_idx; + off += 1; + } + } + chunk_idx += 1; + } + } + } + lane_sync(); + + //////////////////////////// + //- rjf: sort vmap records + // + ProfScope("sort vmap records") + { + //- rjf: set up constants + U64 bytes_per_digit = 1; + U64 num_possible_values_per_digit = 1<<(bytes_per_digit*8); + U64 digits_count = sizeof(((VMapRecord *)0)->key)/bytes_per_digit; + + //- rjf: set up swap buffer / lane counters + U64 records_count = scope_vmap_records_count; + VMapRecord *records = scope_vmap_records; + VMapRecord *records__swap = 0; + U32 **lane_digit_counts = 0; + U32 **lane_digit_offs = 0; + if(lane_idx() == 0) + { + records__swap = push_array_no_zero(scratch.arena, VMapRecord, records_count); + lane_digit_counts = push_array_no_zero(scratch.arena, U32 *, lane_count()); + lane_digit_offs = push_array_no_zero(scratch.arena, U32 *, lane_count()); + } + lane_sync_u64(&records__swap, 0); + lane_sync_u64(&lane_digit_counts, 0); + lane_sync_u64(&lane_digit_offs, 0); + lane_digit_counts[lane_idx()] = push_array_no_zero(scratch.arena, U32, num_possible_values_per_digit); + lane_digit_offs[lane_idx()] = push_array_no_zero(scratch.arena, U32, num_possible_values_per_digit); + + //- rjf: do all sort passes + { + VMapRecord *src = records; + VMapRecord *dst = records__swap; + for EachIndex(digit_idx, digits_count) + { + // rjf: count digit value occurrences per-lane + { + U32 *digit_counts = lane_digit_counts[lane_idx()]; + MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); + Rng1U64 range = lane_range(records_count); + for EachInRange(idx, range) + { + VMapRecord *rec = &src[idx]; + U16 digit_value = (U16)rec->key.digits[digit_idx]; + digit_counts[digit_value] += 1; + } + } + lane_sync(); + + // rjf: compute thread * digit value *relative* offset table + { + Rng1U64 range = lane_range(num_possible_values_per_digit); + for EachInRange(value_idx, range) + { + U64 layout_off = 0; + for EachIndex(lane_idx, lane_count()) + { + lane_digit_offs[lane_idx][value_idx] = layout_off; + layout_off += lane_digit_counts[lane_idx][value_idx]; + } + } + } + lane_sync(); + + // rjf: convert relative offsets -> absolute offsets + if(lane_idx() == 0) + { + U64 last_off = 0; + U64 num_of_nonzero_digit = 0; + for EachIndex(value_idx, num_possible_values_per_digit) + { + for EachIndex(lane_idx, lane_count()) + { + lane_digit_offs[lane_idx][value_idx] += last_off; + } + last_off = lane_digit_offs[lane_count()-1][value_idx] + lane_digit_counts[lane_count()-1][value_idx]; + } + // NOTE(rjf): required that: (last_off == element_count) + } + lane_sync(); + + // rjf: move + { + U32 *lane_digit_offsets = lane_digit_offs[lane_idx()]; + Rng1U64 range = lane_range(records_count); + for EachInRange(idx, range) + { + VMapRecord *src_rec = &src[idx]; + U16 digit_value = (U16)src_rec->key.digits[digit_idx]; + U64 dst_off = lane_digit_offsets[digit_value]; + lane_digit_offsets[digit_value] += 1; + MemoryCopyStruct(&dst[dst_off], src_rec); + } + } + lane_sync(); + + // rjf: swap source with destination for next pass + Swap(VMapRecord *, src, dst); + } + } + } + lane_sync(); + + //////////////////////////// + //- rjf: produce vmap + // + RDI_VMapEntry *vmap = 0; + RDI_U64 vmap_count = 0; + { + U64 records_count = scope_vmap_records_count; + VMapRecord *records = scope_vmap_records; + + //- rjf: allocate vmap + RDI_U64 vmap_count__cap = records_count*2 + 1; + if(lane_idx() == 0) + { + vmap = push_array(arena, RDI_VMapEntry, vmap_count__cap); + } + lane_sync_u64(&vmap, 0); + + //- rjf: bake + if(lane_idx() == 0) + { + typedef struct RangeNode RangeNode; + struct RangeNode + { + RangeNode *next; + Rng1U64 voff_range; + U64 idx; + }; + RDI_VMapEntry *vmap_ptr = vmap; + RDI_VMapEntry *vmap_opl = vmap + vmap_count__cap; + RangeNode *top_range = 0; + RangeNode *free_range = 0; + U64 last_recorded_voff = 0; + for(U64 record_idx = 0; record_idx <= records_count; record_idx += 1) + { + // rjf: get next voff range and index + Rng1U64 voff_range = r1u64(max_U64, max_U64); + U64 idx = 0; + if(record_idx < records_count) + { + VMapRecord *record = &records[record_idx]; + voff_range = r1u64(record->key.voff, record->key.voff + -record->key.negative_size); + idx = (U64)record->idx; + } + + // rjf: pop nodes we've advanced past + { + for(RangeNode *n = top_range, *next = 0; n != 0; n = next) + { + next = n->next; + if(n->voff_range.max <= voff_range.min) + { + SLLStackPop(top_range); + SLLStackPush(free_range, n); + if(n->voff_range.max != last_recorded_voff) + { + vmap_ptr += 1; + } + vmap_ptr->voff = n->voff_range.max; + vmap_ptr->idx = next ? next->idx : 0; + last_recorded_voff = vmap_ptr->voff; + } + else + { + break; + } + } + } + + // rjf: push this node + if(record_idx < records_count) + { + RangeNode *r = free_range; + if(r) + { + SLLStackPop(free_range); + } + else + { + r = push_array(scratch.arena, RangeNode, 1); + } + SLLStackPush(top_range, r); + r->voff_range = voff_range; + r->idx = idx; + if(voff_range.min != last_recorded_voff || (vmap_ptr->idx != idx && vmap_ptr->idx != 0)) + { + vmap_ptr += 1; + } + vmap_ptr->voff = voff_range.min; + vmap_ptr->idx = idx; + last_recorded_voff = voff_range.min; + } + } + if(last_recorded_voff != 0) + { + vmap_ptr += 1; + } + vmap_count = (vmap_ptr - vmap); + } + lane_sync_u64(&vmap_count, 0); + } + lane_sync(); + + scratch_end(scratch); + } + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage gather unsorted vmap keys/markers // @@ -536,257 +851,6 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake all vmaps (NEW) - // -#if 1 - ProfScope("bake all vmaps (NEW)") - { - Temp scratch = scratch_begin(&arena, 1); - RDI_U64 count = rdim_shared->scope_vmap_count; - RDIM_SortKey *keys = rdim_shared->scope_vmap_keys; - - //- rjf: do vmap entry generation for portions of the keys array - typedef struct VMapRangeTask VMapRangeTask; - struct VMapRangeTask - { - VMapRangeTask *next; - U32 idx; - }; - typedef struct VMapFixupTask VMapFixupTask; - struct VMapFixupTask - { - VMapFixupTask *next; - VMapFixupTask *prev; - U64 idx; - }; - Rng1U64 range = lane_range(count); - RDI_U64 lane_vmap_count_cap = dim_1u64(range); - RDI_VMapEntry *lane_vmap = push_array(arena, RDI_VMapEntry, lane_vmap_count_cap); - VMapRangeTask *top_range_task = 0; - VMapFixupTask *first_fixup_task = 0; - VMapFixupTask *last_fixup_task = 0; - RDI_U64 lane_vmap_count_actual = 0; - ProfScope("do vmap entry generation for portions of the keys array") - { - VMapRangeTask *free_range_task = 0; - RDI_VMapEntry *lane_vmap_ptr = lane_vmap; - RDIM_SortKey *key_ptr = keys + range.min; - RDIM_SortKey *key_opl = keys + range.max; - for(;key_ptr < key_opl;) - { - // rjf: get initial range index from range task stack - RDI_U32 initial_idx = (RDI_U32)0xffffffff; - if(top_range_task != 0) - { - initial_idx = top_range_task->idx; - } - - // rjf: update range task stack - // - // * we must process _all_ of the changes that apply at this voff before moving on - // - RDI_U64 voff = key_ptr->key; - B32 failed_pop = 0; - for(;key_ptr < key_opl && key_ptr->key == voff && !failed_pop; key_ptr += 1) - { - RDIM_VMapMarker *marker = (RDIM_VMapMarker *)key_ptr->val; - RDI_U32 idx = marker->idx; - - // rjf: range begin -> push to stack - if(marker->begin_range) - { - VMapRangeTask *task = free_range_task; - if(task != 0) - { - RDIM_SLLStackPop(free_range_task); - } - else - { - task = rdim_push_array(scratch.arena, VMapRangeTask, 1); - } - RDIM_SLLStackPush(top_range_task, task); - task->idx = idx; - } - - // rjf: range ending -> pop matching node from stack (not always the top) - else - { - VMapRangeTask **ptr_in = &top_range_task; - VMapRangeTask *match = 0; - for(VMapRangeTask *node = top_range_task; node != 0;) - { - if(node->idx == idx) - { - match = node; - break; - } - ptr_in = &node->next; - node = node->next; - } - if(match != 0) - { - *ptr_in = match->next; - RDIM_SLLStackPush(free_range_task, match); - } - else - { - failed_pop = 1; - } - } - } - - // rjf: get final map state from tracker stack - RDI_U32 final_idx = 0; - if(top_range_task != 0) - { - final_idx = top_range_task->idx; - } - - // rjf: failed pop -> rely on latter pass, need cross-lane information. remember this spot to fixup - if(failed_pop) - { - VMapFixupTask *fixup_task = push_array(scratch.arena, VMapFixupTask, 1); - fixup_task->idx = (U64)(lane_vmap_ptr - lane_vmap); - DLLPushBack(first_fixup_task, last_fixup_task, fixup_task); - lane_vmap_ptr->voff = voff; - lane_vmap_ptr->idx = 0xffffffff; - lane_vmap_ptr += 1; - } - - // rjf: if final is different from initial - emit new vmap entry - else if(final_idx != initial_idx) - { - lane_vmap_ptr->voff = voff; - lane_vmap_ptr->idx = final_idx; - lane_vmap_ptr += 1; - } - } - lane_vmap_count_actual = (lane_vmap_ptr - lane_vmap); - } - - //- rjf: collect all per-lane artifacts - RDI_U64 *lane_vmaps_counts = 0; - RDI_VMapEntry **lane_vmaps = 0; - VMapRangeTask **lane_leftover_tasks = 0; - VMapFixupTask **lane_first_fixup_tasks = 0; - VMapFixupTask **lane_last_fixup_tasks = 0; - ProfScope("collect all lane vmap counts") - { - if(lane_idx() == 0) - { - lane_vmaps_counts = push_array(scratch.arena, RDI_U64, lane_count()); - lane_vmaps = push_array(scratch.arena, RDI_VMapEntry *, lane_count()); - lane_leftover_tasks = push_array(scratch.arena, VMapRangeTask *, lane_count()); - lane_first_fixup_tasks = push_array(scratch.arena, VMapFixupTask *, lane_count()); - lane_last_fixup_tasks = push_array(scratch.arena, VMapFixupTask *, lane_count()); - } - lane_sync_u64(&lane_vmaps_counts, 0); - lane_sync_u64(&lane_vmaps, 0); - lane_sync_u64(&lane_leftover_tasks, 0); - lane_sync_u64(&lane_first_fixup_tasks, 0); - lane_sync_u64(&lane_last_fixup_tasks, 0); - lane_vmaps_counts[lane_idx()] = lane_vmap_count_actual; - lane_vmaps[lane_idx()] = lane_vmap; - lane_leftover_tasks[lane_idx()] = top_range_task; - lane_first_fixup_tasks[lane_idx()] = first_fixup_task; - lane_last_fixup_tasks[lane_idx()] = last_fixup_task; - } - lane_sync(); - - //- rjf: apply fixups to per-lane vmaps -#if 0 - if(lane_idx() == 0) - { - VMapRangeTask *top_range_task = 0; - for EachIndex(l_idx, lane_count()) - { - VMapFixupTask *first_fixup = lane_first_fixup_tasks[l_idx]; - VMapFixupTask *last_fixup = lane_first_fixup_tasks[l_idx]; - for(VMapFixupTask *f = first_fixup; f != 0; f = f->next) - { - if(top_range_task) - { - SLLStackPop(top_range_task); - } - if(top_range_task) - { - lane_vmaps[l_idx][f->idx].idx = top_range_task->idx; - } - } - for(VMapRangeTask *lot = lane_leftover_tasks[l_idx]; lot != 0; lot = lot->next) - { - if(lot->next == 0) - { - lot->next = top_range_task; - top_range_task = lane_leftover_tasks[l_idx]; - break; - } - } - } - } - lane_sync(); -#endif - - //- rjf: lay out all lane vmaps into single range - RDI_U64 *lane_vmaps_offs = 0; - RDI_U64 lane_vmap_count_total = 0; - ProfScope("lay out all lane vmaps into single range") - { - if(lane_idx() == 0) - { - lane_vmaps_offs = push_array(scratch.arena, RDI_U64, lane_count()); - RDI_U64 off = 0; - for EachIndex(lidx, lane_count()) - { - lane_vmaps_offs[lidx] = off; - off += lane_vmaps_counts[lidx]; - } - lane_vmap_count_total = off; - } - } - lane_sync_u64(&lane_vmaps_offs, 0); - lane_sync_u64(&lane_vmap_count_total, 0); - - //- rjf: join all lane vmaps - RDI_U64 vmap_count = lane_vmap_count_total + 1; - RDI_VMapEntry *vmap = 0; - ProfScope("join all lane vmaps") - { - if(lane_idx() == 0) - { - vmap = push_array_no_zero(arena, RDI_VMapEntry, vmap_count); - } - lane_sync_u64(&vmap, 0); - MemoryCopy(vmap + lane_vmaps_offs[lane_idx()], lane_vmap, sizeof(lane_vmap[0])*lane_vmaps_counts[lane_idx()]); - } - lane_sync(); - - //- rjf: combine duplicate neighbors - RDI_U64 vmap_count__deduplicated = 0; - ProfScope("combine duplicate neighbors") if(lane_idx() == 0) - { - RDI_VMapEntry *vmap_ptr = vmap; - RDI_VMapEntry *vmap_opl = vmap + vmap_count; - RDI_VMapEntry *vmap_out = vmap; - for(;vmap_ptr < vmap_opl;) - { - RDI_VMapEntry *vmap_range_first = vmap_ptr; - RDI_U64 idx = vmap_ptr->idx; - vmap_ptr += 1; - for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; - rdim_memcpy_struct(vmap_out, vmap_range_first); - vmap_out += 1; - } - vmap_count__deduplicated = (RDI_U64)(vmap_out - vmap); - } - lane_sync_u64(&vmap_count__deduplicated, 0); - - scratch_end(scratch); - } - lane_sync(); -#endif - ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build interned path tree // From b757762908fc0287298c14a530bf0e2e0b234332 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 14 Oct 2025 16:34:51 -0700 Subject: [PATCH 108/133] plug in new vmap baking --- src/rdi_make/rdi_make_local.c | 536 +++++++++++++++++++++++----------- 1 file changed, 372 insertions(+), 164 deletions(-) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 556a7868..573f7ec4 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -169,215 +169,418 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); //////////////////////////// - //- rjf: sort vmap records + //- rjf: gather unsorted global vmap records // - ProfScope("sort vmap records") + VMapRecord *global_vmap_records = 0; + U64 global_vmap_records_count = 0; + ProfScope("gather unsorted global vmap records") { - //- rjf: set up constants - U64 bytes_per_digit = 1; - U64 num_possible_values_per_digit = 1<<(bytes_per_digit*8); - U64 digits_count = sizeof(((VMapRecord *)0)->key)/bytes_per_digit; - - //- rjf: set up swap buffer / lane counters - U64 records_count = scope_vmap_records_count; - VMapRecord *records = scope_vmap_records; - VMapRecord *records__swap = 0; - U32 **lane_digit_counts = 0; - U32 **lane_digit_offs = 0; + //- rjf: calculate per-lane-chunk counts + U64 *lane_chunk_range_counts = 0; if(lane_idx() == 0) { - records__swap = push_array_no_zero(scratch.arena, VMapRecord, records_count); - lane_digit_counts = push_array_no_zero(scratch.arena, U32 *, lane_count()); - lane_digit_offs = push_array_no_zero(scratch.arena, U32 *, lane_count()); + lane_chunk_range_counts = push_array(scratch.arena, U64, params->global_variables.chunk_count * lane_count()); } - lane_sync_u64(&records__swap, 0); - lane_sync_u64(&lane_digit_counts, 0); - lane_sync_u64(&lane_digit_offs, 0); - lane_digit_counts[lane_idx()] = push_array_no_zero(scratch.arena, U32, num_possible_values_per_digit); - lane_digit_offs[lane_idx()] = push_array_no_zero(scratch.arena, U32, num_possible_values_per_digit); - - //- rjf: do all sort passes + lane_sync_u64(&lane_chunk_range_counts, 0); { - VMapRecord *src = records; - VMapRecord *dst = records__swap; - for EachIndex(digit_idx, digits_count) + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) { - // rjf: count digit value occurrences per-lane + U64 slot_idx = lane_idx()*params->global_variables.chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + lane_chunk_range_counts[slot_idx] += dim_1u64(range); + chunk_idx += 1; + } + } + lane_sync(); + + //- rjf: calculate per-lane-chunk offsets + U64 *lane_chunk_range_offs = 0; + U64 total_range_count = 0; + if(lane_idx() == 0) + { + lane_chunk_range_offs = push_array(scratch.arena, U64, params->global_variables.chunk_count * lane_count()); + U64 off = 0; + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) + { + for EachIndex(l_idx, lane_count()) { - U32 *digit_counts = lane_digit_counts[lane_idx()]; - MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); - Rng1U64 range = lane_range(records_count); - for EachInRange(idx, range) - { - VMapRecord *rec = &src[idx]; - U16 digit_value = (U16)rec->key.digits[digit_idx]; - digit_counts[digit_value] += 1; - } + U64 slot_idx = l_idx*params->global_variables.chunk_count + chunk_idx; + lane_chunk_range_offs[slot_idx] = off; + off += lane_chunk_range_counts[slot_idx]; } - lane_sync(); - - // rjf: compute thread * digit value *relative* offset table + chunk_idx += 1; + } + total_range_count = off; + } + lane_sync_u64(&lane_chunk_range_offs, 0); + lane_sync_u64(&total_range_count, 0); + + //- rjf: allocate records + if(lane_idx() == 0) + { + global_vmap_records_count = total_range_count; + global_vmap_records = push_array_no_zero(scratch.arena, VMapRecord, global_vmap_records_count); + } + lane_sync_u64(&global_vmap_records, 0); + lane_sync_u64(&global_vmap_records_count, 0); + + //- rjf: fill records + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) + { + U64 slot_idx = lane_idx()*params->global_variables.chunk_count + chunk_idx; + U64 off = lane_chunk_range_offs[slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) { - Rng1U64 range = lane_range(num_possible_values_per_digit); - for EachInRange(value_idx, range) - { - U64 layout_off = 0; - for EachIndex(lane_idx, lane_count()) - { - lane_digit_offs[lane_idx][value_idx] = layout_off; - layout_off += lane_digit_counts[lane_idx][value_idx]; - } - } + RDI_U32 global_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[n_idx]); // TODO(rjf): @u64_to_u32 + RDI_U32 global_size = (RDI_U32)(n->v[n_idx].type ? n->v[n_idx].type->byte_size : 1); + RDI_U64 global_voff = n->v[n_idx].offset; + global_vmap_records[off].key.voff = global_voff; + global_vmap_records[off].key.negative_size = -global_size; + global_vmap_records[off].idx = global_idx; + off += 1; } - lane_sync(); - - // rjf: convert relative offsets -> absolute offsets - if(lane_idx() == 0) - { - U64 last_off = 0; - U64 num_of_nonzero_digit = 0; - for EachIndex(value_idx, num_possible_values_per_digit) - { - for EachIndex(lane_idx, lane_count()) - { - lane_digit_offs[lane_idx][value_idx] += last_off; - } - last_off = lane_digit_offs[lane_count()-1][value_idx] + lane_digit_counts[lane_count()-1][value_idx]; - } - // NOTE(rjf): required that: (last_off == element_count) - } - lane_sync(); - - // rjf: move - { - U32 *lane_digit_offsets = lane_digit_offs[lane_idx()]; - Rng1U64 range = lane_range(records_count); - for EachInRange(idx, range) - { - VMapRecord *src_rec = &src[idx]; - U16 digit_value = (U16)src_rec->key.digits[digit_idx]; - U64 dst_off = lane_digit_offsets[digit_value]; - lane_digit_offsets[digit_value] += 1; - MemoryCopyStruct(&dst[dst_off], src_rec); - } - } - lane_sync(); - - // rjf: swap source with destination for next pass - Swap(VMapRecord *, src, dst); + chunk_idx += 1; } } } lane_sync(); //////////////////////////// - //- rjf: produce vmap + //- rjf: gather unsorted unit vmap records // - RDI_VMapEntry *vmap = 0; - RDI_U64 vmap_count = 0; + VMapRecord *unit_vmap_records = 0; + U64 unit_vmap_records_count = 0; + ProfScope("gather unsorted unit vmap records") { - U64 records_count = scope_vmap_records_count; - VMapRecord *records = scope_vmap_records; - - //- rjf: allocate vmap - RDI_U64 vmap_count__cap = records_count*2 + 1; + //- rjf: calculate per-lane-chunk counts + U64 *lane_chunk_range_counts = 0; if(lane_idx() == 0) { - vmap = push_array(arena, RDI_VMapEntry, vmap_count__cap); + lane_chunk_range_counts = push_array(scratch.arena, U64, params->units.chunk_count * lane_count()); } - lane_sync_u64(&vmap, 0); + lane_sync_u64(&lane_chunk_range_counts, 0); + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_UnitChunkNode, params->units.first) + { + U64 slot_idx = lane_idx()*params->units.chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + lane_chunk_range_counts[slot_idx] += n->v[n_idx].voff_ranges.total_count; + } + chunk_idx += 1; + } + } + lane_sync(); - //- rjf: bake + //- rjf: calculate per-lane-chunk offsets + U64 *lane_chunk_range_offs = 0; + U64 total_range_count = 0; if(lane_idx() == 0) { - typedef struct RangeNode RangeNode; - struct RangeNode + lane_chunk_range_offs = push_array(scratch.arena, U64, params->units.chunk_count * lane_count()); + U64 off = 0; + U64 chunk_idx = 0; + for EachNode(n, RDIM_UnitChunkNode, params->units.first) { - RangeNode *next; - Rng1U64 voff_range; - U64 idx; - }; - RDI_VMapEntry *vmap_ptr = vmap; - RDI_VMapEntry *vmap_opl = vmap + vmap_count__cap; - RangeNode *top_range = 0; - RangeNode *free_range = 0; - U64 last_recorded_voff = 0; - for(U64 record_idx = 0; record_idx <= records_count; record_idx += 1) - { - // rjf: get next voff range and index - Rng1U64 voff_range = r1u64(max_U64, max_U64); - U64 idx = 0; - if(record_idx < records_count) + for EachIndex(l_idx, lane_count()) { - VMapRecord *record = &records[record_idx]; - voff_range = r1u64(record->key.voff, record->key.voff + -record->key.negative_size); - idx = (U64)record->idx; + U64 slot_idx = l_idx*params->units.chunk_count + chunk_idx; + lane_chunk_range_offs[slot_idx] = off; + off += lane_chunk_range_counts[slot_idx]; } - - // rjf: pop nodes we've advanced past + chunk_idx += 1; + } + total_range_count = off; + } + lane_sync_u64(&lane_chunk_range_offs, 0); + lane_sync_u64(&total_range_count, 0); + + //- rjf: allocate records + if(lane_idx() == 0) + { + unit_vmap_records_count = total_range_count; + unit_vmap_records = push_array_no_zero(scratch.arena, VMapRecord, unit_vmap_records_count); + } + lane_sync_u64(&unit_vmap_records, 0); + lane_sync_u64(&unit_vmap_records_count, 0); + + //- rjf: fill records + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_UnitChunkNode, params->units.first) + { + U64 slot_idx = lane_idx()*params->units.chunk_count + chunk_idx; + U64 off = lane_chunk_range_offs[slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) { - for(RangeNode *n = top_range, *next = 0; n != 0; n = next) + RDI_U32 unit_idx = (RDI_U32)rdim_idx_from_unit(&n->v[n_idx]); // TODO(rjf): @u64_to_u32 + for EachNode(rng_n, RDIM_Rng1U64ChunkNode, n->v[n_idx].voff_ranges.first) { - next = n->next; - if(n->voff_range.max <= voff_range.min) + for EachIndex(rng_n_idx, rng_n->count) { - SLLStackPop(top_range); - SLLStackPush(free_range, n); - if(n->voff_range.max != last_recorded_voff) - { - vmap_ptr += 1; - } - vmap_ptr->voff = n->voff_range.max; - vmap_ptr->idx = next ? next->idx : 0; - last_recorded_voff = vmap_ptr->voff; - } - else - { - break; + unit_vmap_records[off].key.voff = rng_n->v[rng_n_idx].min; + unit_vmap_records[off].key.negative_size = -(RDI_U32)(rng_n->v[rng_n_idx].max - rng_n->v[rng_n_idx].min); + unit_vmap_records[off].idx = unit_idx; + off += 1; } } } - - // rjf: push this node - if(record_idx < records_count) - { - RangeNode *r = free_range; - if(r) - { - SLLStackPop(free_range); - } - else - { - r = push_array(scratch.arena, RangeNode, 1); - } - SLLStackPush(top_range, r); - r->voff_range = voff_range; - r->idx = idx; - if(voff_range.min != last_recorded_voff || (vmap_ptr->idx != idx && vmap_ptr->idx != 0)) - { - vmap_ptr += 1; - } - vmap_ptr->voff = voff_range.min; - vmap_ptr->idx = idx; - last_recorded_voff = voff_range.min; - } + chunk_idx += 1; } - if(last_recorded_voff != 0) - { - vmap_ptr += 1; - } - vmap_count = (vmap_ptr - vmap); } - lane_sync_u64(&vmap_count, 0); } lane_sync(); + //////////////////////////// + //- rjf: sort & bake all vmaps + // + struct + { + String8 name; + VMapRecord *records; + U64 records_count; + RDI_VMapEntry **vmap_out; + U32 *vmap_count_out; + } + vmap_tasks[] = + { + {str8_lit_comp("scopes"), scope_vmap_records, scope_vmap_records_count, &rdim_shared->baked_scope_vmap.vmap.vmap, &rdim_shared->baked_scope_vmap.vmap.count}, + {str8_lit_comp("globals"), global_vmap_records, global_vmap_records_count, &rdim_shared->baked_global_vmap.vmap.vmap, &rdim_shared->baked_global_vmap.vmap.count}, + {str8_lit_comp("units"), unit_vmap_records, unit_vmap_records_count, &rdim_shared->baked_unit_vmap.vmap.vmap, &rdim_shared->baked_unit_vmap.vmap.count}, + }; + ProfScope("sort & bake all vmaps") + { + for EachElement(vmap_task_idx, vmap_tasks) ProfScope("sort & bake vmap for %.*s", str8_varg(vmap_tasks[vmap_task_idx].name)) + { + VMapRecord *records = vmap_tasks[vmap_task_idx].records; + U64 records_count = vmap_tasks[vmap_task_idx].records_count; + + //////////////////////// + //- rjf: sort + // + ProfScope("sort") + { + //- rjf: set up constants + U64 bytes_per_digit = 1; + U64 num_possible_values_per_digit = 1<<(bytes_per_digit*8); + U64 digits_count = sizeof(((VMapRecord *)0)->key)/bytes_per_digit; + + //- rjf: set up swap buffer / lane counters + VMapRecord *records__swap = 0; + U32 **lane_digit_counts = 0; + U32 **lane_digit_offs = 0; + if(lane_idx() == 0) + { + records__swap = push_array_no_zero(scratch.arena, VMapRecord, records_count); + lane_digit_counts = push_array_no_zero(scratch.arena, U32 *, lane_count()); + lane_digit_offs = push_array_no_zero(scratch.arena, U32 *, lane_count()); + } + lane_sync_u64(&records__swap, 0); + lane_sync_u64(&lane_digit_counts, 0); + lane_sync_u64(&lane_digit_offs, 0); + lane_digit_counts[lane_idx()] = push_array_no_zero(scratch.arena, U32, num_possible_values_per_digit); + lane_digit_offs[lane_idx()] = push_array_no_zero(scratch.arena, U32, num_possible_values_per_digit); + + //- rjf: do all sort passes + { + VMapRecord *src = records; + VMapRecord *dst = records__swap; + for EachIndex(digit_idx, digits_count) + { + // rjf: count digit value occurrences per-lane + { + U32 *digit_counts = lane_digit_counts[lane_idx()]; + MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); + Rng1U64 range = lane_range(records_count); + for EachInRange(idx, range) + { + VMapRecord *rec = &src[idx]; + U16 digit_value = (U16)rec->key.digits[digit_idx]; + digit_counts[digit_value] += 1; + } + } + lane_sync(); + + // rjf: compute thread * digit value *relative* offset table + { + Rng1U64 range = lane_range(num_possible_values_per_digit); + for EachInRange(value_idx, range) + { + U64 layout_off = 0; + for EachIndex(lane_idx, lane_count()) + { + lane_digit_offs[lane_idx][value_idx] = layout_off; + layout_off += lane_digit_counts[lane_idx][value_idx]; + } + } + } + lane_sync(); + + // rjf: convert relative offsets -> absolute offsets + if(lane_idx() == 0) + { + U64 last_off = 0; + U64 num_of_nonzero_digit = 0; + for EachIndex(value_idx, num_possible_values_per_digit) + { + for EachIndex(lane_idx, lane_count()) + { + lane_digit_offs[lane_idx][value_idx] += last_off; + } + last_off = lane_digit_offs[lane_count()-1][value_idx] + lane_digit_counts[lane_count()-1][value_idx]; + } + // NOTE(rjf): required that: (last_off == element_count) + } + lane_sync(); + + // rjf: move + { + U32 *lane_digit_offsets = lane_digit_offs[lane_idx()]; + Rng1U64 range = lane_range(records_count); + for EachInRange(idx, range) + { + VMapRecord *src_rec = &src[idx]; + U16 digit_value = (U16)src_rec->key.digits[digit_idx]; + U64 dst_off = lane_digit_offsets[digit_value]; + lane_digit_offsets[digit_value] += 1; + MemoryCopyStruct(&dst[dst_off], src_rec); + } + } + lane_sync(); + + // rjf: swap source with destination for next pass + Swap(VMapRecord *, src, dst); + } + } + } + lane_sync(); + + //////////////////////// + //- rjf: bake + // + RDI_VMapEntry *vmap = 0; + RDI_U64 vmap_count = 0; + { + //- rjf: allocate vmap + RDI_U64 vmap_count__cap = records_count*2 + 1; + if(lane_idx() == 0) + { + vmap = push_array(arena, RDI_VMapEntry, vmap_count__cap); + } + lane_sync_u64(&vmap, 0); + + //- rjf: bake + if(lane_idx() == 0) + { + typedef struct RangeNode RangeNode; + struct RangeNode + { + RangeNode *next; + Rng1U64 voff_range; + U64 idx; + }; + RDI_VMapEntry *vmap_ptr = vmap; + RDI_VMapEntry *vmap_opl = vmap + vmap_count__cap; + RangeNode *top_range = 0; + RangeNode *free_range = 0; + U64 last_recorded_voff = 0; + for(U64 record_idx = 0; record_idx <= records_count; record_idx += 1) + { + // rjf: get next voff range and index + Rng1U64 voff_range = r1u64(max_U64, max_U64); + U64 idx = 0; + if(record_idx < records_count) + { + VMapRecord *record = &records[record_idx]; + voff_range = r1u64(record->key.voff, record->key.voff + -record->key.negative_size); + idx = (U64)record->idx; + } + + // rjf: pop nodes we've advanced past + { + for(RangeNode *n = top_range, *next = 0; n != 0; n = next) + { + next = n->next; + if(n->voff_range.max <= voff_range.min) + { + SLLStackPop(top_range); + SLLStackPush(free_range, n); + if(n->voff_range.max != last_recorded_voff) + { + vmap_ptr += 1; + } + vmap_ptr->voff = n->voff_range.max; + vmap_ptr->idx = next ? next->idx : 0; + last_recorded_voff = vmap_ptr->voff; + } + else + { + break; + } + } + } + + // rjf: push this node + if(record_idx < records_count) + { + RangeNode *r = free_range; + if(r) + { + SLLStackPop(free_range); + } + else + { + r = push_array(scratch.arena, RangeNode, 1); + } + SLLStackPush(top_range, r); + r->voff_range = voff_range; + r->idx = idx; + if(voff_range.min != last_recorded_voff || (vmap_ptr->idx != idx && vmap_ptr->idx != 0)) + { + vmap_ptr += 1; + } + vmap_ptr->voff = voff_range.min; + vmap_ptr->idx = idx; + last_recorded_voff = voff_range.min; + } + } + if(last_recorded_voff != 0) + { + vmap_ptr += 1; + } + vmap_count = (vmap_ptr - vmap); + } + lane_sync_u64(&vmap_count, 0); + } + lane_sync(); + + //////////////////////// + //- rjf: store + // + if(lane_idx() == 0) + { + vmap_tasks[vmap_task_idx].vmap_out[0] = vmap; + vmap_tasks[vmap_task_idx].vmap_count_out[0] = vmap_count; + } + } + } + scratch_end(scratch); } + lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage gather unsorted vmap keys/markers // +#if 0 ProfScope("gather unsorted vmap keys/markers") { //- rjf: gather scope vmap keys/markers @@ -553,10 +756,12 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } } lane_sync(); +#endif ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage sort all vmap keys // +#if 0 ProfScope("sort all vmap keys") { // rjf: set up @@ -666,10 +871,12 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } } lane_sync(); +#endif ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake all vmaps // +#if 0 ProfScope("bake all vmaps") { Temp scratch = scratch_begin(&arena, 1); @@ -850,6 +1057,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) scratch_end(scratch); } lane_sync(); +#endif ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build interned path tree From c7d0a3431b67ebcdf6c7961b3f70d3293b9959a6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 14 Oct 2025 16:35:24 -0700 Subject: [PATCH 109/133] eliminate old vmap baking --- src/rdi_make/rdi_make_local.c | 482 ---------------------------------- 1 file changed, 482 deletions(-) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 573f7ec4..67f70693 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -577,488 +577,6 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage gather unsorted vmap keys/markers - // -#if 0 - ProfScope("gather unsorted vmap keys/markers") - { - //- rjf: gather scope vmap keys/markers - if(lane_idx() == lane_from_task_idx(0)) ProfScope("gather scope vmap keys/markers") - { - rdim_shared->scope_vmap_count = params->scopes.scope_voff_count; - rdim_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim_shared->scope_vmap_count); - rdim_shared->scope_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, rdim_shared->scope_vmap_count); - rdim_shared->scope_vmap_markers = push_array_no_zero(arena, RDIM_VMapMarker, rdim_shared->scope_vmap_count); - ProfScope("fill keys/markers") - { - RDIM_SortKey *key_ptr = rdim_shared->scope_vmap_keys; - RDIM_VMapMarker *marker_ptr = rdim_shared->scope_vmap_markers; - for(RDIM_ScopeChunkNode *chunk_n = params->scopes.first; chunk_n != 0; chunk_n = chunk_n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) - { - RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; - RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope); // TODO(rjf): @u64_to_u32 - for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) - { - key_ptr->key = n->v.min; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = n->v.max; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - } - } - } - - //- rjf: gather unit vmap keys/markers - if(lane_idx() == lane_from_task_idx(1)) ProfScope("gather unit vmap keys/markers") - { - // rjf: count voff ranges - RDI_U64 voff_range_count = 0; - for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDIM_Unit *unit = &n->v[idx]; - voff_range_count += unit->voff_ranges.total_count; - } - } - - // rjf: count necessary markers - RDI_U64 marker_count = voff_range_count*2; - - // rjf: build keys/markers arrays - RDIM_SortKey *keys = rdim_push_array_no_zero(arena, RDIM_SortKey, marker_count); - RDIM_VMapMarker *markers = rdim_push_array_no_zero(arena, RDIM_VMapMarker, marker_count); - { - RDIM_SortKey *key_ptr = keys; - RDIM_VMapMarker *marker_ptr = markers; - RDI_U32 unit_idx = 1; - for(RDIM_UnitChunkNode *unit_chunk_n = params->units.first; - unit_chunk_n != 0; - unit_chunk_n = unit_chunk_n->next) - { - for(RDI_U64 idx = 0; idx < unit_chunk_n->count; idx += 1) - { - RDIM_Unit *unit = &unit_chunk_n->v[idx]; - for(RDIM_Rng1U64ChunkNode *n = unit->voff_ranges.first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_Rng1U64 range = n->v[chunk_idx]; - if(range.min < range.max) - { - key_ptr->key = range.min; - key_ptr->val = marker_ptr; - marker_ptr->idx = unit_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = range.max; - key_ptr->val = marker_ptr; - marker_ptr->idx = unit_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - } - unit_idx += 1; - } - } - } - - // rjf: store - rdim_shared->unit_vmap_count = marker_count; - rdim_shared->unit_vmap_keys = keys; - rdim_shared->unit_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); - rdim_shared->unit_vmap_markers = markers; - } - - //- rjf: gather global vmap keys/markers - if(lane_idx() == lane_from_task_idx(2)) ProfScope("gather global vmap keys/markers") - { - //- rjf: allocate keys/markers - RDI_U64 marker_count = params->global_variables.total_count*2 + 2; - RDIM_SortKey *keys = rdim_push_array_no_zero(arena, RDIM_SortKey, marker_count); - RDIM_VMapMarker *markers = rdim_push_array_no_zero(arena, RDIM_VMapMarker, marker_count); - - //- rjf: fill - { - RDIM_SortKey *key_ptr = keys; - RDIM_VMapMarker *marker_ptr = markers; - - // rjf: fill actual globals - for(RDIM_SymbolChunkNode *n = params->global_variables.first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_Symbol *global_var = &n->v[chunk_idx]; - RDI_U32 global_var_idx = (RDI_U32)rdim_idx_from_symbol(global_var); // TODO(rjf): @u64_to_u32 - RDI_U64 global_var_size = global_var->type ? global_var->type->byte_size : 1; - - RDI_U64 first = global_var->offset; - RDI_U64 opl = first + global_var_size; - - key_ptr->key = first; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_var_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_var_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - - // rjf: fill nil global - { - RDI_U32 global_idx = 0; - RDI_U64 first = 0; - RDI_U64 opl = 0xffffffffffffffffull; - key_ptr->key = first; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - key_ptr->key = opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - - //- rjf: store - rdim_shared->global_vmap_count = marker_count; - rdim_shared->global_vmap_keys = keys; - rdim_shared->global_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); - rdim_shared->global_vmap_markers = markers; - } - } - lane_sync(); -#endif - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage sort all vmap keys - // -#if 0 - ProfScope("sort all vmap keys") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); - rdim_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); - } - lane_sync(); - - // rjf: sort - struct - { - RDI_U64 vmap_count; - RDIM_SortKey *keys; - RDIM_SortKey *keys__swap; - } - sort_tasks[] = - { - {rdim_shared->scope_vmap_count, rdim_shared->scope_vmap_keys, rdim_shared->scope_vmap_keys__swap}, - {rdim_shared->unit_vmap_count, rdim_shared->unit_vmap_keys, rdim_shared->unit_vmap_keys__swap}, - {rdim_shared->global_vmap_count, rdim_shared->global_vmap_keys, rdim_shared->global_vmap_keys__swap}, - }; - for EachElement(sort_task_idx, sort_tasks) ProfScope("sort %I64u", sort_task_idx) - { - RDI_U64 vmap_count = sort_tasks[sort_task_idx].vmap_count; - RDIM_SortKey *keys = sort_tasks[sort_task_idx].keys; - RDIM_SortKey *keys__swap = sort_tasks[sort_task_idx].keys__swap; - U64 bits_per_digit = 8; - U64 digits_count = 64 / bits_per_digit; - U64 num_possible_values_per_digit = 1 << bits_per_digit; - rdim_shared->lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); - rdim_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); - RDIM_SortKey *src = keys; - RDIM_SortKey *dst = keys__swap; - U64 element_count = vmap_count; - for EachIndex(digit_idx, digits_count) - { - // rjf: count digit value occurrences per-lane - { - U32 *digit_counts = rdim_shared->lane_digit_counts[lane_idx()]; - MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); - Rng1U64 range = lane_range(element_count); - for EachInRange(idx, range) - { - RDIM_SortKey *sort_key = &src[idx]; - U16 digit_value = (U16)(U8)(sort_key->key >> (digit_idx*bits_per_digit)); - digit_counts[digit_value] += 1; - } - } - lane_sync(); - - // rjf: compute thread * digit value *relative* offset table - { - Rng1U64 range = lane_range(num_possible_values_per_digit); - for EachInRange(value_idx, range) - { - U64 layout_off = 0; - for EachIndex(lane_idx, lane_count()) - { - rdim_shared->lane_digit_offsets[lane_idx][value_idx] = layout_off; - layout_off += rdim_shared->lane_digit_counts[lane_idx][value_idx]; - } - } - } - lane_sync(); - - // rjf: convert relative offsets -> absolute offsets - if(lane_idx() == 0) - { - U64 last_off = 0; - U64 num_of_nonzero_digit = 0; - for EachIndex(value_idx, num_possible_values_per_digit) - { - for EachIndex(lane_idx, lane_count()) - { - rdim_shared->lane_digit_offsets[lane_idx][value_idx] += last_off; - } - last_off = rdim_shared->lane_digit_offsets[lane_count()-1][value_idx] + rdim_shared->lane_digit_counts[lane_count()-1][value_idx]; - } - // NOTE(rjf): required that: (last_off == element_count) - } - lane_sync(); - - // rjf: move - { - U32 *lane_digit_offsets = rdim_shared->lane_digit_offsets[lane_idx()]; - Rng1U64 range = lane_range(element_count); - for EachInRange(idx, range) - { - RDIM_SortKey *src_key = &src[idx]; - U16 digit_value = (U16)(U8)(src_key->key >> (digit_idx*bits_per_digit)); - U64 dst_off = lane_digit_offsets[digit_value]; - lane_digit_offsets[digit_value] += 1; - MemoryCopyStruct(&dst[dst_off], src_key); - } - } - lane_sync(); - - // rjf: swap - { - RDIM_SortKey *swap = src; - src = dst; - dst = swap; - } - } - } - } - lane_sync(); -#endif - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake all vmaps - // -#if 0 - ProfScope("bake all vmaps") - { - Temp scratch = scratch_begin(&arena, 1); - typedef struct VMapBakeTask VMapBakeTask; - struct VMapBakeTask - { - VMapBakeTask *next; - String8 name; - RDI_U64 count; - RDIM_SortKey *keys; - RDIM_VMapMarker *markers; - RDIM_BakeVMap *bake_vmap_out; - }; - VMapBakeTask *first_task = 0; - VMapBakeTask *last_task = 0; - if(lane_idx() == lane_from_task_idx(0)) - { - VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); - task->name = str8_lit("scopes"); - task->count = rdim_shared->scope_vmap_count; - task->keys = rdim_shared->scope_vmap_keys; - task->markers = rdim_shared->scope_vmap_markers; - task->bake_vmap_out = &rdim_shared->baked_scope_vmap.vmap; - SLLQueuePush(first_task, last_task, task); - } - if(lane_idx() == lane_from_task_idx(1)) - { - VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); - task->name = str8_lit("units"); - task->count = rdim_shared->unit_vmap_count; - task->keys = rdim_shared->unit_vmap_keys; - task->markers = rdim_shared->unit_vmap_markers; - task->bake_vmap_out = &rdim_shared->baked_unit_vmap.vmap; - SLLQueuePush(first_task, last_task, task); - } - if(lane_idx() == lane_from_task_idx(2)) - { - VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); - task->name = str8_lit("globals"); - task->count = rdim_shared->global_vmap_count; - task->keys = rdim_shared->global_vmap_keys; - task->markers = rdim_shared->global_vmap_markers; - task->bake_vmap_out = &rdim_shared->baked_global_vmap.vmap; - SLLQueuePush(first_task, last_task, task); - } - for(VMapBakeTask *task = first_task; task != 0; task = task->next) ProfScope("vmap bake for %.*s", str8_varg(task->name)) - { - //- rjf: determine if an extra vmap entry for zero is needed - RDI_U32 extra_vmap_entry = 0; - if(task->count > 0 && task->keys[0].key != 0) - { - extra_vmap_entry = 1; - } - - //- rjf: fill output vmap entries - RDI_U32 vmap_count_raw = extra_vmap_entry + task->count; - RDI_VMapEntry *vmap = rdim_push_array(arena, RDI_VMapEntry, vmap_count_raw); - RDI_U32 vmap_entry_count_pass_1 = 0; - ProfScope("fill output vmap entries") - { - typedef struct RDIM_VMapRangeTracker RDIM_VMapRangeTracker; - struct RDIM_VMapRangeTracker - { - RDIM_VMapRangeTracker *next; - RDI_U32 idx; - }; - RDI_VMapEntry *vmap_ptr = vmap; - if(extra_vmap_entry) - { - vmap_ptr->voff = 0; - vmap_ptr->idx = 0; - vmap_ptr += 1; - } - RDIM_VMapRangeTracker *tracker_stack = 0; - RDIM_VMapRangeTracker *tracker_free = 0; - RDIM_SortKey *key_ptr = task->keys; - RDIM_SortKey *key_opl = task->keys + task->count; - for(;key_ptr < key_opl;) - { - // rjf: get initial map state from tracker stack - RDI_U32 initial_idx = (RDI_U32)0xffffffff; - if(tracker_stack != 0) - { - initial_idx = tracker_stack->idx; - } - - // rjf: update tracker stack - // - // * we must process _all_ of the changes that apply at this voff before moving on - // - RDI_U64 voff = key_ptr->key; - for(;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1) - { - RDIM_VMapMarker *marker = (RDIM_VMapMarker*)key_ptr->val; - RDI_U32 idx = marker->idx; - - // rjf: range begin -> push to stack - if(marker->begin_range) - { - RDIM_VMapRangeTracker *new_tracker = tracker_free; - if(new_tracker != 0) - { - RDIM_SLLStackPop(tracker_free); - } - else - { - new_tracker = rdim_push_array(scratch.arena, RDIM_VMapRangeTracker, 1); - } - RDIM_SLLStackPush(tracker_stack, new_tracker); - new_tracker->idx = idx; - } - - // rjf: range ending -> pop matching node from stack (not always the top) - else - { - RDIM_VMapRangeTracker **ptr_in = &tracker_stack; - RDIM_VMapRangeTracker *match = 0; - for(RDIM_VMapRangeTracker *node = tracker_stack; node != 0;) - { - if(node->idx == idx) - { - match = node; - break; - } - ptr_in = &node->next; - node = node->next; - } - if(match != 0) - { - *ptr_in = match->next; - RDIM_SLLStackPush(tracker_free, match); - } - } - } - - // rjf: get final map state from tracker stack - RDI_U32 final_idx = 0; - if(tracker_stack != 0) - { - final_idx = tracker_stack->idx; - } - - // rjf: if final is different from initial - emit new vmap entry - if(final_idx != initial_idx) - { - vmap_ptr->voff = voff; - vmap_ptr->idx = final_idx; - vmap_ptr += 1; - } - } - - vmap_entry_count_pass_1 = (RDI_U32)(vmap_ptr - vmap); // TODO(rjf): @u64_to_u32 - } - - //- rjf: combine duplicate neighbors - RDI_U32 vmap_entry_count = 0; - ProfScope("combine duplicate neighbors") - { - RDI_VMapEntry *vmap_ptr = vmap; - RDI_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; - RDI_VMapEntry *vmap_out = vmap; - for(;vmap_ptr < vmap_opl;) - { - RDI_VMapEntry *vmap_range_first = vmap_ptr; - RDI_U64 idx = vmap_ptr->idx; - vmap_ptr += 1; - for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; - rdim_memcpy_struct(vmap_out, vmap_range_first); - vmap_out += 1; - } - vmap_entry_count = (RDI_U32)(vmap_out - vmap); // TODO(rjf): @u64_to_u32 - } - - //- rjf: fill result - task->bake_vmap_out->vmap = vmap; - task->bake_vmap_out->count = vmap_entry_count; - } - scratch_end(scratch); - } - lane_sync(); -#endif - ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build interned path tree // From 5cc9d9ae89c900d97eb685b4ca9c98e667e0363e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 14 Oct 2025 16:37:47 -0700 Subject: [PATCH 110/133] remove new marker --- src/rdi_make/rdi_make_local.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 67f70693..353f02b5 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -59,9 +59,9 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake vmaps (NEW) + //- rjf: @rdim_bake_stage bake vmaps // - ProfScope("bake vmaps (NEW)") + ProfScope("bake vmaps") { Temp scratch = scratch_begin(&arena, 1); #pragma pack(push, 1) From 1d9870c1f99f06558d9ea40aab4e29c17502e4f5 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 11:55:45 -0700 Subject: [PATCH 111/133] rdi string baking, name map baking, idx run baking: put temporary per-lane artifacts/maps onto scratch & pop - reduce permanent memory usage --- src/rdi_make/rdi_make_local.c | 196 +++++++++++++++++++--------------- src/rdi_make/rdi_make_local.h | 25 ----- 2 files changed, 111 insertions(+), 110 deletions(-) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 353f02b5..f1a2457e 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -801,26 +801,33 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) // ProfScope("build string map") { + Temp scratch = scratch_begin(&arena, 1); + //- rjf: set up per-lane outputs + RDIM_BakeStringMapTopology *top = 0; + RDIM_BakeStringMapLoose **lane_maps__loose = 0; + RDIM_BakeStringMapLoose *map__loose = 0; if(lane_idx() == 0) ProfScope("set up per-lane outputs") { - rdim_shared->bake_string_map_topology.slots_count = (64 + - params->procedures.total_count*1 + - params->global_variables.total_count*1 + - params->thread_variables.total_count*1 + - params->types.total_count/2); - rdim_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); - rdim_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim_shared->bake_string_map_topology); + top = push_array(scratch.arena, RDIM_BakeStringMapTopology, 1); + top->slots_count = (64 + + params->procedures.total_count*1 + + params->global_variables.total_count*1 + + params->thread_variables.total_count*1 + + params->types.total_count/2); + lane_maps__loose = push_array(scratch.arena, RDIM_BakeStringMapLoose *, lane_count()); + map__loose = rdim_bake_string_map_loose_make(scratch.arena, top); } - lane_sync(); + lane_sync_u64(&top, 0); + lane_sync_u64(&lane_maps__loose, 0); + lane_sync_u64(&map__loose, 0); //- rjf: set up this lane's map ProfScope("set up this lane's map") { - rdim_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim_shared->bake_string_map_topology); + lane_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(scratch.arena, top); } - RDIM_BakeStringMapTopology *lane_map_top = &rdim_shared->bake_string_map_topology; - RDIM_BakeStringMapLoose *lane_map = rdim_shared->lane_bake_string_maps__loose[lane_idx()]; + RDIM_BakeStringMapLoose *lane_map = lane_maps__loose[lane_idx()]; //- rjf: push all strings into this lane's map ProfScope("push all strings into this lane's map") @@ -828,15 +835,15 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) // rjf: push small top-level strings if(lane_idx() == 0) ProfScope("push small top-level strings") { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, params->top_level_info.exe_name); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, params->top_level_info.producer_name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, params->top_level_info.exe_name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, params->top_level_info.producer_name); for(RDIM_BinarySectionNode *n = params->binary_sections.first; n != 0; n = n->next) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, n->v.name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, n->v.name); } for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, n->name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, n->name); } } @@ -849,7 +856,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, range) { RDIM_String8 normalized_path = rdim_lower_from_str8(arena, n->v[n_idx].path); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, normalized_path); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, normalized_path); } } } @@ -862,12 +869,12 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].unit_name); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].compiler_name); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].source_file); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].object_file); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].archive_file); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].build_path); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].unit_name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].compiler_name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].source_file); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].object_file); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].archive_file); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].build_path); } } } @@ -880,7 +887,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].name); } } } @@ -895,11 +902,11 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { for EachNode(mem, RDIM_UDTMember, n->v[idx].first_member) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, mem->name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, mem->name); } for EachNode(enum_val, RDIM_UDTEnumVal, n->v[idx].first_enum_val) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, enum_val->name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, enum_val->name); } } } @@ -922,8 +929,8 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].link_name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].link_name); } } } @@ -937,7 +944,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].name); } } } @@ -952,7 +959,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { for EachNode(local, RDIM_Local, n->v[n_idx].first_local) { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, local->name); + rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, local->name); } } } @@ -963,13 +970,13 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: join ProfScope("join") { - Rng1U64 slot_range = lane_range(rdim_shared->bake_string_map_topology.slots_count); + Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { - RDIM_BakeStringMapLoose *src_map = rdim_shared->lane_bake_string_maps__loose[src_lane_idx]; - RDIM_BakeStringMapLoose *dst_map = rdim_shared->bake_string_map__loose; + RDIM_BakeStringMapLoose *src_map = lane_maps__loose[src_lane_idx]; + RDIM_BakeStringMapLoose *dst_map = map__loose; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { dst_map->slots[slot_idx] = src_map->slots[slot_idx]; @@ -986,8 +993,8 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: sort ProfScope("sort") { - RDIM_BakeStringMapLoose *map = rdim_shared->bake_string_map__loose; - Rng1U64 slot_range = lane_range(rdim_shared->bake_string_map_topology.slots_count); + RDIM_BakeStringMapLoose *map = map__loose; + Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) @@ -1001,12 +1008,11 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: tighten string table ProfScope("tighten string table") { - RDIM_BakeStringMapLoose *map = rdim_shared->bake_string_map__loose; - RDIM_BakeStringMapTopology *map_top = &rdim_shared->bake_string_map_topology; + RDIM_BakeStringMapLoose *map = map__loose; if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") { - RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); - rdim_shared->bake_strings.slots_count = map_top->slots_count; + RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, top, map); + rdim_shared->bake_strings.slots_count = top->slots_count; rdim_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim_shared->bake_strings.slots_count); rdim_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; rdim_shared->bake_strings.total_count = rdim_shared->bake_strings.slots_base_idxs[rdim_shared->bake_strings.slots_count]; @@ -1024,6 +1030,8 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } } } + + scratch_end(scratch); } lane_sync(); RDIM_BakeStringMapTight *bake_strings = &rdim_shared->bake_strings; @@ -1031,11 +1039,19 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build name maps // + RDIM_BakeNameMapTopology *bake_name_maps_tops = 0; + RDIM_BakeNameMap **bake_name_maps = 0; ProfScope("build name maps") { + Temp scratch = scratch_begin(&arena, 1); + //- rjf: set up + RDIM_BakeNameMap ***lane_maps = 0; if(lane_idx() == 0) { + bake_name_maps_tops = push_array(arena, RDIM_BakeNameMapTopology, RDI_NameMapKind_COUNT); + bake_name_maps = push_array(arena, RDIM_BakeNameMap *, RDI_NameMapKind_COUNT); + lane_maps = push_array(scratch.arena, RDIM_BakeNameMap **, RDI_NameMapKind_COUNT); for EachNonZeroEnumVal(RDI_NameMapKind, k) { U64 slot_count = 0; @@ -1054,18 +1070,20 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) Case(NormalSourcePaths, params->src_files.total_count); #undef Case } - rdim_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap *, lane_count()); - rdim_shared->bake_name_map_topology[k].slots_count = slot_count; + lane_maps[k] = push_array(arena, RDIM_BakeNameMap *, lane_count()); + bake_name_maps_tops[k].slots_count = slot_count; } } - lane_sync(); + lane_sync_u64(&bake_name_maps_tops, 0); + lane_sync_u64(&bake_name_maps, 0); + lane_sync_u64(&lane_maps, 0); //- rjf: wide build for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) { - RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; - rdim_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_make(arena, top); - RDIM_BakeNameMap *map = rdim_shared->lane_bake_name_maps[k][lane_idx()]; + RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; + lane_maps[k][lane_idx()] = rdim_bake_name_map_make(scratch.arena, top); + RDIM_BakeNameMap *map = lane_maps[k][lane_idx()]; B32 link_names = 0; RDIM_SymbolChunkList *symbols = 0; switch((RDI_NameMapKindEnum)k) @@ -1126,14 +1144,14 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { for EachNonZeroEnumVal(RDI_NameMapKind, k) { - rdim_shared->bake_name_maps[k] = rdim_bake_name_map_make(arena, &rdim_shared->bake_name_map_topology[k]); + bake_name_maps[k] = rdim_bake_name_map_make(arena, &bake_name_maps_tops[k]); } } lane_sync(); for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) { - RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap *map = rdim_shared->bake_name_maps[k]; + RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; + RDIM_BakeNameMap *map = bake_name_maps[k]; //- rjf: join ProfScope("join") @@ -1143,7 +1161,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { for EachIndex(src_lane_idx, lane_count()) { - RDIM_BakeNameMap *src_map = rdim_shared->lane_bake_name_maps[k][src_lane_idx]; + RDIM_BakeNameMap *src_map = lane_maps[k][src_lane_idx]; RDIM_BakeNameMap *dst_map = map; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { @@ -1163,13 +1181,16 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + if(map->slots[slot_idx] != 0) { *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); } } } } + lane_sync(); + + scratch_end(scratch); } lane_sync(); @@ -1178,26 +1199,32 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) // ProfScope("build index runs") { + Temp scratch = scratch_begin(&arena, 1); + //- rjf: set up per-lane outputs + RDIM_BakeIdxRunMapTopology *top = 0; + RDIM_BakeIdxRunMapLoose **lane_maps__loose = 0; + RDIM_BakeIdxRunMapLoose *map__loose = 0; if(lane_idx() == 0) ProfScope("set up per-lane outputs") { - rdim_shared->bake_idx_run_map_topology.slots_count = (64 + - params->procedures.total_count + - params->global_variables.total_count + - params->thread_variables.total_count + - params->types.total_count); - rdim_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); - rdim_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim_shared->bake_idx_run_map_topology); + top = push_array(scratch.arena, RDIM_BakeIdxRunMapTopology, 1); + top->slots_count = 64 + ((params->procedures.total_count + + params->global_variables.total_count + + params->thread_variables.total_count + + params->udts.total_count) * 3) / 4; + lane_maps__loose = push_array(scratch.arena, RDIM_BakeIdxRunMapLoose *, lane_count()); + map__loose = rdim_bake_idx_run_map_loose_make(scratch.arena, top); } - lane_sync(); + lane_sync_u64(&top, 0); + lane_sync_u64(&lane_maps__loose, 0); + lane_sync_u64(&map__loose, 0); //- rjf: set up this lane's map ProfScope("set up this lane's map") { - rdim_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim_shared->bake_idx_run_map_topology); + lane_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(scratch.arena, top); } - RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim_shared->bake_idx_run_map_topology; - RDIM_BakeIdxRunMapLoose *lane_map = rdim_shared->lane_bake_idx_run_maps__loose[lane_idx()]; + RDIM_BakeIdxRunMapLoose *lane_map = lane_maps__loose[lane_idx()]; //- rjf: wide fill of all index runs ProfScope("fill all lane index run maps") @@ -1223,7 +1250,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 } - rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, param_idx_run, param_idx_run_count); + rdim_bake_idx_run_map_loose_insert(scratch.arena, top, lane_map, 4, param_idx_run, param_idx_run_count); } } } @@ -1232,15 +1259,14 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: bake runs of name map match lists for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) { - RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap *map = rdim_shared->bake_name_maps[k]; - Rng1U64 slot_idx_range = lane_range(top->slots_count); + RDIM_BakeNameMapTopology *name_map_top = &bake_name_maps_tops[k]; + RDIM_BakeNameMap *name_map = bake_name_maps[k]; + Rng1U64 slot_idx_range = lane_range(name_map_top->slots_count); for EachInRange(slot_idx, slot_idx_range) { - RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; + RDIM_BakeNameChunkList *slot = name_map->slots[slot_idx]; if(slot != 0) { - Temp scratch = scratch_begin(&arena, 1); typedef struct IdxRunNode IdxRunNode; struct IdxRunNode { @@ -1286,13 +1312,12 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) write_idx += 1; } } - rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); + rdim_bake_idx_run_map_loose_insert(scratch.arena, top, lane_map, 4, idxs, idxs_count); } active_string = string; first_idx_run_node = 0; last_idx_run_node = 0; active_idx_count = 0; - temp_end(scratch); } // rjf: new element matches the active list -> push @@ -1313,7 +1338,6 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) break; } } - scratch_end(scratch); } } } @@ -1323,13 +1347,13 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: join ProfScope("join") { - Rng1U64 slot_range = lane_range(rdim_shared->bake_idx_run_map_topology.slots_count); + Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { - RDIM_BakeIdxRunMapLoose *src_map = rdim_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; - RDIM_BakeIdxRunMapLoose *dst_map = rdim_shared->bake_idx_run_map__loose; + RDIM_BakeIdxRunMapLoose *src_map = lane_maps__loose[src_lane_idx]; + RDIM_BakeIdxRunMapLoose *dst_map = map__loose; dst_map->slots_idx_counts[slot_idx] += src_map->slots_idx_counts[slot_idx]; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { @@ -1347,11 +1371,11 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: sort ProfScope("sort") { - RDIM_BakeIdxRunMapLoose *map = rdim_shared->bake_idx_run_map__loose; - Rng1U64 slot_range = lane_range(rdim_shared->bake_idx_run_map_topology.slots_count); + RDIM_BakeIdxRunMapLoose *map = map__loose; + Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + if(map->slots[slot_idx] != 0) { *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); map->slots_idx_counts[slot_idx] = 0; @@ -1370,15 +1394,14 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: tighten idx run table ProfScope("tighten idx run table") { - RDIM_BakeIdxRunMapLoose *map = rdim_shared->bake_idx_run_map__loose; - RDIM_BakeIdxRunMapTopology *map_top = &rdim_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose *map = map__loose; if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") { - rdim_shared->bake_idx_runs.slots_count = map_top->slots_count; + rdim_shared->bake_idx_runs.slots_count = top->slots_count; rdim_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim_shared->bake_idx_runs.slots_count); rdim_shared->bake_idx_runs.slots_base_idxs = rdim_push_array(arena, RDI_U64, rdim_shared->bake_idx_runs.slots_count+1); RDI_U64 encoding_idx_off = 0; - for(RDI_U64 slot_idx = 0; slot_idx < map_top->slots_count; slot_idx += 1) + for(RDI_U64 slot_idx = 0; slot_idx < top->slots_count; slot_idx += 1) { rdim_shared->bake_idx_runs.slots_base_idxs[slot_idx] = encoding_idx_off; if(map->slots[slot_idx] != 0) @@ -1386,7 +1409,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) encoding_idx_off += map->slots_idx_counts[slot_idx]; } } - rdim_shared->bake_idx_runs.slots_base_idxs[map_top->slots_count] = encoding_idx_off; + rdim_shared->bake_idx_runs.slots_base_idxs[top->slots_count] = encoding_idx_off; } lane_sync(); ProfScope("fill tight map") @@ -1401,6 +1424,9 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) } } } + lane_sync(); + + scratch_end(scratch); } lane_sync(); RDIM_BakeIdxRunMap *bake_idx_runs = &rdim_shared->bake_idx_runs; @@ -1509,8 +1535,8 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); for EachNonZeroEnumVal(RDI_NameMapKind, k) { - RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap *map = rdim_shared->bake_name_maps[k]; + RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; + RDIM_BakeNameMap *map = bake_name_maps[k]; Rng1U64 range = lane_range(top->slots_count); for EachInRange(idx, range) { @@ -1564,7 +1590,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { rdim_shared->baked_top_level_name_maps.name_maps[k].bucket_base_idx = bucket_off; rdim_shared->baked_top_level_name_maps.name_maps[k].node_base_idx = node_off; - rdim_shared->baked_top_level_name_maps.name_maps[k].bucket_count = (RDI_U32)rdim_shared->bake_name_map_topology[k].slots_count; // TODO(rjf): @u64_to_u32 + rdim_shared->baked_top_level_name_maps.name_maps[k].bucket_count = (RDI_U32)bake_name_maps_tops[k].slots_count; // TODO(rjf): @u64_to_u32 rdim_shared->baked_top_level_name_maps.name_maps[k].node_count = (RDI_U32)rdim_shared->name_map_node_counts[k]; // TODO(rjf): @u64_to_u32 bucket_off += rdim_shared->baked_top_level_name_maps.name_maps[k].bucket_count; node_off += rdim_shared->baked_top_level_name_maps.name_maps[k].node_count; @@ -1586,9 +1612,9 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("wide fill (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) { RDI_U64 write_node_off = rdim_shared->lane_name_map_node_offs[k][lane_idx()]; - RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; + RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; U64 slots_count = top->slots_count; - RDIM_BakeNameMap *src_map = rdim_shared->bake_name_maps[k]; + RDIM_BakeNameMap *src_map = bake_name_maps[k]; RDI_NameMap *dst_map = &rdim_shared->baked_top_level_name_maps.name_maps[k]; RDI_NameMapBucket *dst_buckets = rdim_shared->baked_name_maps.buckets + dst_map->bucket_base_idx; RDI_NameMapNode *dst_nodes = rdim_shared->baked_name_maps.nodes + dst_map->node_base_idx; diff --git a/src/rdi_make/rdi_make_local.h b/src/rdi_make/rdi_make_local.h index b6134a4e..b7ed9ed9 100644 --- a/src/rdi_make/rdi_make_local.h +++ b/src/rdi_make/rdi_make_local.h @@ -65,21 +65,6 @@ struct RDIM_UnsortedJoinedLineTable typedef struct RDIM_Shared RDIM_Shared; struct RDIM_Shared { - RDI_U64 scope_vmap_count; - RDIM_SortKey *scope_vmap_keys; - RDIM_SortKey *scope_vmap_keys__swap; - RDIM_VMapMarker *scope_vmap_markers; - RDI_U64 unit_vmap_count; - RDIM_SortKey *unit_vmap_keys; - RDIM_SortKey *unit_vmap_keys__swap; - RDIM_VMapMarker *unit_vmap_markers; - RDI_U64 global_vmap_count; - RDIM_SortKey *global_vmap_keys; - RDIM_SortKey *global_vmap_keys__swap; - RDIM_VMapMarker *global_vmap_markers; - U32 **lane_digit_counts; - U32 **lane_digit_offsets; - RDIM_ScopeVMapBakeResult baked_scope_vmap; RDIM_UnitVMapBakeResult baked_unit_vmap; RDIM_GlobalVMapBakeResult baked_global_vmap; @@ -95,18 +80,8 @@ struct RDIM_Shared RDIM_LineTableBakeResult baked_line_tables; - RDIM_BakeStringMapTopology bake_string_map_topology; - RDIM_BakeStringMapLoose **lane_bake_string_maps__loose; - RDIM_BakeStringMapLoose *bake_string_map__loose; RDIM_BakeStringMapTight bake_strings; - RDIM_BakeNameMapTopology bake_name_map_topology[RDI_NameMapKind_COUNT]; - RDIM_BakeNameMap **lane_bake_name_maps[RDI_NameMapKind_COUNT]; - RDIM_BakeNameMap *bake_name_maps[RDI_NameMapKind_COUNT]; - - RDIM_BakeIdxRunMapTopology bake_idx_run_map_topology; - RDIM_BakeIdxRunMapLoose **lane_bake_idx_run_maps__loose; - RDIM_BakeIdxRunMapLoose *bake_idx_run_map__loose; RDIM_BakeIdxRunMap bake_idx_runs; RDIM_StringBakeResult baked_strings; From 80b674467345a7a8fc85e9278f700d577f92445e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 12:01:40 -0700 Subject: [PATCH 112/133] move more scratch artifacts to scratch lifetimes --- src/rdi_make/rdi_make_local.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index f1a2457e..3cc1ecb3 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -997,7 +997,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + if(map->slots[slot_idx] != 0) { *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); } @@ -1104,7 +1104,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, n_range) { RDIM_Symbol *symbol = &n->v[n_idx]; - rdim_bake_name_map_insert(arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); + rdim_bake_name_map_insert(scratch.arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); } } }break; @@ -1117,7 +1117,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, n_range) { RDIM_Type *type = &n->v[n_idx]; - rdim_bake_name_map_insert(arena, top, map, 4, type->name, rdim_idx_from_type(type)); + rdim_bake_name_map_insert(scratch.arena, top, map, 4, type->name, rdim_idx_from_type(type)); } } }break; @@ -1131,7 +1131,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { RDIM_SrcFile *src_file = &n->v[n_idx]; RDIM_String8 normalized_path = rdim_lower_from_str8(arena, src_file->path); - rdim_bake_name_map_insert(arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); + rdim_bake_name_map_insert(scratch.arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); } } }break; @@ -1183,7 +1183,9 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { if(map->slots[slot_idx] != 0) { - *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + RDIM_BakeNameChunkList *scratch_og_unsorted = map->slots[slot_idx]; + map->slots[slot_idx] = push_array(arena, RDIM_BakeNameChunkList, 1); + *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, scratch_og_unsorted); } } } From d347e2473b08d42d64150516d83e5d65da75be24 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 14:07:42 -0700 Subject: [PATCH 113/133] eliminate most reliance on p2r_shared for shared data - isolate scratch allocations, pull into scratch arenas, pop when possible --- src/rdi_from_pdb/rdi_from_pdb.c | 618 ++++++++++++++++++-------------- src/rdi_from_pdb/rdi_from_pdb.h | 68 ---- 2 files changed, 348 insertions(+), 338 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 52939b16..c81a175d 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -406,135 +406,170 @@ p2r_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunk internal RDIM_BakeParams p2r_convert(Arena *arena, P2R_ConvertParams *params) { + Temp scratch = scratch_begin(&arena, 1); + + ////////////////////////////////////////////////////////////// + //- rjf: setup shared state + // + P2R_Shared *p2r_shared = 0; + if(lane_idx() == 0) + { + p2r_shared = push_array(scratch.arena, P2R_Shared, 1); + } + lane_sync_u64(&p2r_shared, 0); + ////////////////////////////////////////////////////////////// //- rjf: do base MSF parse // + MSF_Parsed *msf = 0; { + Temp scratch2 = scratch_begin(&scratch.arena, 1); + // rjf: setup output buckets + MSF_RawStreamTable *msf_raw_stream_table = 0; if(lane_idx() == 0) { - p2r_shared = push_array(arena, P2R_Shared, 1); - p2r_shared->msf_raw_stream_table = msf_raw_stream_table_from_data(arena, params->input_pdb_data); - p2r_shared->msf = push_array(arena, MSF_Parsed, 1); - p2r_shared->msf->page_size = p2r_shared->msf_raw_stream_table->page_size; - p2r_shared->msf->page_count = p2r_shared->msf_raw_stream_table->total_page_count; - p2r_shared->msf->stream_count = p2r_shared->msf_raw_stream_table->stream_count; - p2r_shared->msf->streams = push_array(arena, String8, p2r_shared->msf->stream_count); - p2r_shared->msf_stream_lane_counter = 0; + msf_raw_stream_table = msf_raw_stream_table_from_data(scratch2.arena, params->input_pdb_data); + msf = push_array(scratch.arena, MSF_Parsed, 1); + msf->page_size = msf_raw_stream_table->page_size; + msf->page_count = msf_raw_stream_table->total_page_count; + msf->stream_count = msf_raw_stream_table->stream_count; + msf->streams = push_array(scratch.arena, String8, msf->stream_count); } - lane_sync(); + lane_sync_u64(&msf, 0); + lane_sync_u64(&msf_raw_stream_table, 0); // rjf: do wide fill { + U64 msf_stream_take_counter = 0; + U64 *msf_stream_take_counter_ptr = &msf_stream_take_counter; + lane_sync_u64(&msf_stream_take_counter_ptr, 0); for(;;) { - U64 stream_num = ins_atomic_u64_inc_eval(&p2r_shared->msf_stream_lane_counter); - if(stream_num < 1 || p2r_shared->msf->stream_count < stream_num) + U64 stream_idx = ins_atomic_u64_inc_eval(msf_stream_take_counter_ptr) - 1; + if(stream_idx >= msf->stream_count) { break; } - U64 stream_idx = stream_num-1; - p2r_shared->msf->streams[stream_idx] = msf_data_from_stream_number(arena, params->input_pdb_data, p2r_shared->msf_raw_stream_table, stream_idx); + msf->streams[stream_idx] = msf_data_from_stream_number(arena, params->input_pdb_data, msf_raw_stream_table, stream_idx); } } + lane_sync(); + + scratch_end(scratch2); } lane_sync(); - MSF_Parsed *msf = p2r_shared->msf; ////////////////////////////////////////////////////////////// //- rjf: do top-level MSF/PDB extraction // + PDB_Info *pdb_info = 0; + PDB_NamedStreamTable *named_streams = 0; ProfScope("do top-level MSF/PDB extraction") if(lane_idx() == 0) { ProfScope("parse PDB info") { String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_Info); - p2r_shared->pdb_info = pdb_info_from_data(arena, info_data); - if(p2r_shared->pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) + pdb_info = pdb_info_from_data(scratch.arena, info_data); + if(pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) { log_user_error(str8_lit("PDB was linked with /DEBUG:FASTLINK; partial debug info is not supported. Please relink using /DEBUG:FULL.")); } } ProfScope("parse named streams table") { - p2r_shared->named_streams = pdb_named_stream_table_from_info(arena, p2r_shared->pdb_info); + named_streams = pdb_named_stream_table_from_info(scratch.arena, pdb_info); } } - lane_sync(); - PDB_Info *pdb_info = p2r_shared->pdb_info; - PDB_NamedStreamTable *named_streams = p2r_shared->named_streams; + lane_sync_u64(&pdb_info, 0); + lane_sync_u64(&named_streams, 0); ////////////////////////////////////////////////////////////// //- rjf: parse PDB strtbl & top-level streams // + PDB_Strtbl *strtbl = 0; + String8 raw_strtbl = {0}; + PDB_DbiParsed *dbi = 0; + PDB_TpiParsed *tpi = 0; + PDB_TpiParsed *ipi = 0; ProfScope("parse PDB strtbl & top-level streams") { if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse PDB strtbl") { MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); - p2r_shared->strtbl = pdb_strtbl_from_data(arena, strtbl_data); - p2r_shared->raw_strtbl = str8_substr(strtbl_data, rng_1u64(p2r_shared->strtbl->strblock_min, p2r_shared->strtbl->strblock_max)); + strtbl = pdb_strtbl_from_data(scratch.arena, strtbl_data); + raw_strtbl = str8_substr(strtbl_data, rng_1u64(strtbl->strblock_min, strtbl->strblock_max)); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse DBI") { String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); - p2r_shared->dbi = pdb_dbi_from_data(arena, dbi_data); + dbi = pdb_dbi_from_data(scratch.arena, dbi_data); } if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI") { String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); - p2r_shared->tpi = pdb_tpi_from_data(arena, tpi_data); + tpi = pdb_tpi_from_data(scratch.arena, tpi_data); } if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI") { String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); - p2r_shared->ipi = pdb_tpi_from_data(arena, ipi_data); + ipi = pdb_tpi_from_data(scratch.arena, ipi_data); } } - lane_sync(); - PDB_Strtbl *strtbl = p2r_shared->strtbl; - String8 raw_strtbl = p2r_shared->raw_strtbl; - PDB_DbiParsed *dbi = p2r_shared->dbi; - PDB_TpiParsed *tpi = p2r_shared->tpi; - PDB_TpiParsed *ipi = p2r_shared->ipi; + lane_sync_u64(&strtbl, lane_from_task_idx(0)); + lane_sync_u64(&raw_strtbl.size, lane_from_task_idx(0)); + lane_sync_u64(&raw_strtbl.str, lane_from_task_idx(0)); + lane_sync_u64(&dbi, lane_from_task_idx(1)); + lane_sync_u64(&tpi, lane_from_task_idx(2)); + lane_sync_u64(&ipi, lane_from_task_idx(3)); ////////////////////////////////////////////////////////////// //- rjf: unpack DBI // + COFF_SectionHeaderArray coff_sections = {0}; + PDB_GsiParsed *gsi = 0; + PDB_GsiParsed *psi_gsi_part = 0; ProfScope("unpack DBI") { if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse COFF sections") { MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; String8 section_data = msf_data_from_stream(msf, section_stream); - p2r_shared->coff_sections = pdb_coff_section_array_from_data(arena, section_data); + coff_sections = pdb_coff_section_array_from_data(scratch.arena, section_data); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse GSI") { String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); - p2r_shared->gsi = pdb_gsi_from_data(arena, gsi_data); + gsi = pdb_gsi_from_data(scratch.arena, gsi_data); } if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse GSI part of PSI") { String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), psi_data.str + psi_data.size); - p2r_shared->psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); + psi_gsi_part = pdb_gsi_from_data(scratch.arena, psi_data_gsi_part); } } - lane_sync(); - COFF_SectionHeaderArray coff_sections = p2r_shared->coff_sections; - PDB_GsiParsed *gsi = p2r_shared->gsi; - PDB_GsiParsed *psi_gsi_part = p2r_shared->psi_gsi_part; + lane_sync_u64(&coff_sections.v, lane_from_task_idx(0)); + lane_sync_u64(&coff_sections.count, lane_from_task_idx(0)); + lane_sync_u64(&gsi, lane_from_task_idx(1)); + lane_sync_u64(&psi_gsi_part, lane_from_task_idx(2)); ////////////////////////////////////////////////////////////// //- rjf: hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units // + U64 exe_hash = 0; + PDB_TpiHashParsed *tpi_hash = 0; + CV_LeafParsed *tpi_leaf = 0; + PDB_TpiHashParsed *ipi_hash = 0; + CV_LeafParsed *ipi_leaf = 0; + PDB_CompUnitArray *comp_units = 0; + PDB_CompUnitContributionArray *comp_unit_contributions = 0; ProfScope("hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units") { if(lane_idx() == lane_from_task_idx(0)) ProfScope("hash EXE") { - p2r_shared->exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); + exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse TPI hash") { @@ -544,12 +579,12 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { hash_data = aux_data = str8_zero(); } - p2r_shared->tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data); + tpi_hash = pdb_tpi_hash_from_data(scratch.arena, strtbl, tpi, hash_data, aux_data); } if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI leaf") { String8 leaf_data = pdb_leaf_data_from_tpi(tpi); - p2r_shared->tpi_leaf = cv_leaf_from_data(arena, leaf_data, tpi->itype_first); + tpi_leaf = cv_leaf_from_data(scratch.arena, leaf_data, tpi->itype_first); } if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI hash") { @@ -559,119 +594,146 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { hash_data = aux_data = str8_zero(); } - p2r_shared->ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data); + ipi_hash = pdb_tpi_hash_from_data(scratch.arena, strtbl, ipi, hash_data, aux_data); } if(lane_idx() == lane_from_task_idx(4)) ProfScope("parse IPI leaf") { String8 leaf_data = pdb_leaf_data_from_tpi(ipi); - p2r_shared->ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); + ipi_leaf = cv_leaf_from_data(scratch.arena, leaf_data, ipi->itype_first); } if(lane_idx() == lane_from_task_idx(5)) ProfScope("parse compilation units") { String8 comp_units_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); - p2r_shared->comp_units = pdb_comp_unit_array_from_data(arena, comp_units_data); + comp_units = pdb_comp_unit_array_from_data(scratch.arena, comp_units_data); } if(lane_idx() == lane_from_task_idx(6)) ProfScope("parse compilation unit contributions") { String8 contribs_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); - p2r_shared->comp_unit_contributions = pdb_comp_unit_contribution_array_from_data(arena, contribs_data, coff_sections); + comp_unit_contributions = push_array(scratch.arena, PDB_CompUnitContributionArray, 1); + comp_unit_contributions[0] = pdb_comp_unit_contribution_array_from_data(scratch.arena, contribs_data, coff_sections); } } - lane_sync(); - U64 exe_hash = p2r_shared->exe_hash; - PDB_TpiHashParsed *tpi_hash = p2r_shared->tpi_hash; - CV_LeafParsed *tpi_leaf = p2r_shared->tpi_leaf; - PDB_TpiHashParsed *ipi_hash = p2r_shared->ipi_hash; - CV_LeafParsed *ipi_leaf = p2r_shared->ipi_leaf; - PDB_CompUnitArray *comp_units = p2r_shared->comp_units; - PDB_CompUnitContributionArray *comp_unit_contributions = &p2r_shared->comp_unit_contributions; + lane_sync_u64(&exe_hash, lane_from_task_idx(0)); + lane_sync_u64(&tpi_hash, lane_from_task_idx(1)); + lane_sync_u64(&tpi_leaf, lane_from_task_idx(2)); + lane_sync_u64(&ipi_hash, lane_from_task_idx(3)); + lane_sync_u64(&ipi_leaf, lane_from_task_idx(4)); + lane_sync_u64(&comp_units, lane_from_task_idx(5)); + lane_sync_u64(&comp_unit_contributions, lane_from_task_idx(6)); ////////////////////////////////////////////////////////////// //- rjf: bucket compilation unit contributions // + RDIM_Rng1U64ChunkList *unit_ranges = 0; ProfScope("bucket compilation unit contributions") if(lane_idx() == 0) { - p2r_shared->unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, comp_units->count); + unit_ranges = push_array(scratch.arena, RDIM_Rng1U64ChunkList, comp_units->count); for(U64 idx = 0; idx < comp_unit_contributions->count; idx += 1) { PDB_CompUnitContribution *contribution = &comp_unit_contributions->contributions[idx]; if(contribution->mod < comp_units->count) { RDIM_Rng1U64 r = {contribution->voff_first, contribution->voff_opl}; - rdim_rng1u64_chunk_list_push(arena, &p2r_shared->unit_ranges[contribution->mod], 256, r); + rdim_rng1u64_chunk_list_push(arena, &unit_ranges[contribution->mod], 256, r); } } } - lane_sync(); - RDIM_Rng1U64ChunkList *unit_ranges = p2r_shared->unit_ranges; + lane_sync_u64(&unit_ranges, 0); ////////////////////////////////////////////////////////////// //- rjf: parse all syms & c13 line info streams // + U64 all_syms_count = 0; + CV_SymParsed **all_syms = 0; + CV_C13Parsed **all_c13s = 0; ProfScope("parse all syms & c13 line info streams") { //- rjf: setup outputs if(lane_idx() == 0) { - p2r_shared->all_syms_count = comp_units->count+1; // +1 for global symbol stream from DBI - p2r_shared->all_syms = push_array(arena, CV_SymParsed *, p2r_shared->all_syms_count); - p2r_shared->all_c13s = push_array(arena, CV_C13Parsed *, p2r_shared->all_syms_count); - p2r_shared->sym_c13_unit_lane_counter = 0; + all_syms_count = comp_units->count+1; // +1 for global symbol stream from DBI + all_syms = push_array(scratch.arena, CV_SymParsed *, all_syms_count); + all_c13s = push_array(scratch.arena, CV_C13Parsed *, all_syms_count); } - lane_sync(); + lane_sync_u64(&all_syms_count, 0); + lane_sync_u64(&all_syms, 0); + lane_sync_u64(&all_c13s, 0); //- rjf: wide fill { - U64 task_count = p2r_shared->all_syms_count; + U64 task_counter = 0; + U64 *task_counter_ptr = &task_counter; + lane_sync_u64(&task_counter_ptr, 0); + U64 task_count = all_syms_count; for(;;) { - U64 task_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_c13_unit_lane_counter); - if(task_num == 0 || task_count < task_num) + U64 task_idx = ins_atomic_u64_inc_eval(task_counter_ptr) - 1; + if(task_idx >= task_count) { break; } - U64 task_idx = task_num-1; if(task_idx > 0) { PDB_CompUnit *unit = comp_units->units[task_idx-1]; String8 unit_sym_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); String8 unit_c13_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); - p2r_shared->all_syms[task_idx] = cv_sym_from_data(arena, unit_sym_data, 4); - p2r_shared->all_c13s[task_idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); + all_syms[task_idx] = cv_sym_from_data(arena, unit_sym_data, 4); + all_c13s[task_idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); } else { String8 global_sym_data = msf_data_from_stream(msf, dbi->sym_sn); - p2r_shared->all_syms[task_idx] = cv_sym_from_data(arena, global_sym_data, 4); + all_syms[task_idx] = cv_sym_from_data(arena, global_sym_data, 4); } } } } lane_sync(); - U64 all_syms_count = p2r_shared->all_syms_count; - CV_SymParsed **all_syms = p2r_shared->all_syms; - CV_C13Parsed **all_c13s = p2r_shared->all_c13s; ////////////////////////////////////////////////////////////// //- rjf: calculate EXE's max voff // - if(lane_idx() == 0) + U64 exe_voff_max = 0; { - COFF_SectionHeader *coff_sec_ptr = coff_sections.v; - COFF_SectionHeader *coff_ptr_opl = coff_sec_ptr + coff_sections.count; - for(;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1) + Temp scratch2 = scratch_begin(&scratch.arena, 1); + + // rjf: set up + U64 *lane_voff_maxes = 0; + if(lane_idx() == 0) { - U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize; - p2r_shared->exe_voff_max = Max(p2r_shared->exe_voff_max, sec_voff_max); + lane_voff_maxes = push_array(scratch2.arena, U64, lane_count()); } + lane_sync_u64(&lane_voff_maxes, 0); + + // rjf: compute each lane's max + { + U64 lane_voff_max = 0; + COFF_SectionHeader *sections = coff_sections.v; + Rng1U64 range = lane_range(coff_sections.count); + for EachInRange(idx, range) + { + lane_voff_max = Max(lane_voff_max, sections[idx].voff + sections[idx].vsize); + } + lane_voff_maxes[lane_idx()] = lane_voff_max; + } + lane_sync(); + + // rjf: find max from all lanes + U64 exe_voff_max = 0; + for EachIndex(l_idx, lane_count()) + { + exe_voff_max = Max(exe_voff_max, lane_voff_maxes[l_idx]); + } + lane_sync(); + + scratch_end(scratch2); } - lane_sync(); - U64 exe_voff_max = p2r_shared->exe_voff_max; ////////////////////////////////////////////////////////////// //- rjf: determine architecture // - if(lane_idx() == 0) + RDI_Arch arch = RDI_Arch_NULL; + U64 arch_addr_size = 0; { // // TODO(rjf): in some cases, the first compilation unit has a zero @@ -689,42 +751,44 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // for EachIndex(idx, all_syms_count) { - p2r_shared->arch = p2r_rdi_arch_from_cv_arch(all_syms[idx]->info.arch); - if(p2r_shared->arch != RDI_Arch_NULL) + arch = p2r_rdi_arch_from_cv_arch(all_syms[idx]->info.arch); + if(arch != RDI_Arch_NULL) { break; } } + arch_addr_size = rdi_addr_size_from_arch(arch); } - lane_sync(); - RDI_Arch arch = p2r_shared->arch; - U64 arch_addr_size = rdi_addr_size_from_arch(arch); ////////////////////////////////////////////////////////////// //- rjf: predict total symbol count // - if(lane_idx() == 0) + U64 symbol_count_prediction = 0; { - U64 rec_range_count = 0; - for EachIndex(idx, all_syms_count) + U64 *symbol_count_prediction_ptr = &symbol_count_prediction; + lane_sync_u64(&symbol_count_prediction_ptr, 0); + U64 lane_sym_count = 0; + Rng1U64 range = lane_range(all_syms_count); + for EachInRange(idx, range) { - rec_range_count += all_syms[idx]->sym_ranges.count; + lane_sym_count += all_syms[idx]->sym_ranges.count; } - p2r_shared->symbol_count_prediction = rec_range_count/8; - p2r_shared->symbol_count_prediction = Max(p2r_shared->symbol_count_prediction, 256); + ins_atomic_u64_add_eval(symbol_count_prediction_ptr, lane_sym_count); + lane_sync(); + symbol_count_prediction = *symbol_count_prediction_ptr; } - lane_sync(); - U64 symbol_count_prediction = p2r_shared->symbol_count_prediction; ////////////////////////////////////////////////////////////// //- rjf: build link name map // - ProfScope("build link name map") if(lane_idx() == 0 && all_syms_count != 0) + P2R_LinkNameMap *link_name_map = 0; + ProfScope("build link name map") if(all_syms_count != 0 && lane_idx() == 0) { // rjf: set up { - p2r_shared->link_name_map.buckets_count = symbol_count_prediction; - p2r_shared->link_name_map.buckets = push_array(arena, P2R_LinkNameNode *, p2r_shared->link_name_map.buckets_count); + link_name_map = push_array(scratch.arena, P2R_LinkNameMap, 1); + link_name_map->buckets_count = Max(1, symbol_count_prediction); + link_name_map->buckets = push_array(scratch.arena, P2R_LinkNameNode *, link_name_map->buckets_count); } // rjf: fill @@ -732,7 +796,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { CV_SymParsed *sym = all_syms[0]; CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = rec_ranges_first + sym->sym_ranges.count; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym->sym_ranges.count; for(CV_RecRange *rec_range = rec_ranges_first; rec_range < rec_ranges_opl; rec_range += 1) @@ -767,9 +831,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: commit to link name map U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%p2r_shared->link_name_map.buckets_count; - P2R_LinkNameNode *node = push_array(arena, P2R_LinkNameNode, 1); - SLLStackPush(p2r_shared->link_name_map.buckets[bucket_idx], node); + U64 bucket_idx = hash%link_name_map->buckets_count; + P2R_LinkNameNode *node = push_array(scratch.arena, P2R_LinkNameNode, 1); + SLLStackPush(link_name_map->buckets[bucket_idx], node); node->voff = voff; node->name = name; }break; @@ -777,43 +841,46 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } } - lane_sync(); - P2R_LinkNameMap link_name_map = p2r_shared->link_name_map; + lane_sync_u64(&link_name_map, 0); ////////////////////////////////////////////////////////////// //- rjf: gather all file paths // + P2R_SrcFileStubArray *unit_file_stubs = 0; + U64Array *unit_file_paths_hashes = 0; ProfScope("gather all file paths") { //- rjf: prep outputs ProfScope("prep outputs") if(lane_idx() == 0) { - p2r_shared->unit_file_stubs = push_array(arena, P2R_SrcFileStubArray, comp_units->count); - p2r_shared->unit_file_paths_hashes = push_array(arena, U64Array, comp_units->count); - p2r_shared->sym_lane_take_counter = 0; + unit_file_stubs = push_array(scratch.arena, P2R_SrcFileStubArray, comp_units->count); + unit_file_paths_hashes = push_array(scratch.arena, U64Array, comp_units->count); } - lane_sync(); + lane_sync_u64(&unit_file_stubs, 0); + lane_sync_u64(&unit_file_paths_hashes, 0); //- rjf: do wide gather ProfScope("do wide gather") { - Temp scratch = scratch_begin(&arena, 1); + Temp scratch2 = scratch_begin(&scratch.arena, 1); //- rjf: build local hash table to dedup files within this lane U64 hit_path_slots_count = 4096; - String8Node **hit_path_slots = push_array(scratch.arena, String8Node *, hit_path_slots_count); + String8Node **hit_path_slots = push_array(scratch2.arena, String8Node *, hit_path_slots_count); //- rjf: take units across lanes, find all file paths + U64 sym_take_counter = 0; + U64 *sym_take_counter_ptr = &sym_take_counter; + lane_sync_u64(&sym_take_counter_ptr, 0); ProfScope("take units across lanes, find all file paths") for(;;) { //- rjf: take next unit - U64 unit_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); - if(unit_num > comp_units->count) + U64 unit_idx = ins_atomic_u64_inc_eval(sym_take_counter_ptr) - 1; + if(unit_idx >= comp_units->count) { break; } - U64 unit_idx = unit_num-1; //- rjf: unpack unit PDB_CompUnit *unit = comp_units->units[unit_idx]; @@ -831,7 +898,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) MemoryZeroStruct(&obj_name); } } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + String8 obj_folder_path = backslashed_from_str8(scratch2.arena, str8_chop_last_slash(obj_name)); //- rjf: find all inline site symbols & gather file stubs P2R_SrcFileStubNode *first_src_file_stub = 0; @@ -947,19 +1014,19 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: file name -> normalized file path String8 file_path = seq_file_name; - String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); + String8 file_path_normalized = lower_from_str8(scratch2.arena, str8_skip_chop_whitespace(file_path)); { PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); - String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); + String8List file_path_normalized_parts = str8_split_path(scratch2.arena, file_path_normalized); if(file_path_normalized_style == PathStyle_Relative) { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + String8List obj_folder_path_parts = str8_split_path(scratch2.arena, obj_folder_path); str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); file_path_normalized_parts = obj_folder_path_parts; file_path_normalized_style = path_style_from_str8(obj_folder_path); } str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); - file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); + file_path_normalized = str8_path_list_join_by_style(scratch2.arena, &file_path_normalized_parts, file_path_normalized_style); } // rjf: normalized file path -> source file node @@ -976,15 +1043,15 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } if(hit_path_node == 0) { - hit_path_node = push_array(scratch.arena, String8Node, 1); + hit_path_node = push_array(scratch2.arena, String8Node, 1); SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); hit_path_node->string = file_path_normalized; - P2R_SrcFileStubNode *stub_n = push_array(arena, P2R_SrcFileStubNode, 1); + P2R_SrcFileStubNode *stub_n = push_array(scratch.arena, P2R_SrcFileStubNode, 1); SLLQueuePush(first_src_file_stub, last_src_file_stub, stub_n); src_file_stub_count += 1; - stub_n->v.file_path = str8_copy(arena, file_path_normalized); + stub_n->v.file_path = str8_copy(scratch.arena, file_path_normalized); stub_n->v.checksum_kind = checksum_kind; - stub_n->v.checksum = str8_copy(arena, checksum_value); + stub_n->v.checksum = str8_copy(scratch.arena, checksum_value); } line_count = 0; } @@ -1020,19 +1087,19 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { // rjf: file name -> sanitized file path String8 file_path = lines_n->v.file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + String8 file_path_sanitized = str8_copy(scratch2.arena, str8_skip_chop_whitespace(file_path)); { PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch2.arena, file_path_sanitized); if(file_path_sanitized_style == PathStyle_Relative) { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + String8List obj_folder_path_parts = str8_split_path(scratch2.arena, obj_folder_path); str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); file_path_sanitized_parts = obj_folder_path_parts; file_path_sanitized_style = path_style_from_str8(obj_folder_path); } str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch2.arena, &file_path_sanitized_parts, file_path_sanitized_style); } // rjf: sanitized file path -> source file node @@ -1049,71 +1116,73 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } if(hit_path_node == 0) { - hit_path_node = push_array(scratch.arena, String8Node, 1); + hit_path_node = push_array(scratch2.arena, String8Node, 1); SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); hit_path_node->string = file_path_sanitized; P2R_SrcFileStubNode *stub_n = push_array(arena, P2R_SrcFileStubNode, 1); SLLQueuePush(first_src_file_stub, last_src_file_stub, stub_n); src_file_stub_count += 1; - stub_n->v.file_path = str8_copy(arena, file_path_sanitized); + stub_n->v.file_path = str8_copy(scratch.arena, file_path_sanitized); stub_n->v.checksum_kind = lines_n->v.checksum_kind; - stub_n->v.checksum = str8_copy(arena, lines_n->v.checksum); + stub_n->v.checksum = str8_copy(scratch.arena, lines_n->v.checksum); } } } } //- rjf: merge into array for this unit - p2r_shared->unit_file_stubs[unit_idx].count = src_file_stub_count; - p2r_shared->unit_file_stubs[unit_idx].v = push_array_no_zero(arena, P2R_SrcFileStub, p2r_shared->unit_file_stubs[unit_idx].count); + unit_file_stubs[unit_idx].count = src_file_stub_count; + unit_file_stubs[unit_idx].v = push_array_no_zero(arena, P2R_SrcFileStub, unit_file_stubs[unit_idx].count); { U64 idx = 0; for EachNode(n, P2R_SrcFileStubNode, first_src_file_stub) { - p2r_shared->unit_file_stubs[unit_idx].v[idx] = n->v; + unit_file_stubs[unit_idx].v[idx] = n->v; idx += 1; } } //- rjf: hash this unit's file paths U64Array hashes = {0}; - hashes.count = p2r_shared->unit_file_stubs[unit_idx].count; + hashes.count = unit_file_stubs[unit_idx].count; hashes.v = push_array(arena, U64, hashes.count); - for EachIndex(idx, p2r_shared->unit_file_stubs[unit_idx].count) + for EachIndex(idx, unit_file_stubs[unit_idx].count) { - hashes.v[idx] = rdi_hash(p2r_shared->unit_file_stubs[unit_idx].v[idx].file_path.str, p2r_shared->unit_file_stubs[unit_idx].v[idx].file_path.size); + hashes.v[idx] = rdi_hash(unit_file_stubs[unit_idx].v[idx].file_path.str, unit_file_stubs[unit_idx].v[idx].file_path.size); } - p2r_shared->unit_file_paths_hashes[unit_idx] = hashes; + unit_file_paths_hashes[unit_idx] = hashes; } - scratch_end(scratch); + lane_sync(); + + scratch_end(scratch2); } } - lane_sync(); - P2R_SrcFileStubArray *unit_file_stubs = p2r_shared->unit_file_stubs; - U64Array *unit_file_paths_hashes = p2r_shared->unit_file_paths_hashes; ////////////////////////////////////////////////////////////// //- rjf: build unified collection & map for source files // - if(params->subset_flags & (RDIM_SubsetFlag_NormalSourcePathNameMap| - RDIM_SubsetFlag_LineInfo| - RDIM_SubsetFlag_InlineLineInfo)) + RDIM_SrcFileChunkList *all_src_files__sequenceless = 0; + P2R_SrcFileMap *src_file_map = 0; + if(lane_idx() == 0 && params->subset_flags & (RDIM_SubsetFlag_NormalSourcePathNameMap| + RDIM_SubsetFlag_LineInfo| + RDIM_SubsetFlag_InlineLineInfo)) { //- rjf: set up table - ProfScope("set up table") if(lane_idx() == 0) + U64 total_path_count = 0; + ProfScope("set up table") { - p2r_shared->total_path_count = 0; + all_src_files__sequenceless = push_array(scratch.arena, RDIM_SrcFileChunkList, 1); + src_file_map = push_array(scratch.arena, P2R_SrcFileMap, 1); for EachIndex(idx, comp_units->count) { - p2r_shared->total_path_count += unit_file_stubs[idx].count; + total_path_count += unit_file_stubs[idx].count; } - p2r_shared->src_file_map.slots_count = p2r_shared->total_path_count + p2r_shared->total_path_count/2 + 1; - p2r_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r_shared->src_file_map.slots_count); + src_file_map->slots_count = total_path_count + total_path_count/2 + 1; + src_file_map->slots = push_array(scratch.arena, P2R_SrcFileNode *, src_file_map->slots_count); } - lane_sync(); //- rjf: fill table - ProfScope("fill table") if(lane_idx() == 0) + ProfScope("fill table") { for EachIndex(idx, comp_units->count) { @@ -1125,9 +1194,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) CV_C13ChecksumKind c13_checksum_kind = stubs.v[stub_idx].checksum_kind; String8 checksum = stubs.v[stub_idx].checksum; U64 file_path_sanitized_hash = hashes.v[stub_idx]; - U64 src_file_slot = file_path_sanitized_hash%p2r_shared->src_file_map.slots_count; + U64 src_file_slot = file_path_sanitized_hash%src_file_map->slots_count; P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = p2r_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) + for(P2R_SrcFileNode *n = src_file_map->slots[src_file_slot]; n != 0; n = n->next) { if(str8_match(n->src_file->path, file_path_sanitized, 0)) { @@ -1138,8 +1207,8 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) if(src_file_node == 0) { src_file_node = push_array(arena, P2R_SrcFileNode, 1); - SLLStackPush(p2r_shared->src_file_map.slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r_shared->all_src_files__sequenceless, p2r_shared->total_path_count); + SLLStackPush(src_file_map->slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, all_src_files__sequenceless, total_path_count); src_file_node->src_file->path = str8_copy(arena, file_path_sanitized); src_file_node->src_file->checksum_kind = p2r_rdi_from_cv_c13_checksum_kind(c13_checksum_kind); src_file_node->src_file->checksum = str8_copy(arena, checksum); @@ -1148,33 +1217,36 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } } - lane_sync(); - RDIM_SrcFileChunkList all_src_files__sequenceless = p2r_shared->all_src_files__sequenceless; - P2R_SrcFileMap src_file_map = p2r_shared->src_file_map; + lane_sync_u64(&all_src_files__sequenceless, 0); + lane_sync_u64(&src_file_map, 0); ////////////////////////////////////////////////////////////// //- rjf: convert unit info // + RDIM_UnitChunkList *all_units_ptr = 0; + RDIM_LineTableChunkList *units_line_tables = 0; + RDIM_LineTable **units_first_inline_site_line_tables = 0; ProfScope("convert unit info") { //- rjf: set up outputs ProfScope("set up outputs") if(lane_idx() == 0) { + all_units_ptr = push_array(scratch.arena, RDIM_UnitChunkList, 1); if(params->subset_flags & RDIM_SubsetFlag_Units) { for EachIndex(idx, comp_units->count) { - rdim_unit_chunk_list_push(arena, &p2r_shared->all_units, comp_units->count); + rdim_unit_chunk_list_push(arena, all_units_ptr, comp_units->count); } } - p2r_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); - p2r_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); - p2r_shared->sym_lane_take_counter = 0; + units_line_tables = push_array(scratch.arena, RDIM_LineTableChunkList, comp_units->count); + units_first_inline_site_line_tables = push_array(scratch.arena, RDIM_LineTable *, comp_units->count); } - lane_sync(); - RDIM_Unit *units = p2r_shared->all_units.first ? p2r_shared->all_units.first->v : 0; - U64 units_count = p2r_shared->all_units.first ? p2r_shared->all_units.first->count : 0; - RDIM_LineTableChunkList *units_line_tables = p2r_shared->units_line_tables; + lane_sync_u64(&all_units_ptr, 0); + lane_sync_u64(&units_line_tables, 0); + lane_sync_u64(&units_first_inline_site_line_tables, 0); + RDIM_Unit *units = all_units_ptr->first ? all_units_ptr->first->v : 0; + U64 units_count = all_units_ptr->first ? all_units_ptr->first->count : 0; Assert(units_count == comp_units->count); //- rjf: do per-lane work @@ -1183,16 +1255,18 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_SubsetFlag_LineInfo| RDIM_SubsetFlag_InlineLineInfo)) { + U64 sym_take_counter = 0; + U64 *sym_take_counter_ptr = &sym_take_counter; + lane_sync_u64(&sym_take_counter_ptr, 0); ProfScope("wide fill") for(;;) { //- rjf: take next unit - U64 unit_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); - if(unit_num > comp_units->count) + U64 unit_idx = ins_atomic_u64_inc_eval(sym_take_counter_ptr) - 1; + if(unit_idx >= comp_units->count) { break; } Temp scratch = scratch_begin(&arena, 1); - U64 unit_idx = unit_num-1; RDIM_LineTableChunkList *dst_line_tables = &units_line_tables[unit_idx]; PDB_CompUnit *src_unit = comp_units->units[unit_idx]; CV_SymParsed *src_unit_sym = all_syms[unit_idx+1]; @@ -1255,11 +1329,11 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: sanitized file path -> source file node U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + U64 src_file_slot = file_path_sanitized_hash%src_file_map->slots_count; P2R_SrcFileNode *src_file_node = 0; if(lines->line_count != 0) { - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + for(P2R_SrcFileNode *n = src_file_map->slots[src_file_slot]; n != 0; n = n->next) { if(str8_match(n->src_file->path, file_path_sanitized, 0)) { @@ -1436,9 +1510,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: sanitized file path -> source file node U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + U64 src_file_slot = file_path_sanitized_hash%src_file_map->slots_count; P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + for(P2R_SrcFileNode *n = src_file_map->slots[src_file_slot]; n != 0; n = n->next) { if(str8_match(n->src_file->path, file_path_sanitized, 0)) { @@ -1471,9 +1545,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) if(line_table == 0) { line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - if(p2r_shared->units_first_inline_site_line_tables[unit_idx] == 0) + if(units_first_inline_site_line_tables[unit_idx] == 0) { - p2r_shared->units_first_inline_site_line_tables[unit_idx] = line_table; + units_first_inline_site_line_tables[unit_idx] = line_table; } } rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); @@ -1520,22 +1594,22 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } lane_sync(); - RDIM_UnitChunkList all_units = p2r_shared->all_units; - RDIM_LineTableChunkList *units_line_tables = p2r_shared->units_line_tables; - RDIM_LineTable **units_first_inline_site_line_tables = p2r_shared->units_first_inline_site_line_tables; + RDIM_UnitChunkList all_units = *all_units_ptr; ////////////////////////////////////////////////////////////// //- rjf: join all line tables // + RDIM_LineTableChunkList all_line_tables = {0}; + RDIM_LineTableChunkList *all_line_tables_ptr = &all_line_tables; ProfScope("join all line tables") if(lane_idx() == 0) { for EachIndex(idx, comp_units->count) { - rdim_line_table_chunk_list_concat_in_place(&p2r_shared->all_line_tables, &units_line_tables[idx]); + rdim_line_table_chunk_list_concat_in_place(&all_line_tables, &units_line_tables[idx]); } } - lane_sync(); - RDIM_LineTableChunkList all_line_tables = p2r_shared->all_line_tables; + lane_sync_u64(&all_line_tables_ptr, 0); + all_line_tables = *all_line_tables_ptr; ////////////////////////////////////////////////////////////// //- rjf: equip source files with line sequences @@ -1551,13 +1625,13 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_LineTable *line_table = &line_table_chunk_n->v[chunk_line_table_idx]; for(RDIM_LineSequenceNode *s = line_table->first_seq; s != 0; s = s->next) { - rdim_src_file_push_line_sequence(arena, &p2r_shared->all_src_files__sequenceless, s->v.src_file, &s->v); + rdim_src_file_push_line_sequence(arena, all_src_files__sequenceless, s->v.src_file, &s->v); } } } } lane_sync(); - RDIM_SrcFileChunkList all_src_files = p2r_shared->all_src_files__sequenceless; + RDIM_SrcFileChunkList all_src_files = *all_src_files__sequenceless; ////////////////////////////////////////////////////////////// //- rjf: types pass 1: produce type forward resolution map @@ -1568,25 +1642,30 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // to hook types up to their actual destination complete types wherever // possible, and so this map can be used to do that in subsequent stages. // + CV_TypeId *itype_fwd_map = 0; + CV_TypeId itype_first = 0; + CV_TypeId itype_opl = 0; ProfScope("types pass 1: produce type forward resolution map") { //- rjf: allocate forward resolution map if(lane_idx() == 0) { - p2r_shared->itype_first = tpi_leaf->itype_first; - p2r_shared->itype_opl = tpi_leaf->itype_opl; - p2r_shared->itype_fwd_map = push_array(arena, CV_TypeId, (U64)p2r_shared->itype_opl); + itype_first = tpi_leaf->itype_first; + itype_opl = tpi_leaf->itype_opl; + itype_fwd_map = push_array(scratch.arena, CV_TypeId, (U64)itype_opl); } - lane_sync(); + lane_sync_u64(&itype_first, 0); + lane_sync_u64(&itype_opl, 0); + lane_sync_u64(&itype_fwd_map, 0); //- rjf: do wide fill if(params->subset_flags & RDIM_SubsetFlag_Types) { - Rng1U64 range = lane_range(p2r_shared->itype_opl); + Rng1U64 range = lane_range(itype_opl); for EachInRange(idx, range) { CV_TypeId itype = (CV_TypeId)idx; - if(itype < p2r_shared->itype_first) { continue; } + if(itype < itype_first) { continue; } //- rjf: determine if this itype resolves to another CV_TypeId itype_fwd = 0; @@ -1698,15 +1777,12 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: if the forwarded itype is nonzero & in TPI range -> save to map if(itype_fwd != 0 && itype_fwd < tpi_leaf->itype_opl) { - p2r_shared->itype_fwd_map[itype] = itype_fwd; + itype_fwd_map[itype] = itype_fwd; } } } } lane_sync(); - CV_TypeId *itype_fwd_map = p2r_shared->itype_fwd_map; - CV_TypeId itype_first = p2r_shared->itype_first; - CV_TypeId itype_opl = p2r_shared->itype_opl; ////////////////////////////////////////////////////////////// //- rjf: types pass 2: produce per-itype itype chain @@ -1718,29 +1794,30 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // this chain is walked, so that deeper dependencies are built first, and // as such, always show up *earlier* in the actually built types. // + P2R_TypeIdChain **itype_chains = 0; ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") { //- rjf: allocate itype chain table if(lane_idx() == 0) { - p2r_shared->itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)p2r_shared->itype_opl); + itype_chains = push_array(scratch.arena, P2R_TypeIdChain *, (U64)itype_opl); } - lane_sync(); + lane_sync_u64(&itype_chains, 0); //- rjf: do wide fill if(params->subset_flags & RDIM_SubsetFlag_Types) { - Rng1U64 range = lane_range(p2r_shared->itype_opl); + Rng1U64 range = lane_range(itype_opl); for EachInRange(idx, range) { CV_TypeId itype = (CV_TypeId)idx; - if(itype < p2r_shared->itype_first) { continue; } + if(itype < itype_first) { continue; } //- rjf: push initial itype - should be final-visited-itype for this itype { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } //- rjf: skip basic types for dependency walk @@ -1750,7 +1827,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } //- rjf: walk dependent types, push to chain - Temp scratch = scratch_begin(&arena, 1); + Temp scratch2 = scratch_begin(&scratch.arena, 1); P2R_TypeIdChain start_walk_task = {0, itype}; P2R_TypeIdChain *first_walk_task = &start_walk_task; P2R_TypeIdChain *last_walk_task = &start_walk_task; @@ -1783,14 +1860,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push dependent itype to chain { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk dependency itype { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->itype; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -1803,14 +1880,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push dependent itype to chain { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk dependency itype { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->itype; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -1823,14 +1900,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push return itypes to chain { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->ret_itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk return itype { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->ret_itype; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -1858,15 +1935,15 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push arg types to chain for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = arglist_itypes_base[idx]; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk arg types for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = arglist_itypes_base[idx]; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -1879,34 +1956,34 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push dependent itypes to chain { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->ret_itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->arg_itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->this_itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk dependency itypes { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->ret_itype; SLLQueuePush(first_walk_task, last_walk_task, c); } { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->arg_itype; SLLQueuePush(first_walk_task, last_walk_task, c); } { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->this_itype; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -1934,15 +2011,15 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push arg types to chain for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = arglist_itypes_base[idx]; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk arg types for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = arglist_itypes_base[idx]; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -1955,14 +2032,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push dependent itype to chain { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk dependency itype { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->itype; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -1975,24 +2052,24 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push dependent itypes to chain { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->entry_itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->index_itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk dependency itypes { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->entry_itype; SLLQueuePush(first_walk_task, last_walk_task, c); } { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->index_itype; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -2005,14 +2082,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: push dependent itypes to chain { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); c->itype = lf->base_itype; - SLLStackPush(p2r_shared->itype_chains[itype], c); + SLLStackPush(itype_chains[itype], c); } // rjf: push task to walk dependency itypes { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + P2R_TypeIdChain *c = push_array(scratch2.arena, P2R_TypeIdChain, 1); c->itype = lf->base_itype; SLLQueuePush(first_walk_task, last_walk_task, c); } @@ -2020,12 +2097,11 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } } - scratch_end(scratch); + scratch_end(scratch2); } } } lane_sync(); - P2R_TypeIdChain **itype_chains = p2r_shared->itype_chains; ////////////////////////////////////////////////////////////// //- rjf: types pass 3: construct all types from TPI @@ -2034,13 +2110,16 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // subsequent passes, to build RDI "UDT" information, which is distinct // from regular type info. // + RDIM_TypeChunkList all_types__pre_typedefs = {0}; + RDIM_TypeChunkList *all_types__pre_typedefs_ptr = &all_types__pre_typedefs; + RDIM_Type **itype_type_ptrs = 0; + RDIM_Type **basic_type_ptrs = 0; if(lane_idx() == 0) ProfScope("types pass 3: construct all root/stub types from TPI") { #define p2r_builtin_type_ptr_from_kind(kind) ((basic_type_ptrs && RDI_TypeKind_FirstBuiltIn <= (kind) && (kind) <= RDI_TypeKind_LastBuiltIn) ? (basic_type_ptrs[(kind) - RDI_TypeKind_FirstBuiltIn]) : 0) #define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - RDIM_Type **itype_type_ptrs = push_array(arena, RDIM_Type *, (U64)(itype_opl)); - RDIM_Type **basic_type_ptrs = push_array(arena, RDIM_Type *, (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn + 1)); - RDIM_TypeChunkList all_types = {0}; + itype_type_ptrs = push_array(scratch.arena, RDIM_Type *, (U64)(itype_opl)); + basic_type_ptrs = push_array(scratch.arena, RDIM_Type *, (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn + 1)); //////////////////////////// //- rjf: build basic types @@ -2051,7 +2130,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) type_kind <= RDI_TypeKind_LastBuiltIn; type_kind += 1) { - RDIM_Type *type = rdim_type_chunk_list_push(arena, &all_types, 512); + RDIM_Type *type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, 512); type->name.str = rdi_string_from_type_kind(type_kind, &type->name.size); type->kind = type_kind; type->byte_size = rdi_size_from_basic_type_kind(type_kind); @@ -2124,7 +2203,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) }; for EachElement(idx, table) { - RDIM_Type *builtin_alias = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + RDIM_Type *builtin_alias = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, tpi_leaf->itype_opl); builtin_alias->kind = RDI_TypeKind_Alias; builtin_alias->name = str8_cstring(table[idx].name); builtin_alias->direct_type = p2r_builtin_type_ptr_from_kind(table[idx].kind_rdi); @@ -2184,7 +2263,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { RDI_TypeKind type_kind = p2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); U32 byte_size = rdi_size_from_basic_type_kind(type_kind); - basic_type = dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + basic_type = dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); if(byte_size == 0xffffffff) { byte_size = arch_addr_size; @@ -2197,7 +2276,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: nonzero ptr kind -> form ptr type to basic tpye if(cv_basic_ptr_kind != 0) { - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); dst_type->kind = RDI_TypeKind_Ptr; dst_type->byte_size = arch_addr_size; dst_type->direct_type = basic_type; @@ -2242,7 +2321,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } else { - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); dst_type->kind = RDI_TypeKind_Modifier; dst_type->flags = flags; dst_type->direct_type = p2r_type_ptr_from_itype(lf->itype); @@ -2292,8 +2371,8 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: fill type if(modifier_flags != 0) { - RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); dst_type->kind = RDI_TypeKind_Modifier; dst_type->flags = modifier_flags; dst_type->direct_type = pointer_type; @@ -2304,7 +2383,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } else { - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); dst_type->kind = type_kind; dst_type->byte_size = arch_addr_size; dst_type->direct_type = direct_type; @@ -2321,7 +2400,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); // rjf: fill type's basics - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); dst_type->kind = RDI_TypeKind_Function; dst_type->byte_size = arch_addr_size; dst_type->direct_type = ret_type; @@ -2369,7 +2448,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); dst_type->kind = (lf->this_itype != 0) ? RDI_TypeKind_Method : RDI_TypeKind_Function; dst_type->byte_size = arch_addr_size; dst_type->direct_type = ret_type; @@ -2423,7 +2502,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); dst_type->kind = RDI_TypeKind_Bitfield; dst_type->off = lf->pos; dst_type->count = lf->len; @@ -2442,7 +2521,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) U64 full_size = cv_u64_from_numeric(&array_count); // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); dst_type->kind = RDI_TypeKind_Array; dst_type->direct_type = direct_type; dst_type->byte_size = full_size; @@ -2464,7 +2543,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); if(lf->props & CV_TypeProp_FwdRef) { dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); @@ -2493,7 +2572,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); if(lf->props & CV_TypeProp_FwdRef) { dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); @@ -2521,7 +2600,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); if(lf->props & CV_TypeProp_FwdRef) { dst_type->kind = RDI_TypeKind_IncompleteUnion; @@ -2547,7 +2626,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, all_types__pre_typedefs_ptr, (U64)itype_opl); if(lf->props & CV_TypeProp_FwdRef) { dst_type->kind = RDI_TypeKind_IncompleteEnum; @@ -2570,16 +2649,13 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } } - p2r_shared->itype_type_ptrs = itype_type_ptrs; - p2r_shared->basic_type_ptrs = basic_type_ptrs; - p2r_shared->all_types__pre_typedefs = all_types; #undef p2r_type_ptr_from_itype #undef p2r_builtin_type_ptr_from_kind } - lane_sync(); - RDIM_Type **itype_type_ptrs = p2r_shared->itype_type_ptrs; - RDIM_Type **basic_type_ptrs = p2r_shared->basic_type_ptrs; - RDIM_TypeChunkList all_types__pre_typedefs = p2r_shared->all_types__pre_typedefs; + lane_sync_u64(&itype_type_ptrs, 0); + lane_sync_u64(&basic_type_ptrs, 0); + lane_sync_u64(&all_types__pre_typedefs_ptr, 0); + all_types__pre_typedefs = *all_types__pre_typedefs_ptr; ////////////////////////////////////////////////////////////// //- rjf: types pass 4: build UDTs @@ -3258,7 +3334,6 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) p2r_shared->syms_scopes = push_array(arena, RDIM_ScopeChunkList, all_syms_count); p2r_shared->syms_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, all_syms_count); p2r_shared->syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); - p2r_shared->sym_lane_take_counter = 0; } lane_sync(); @@ -3277,15 +3352,17 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_SubsetFlag_LinkNameProcedureNameMap| RDIM_SubsetFlag_Types)) { + U64 sym_take_counter = 0; + U64 *sym_take_counter_ptr = &sym_take_counter; + lane_sync_u64(&sym_take_counter_ptr, 0); for(;;) { //- rjf: take next sym - U64 sym_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); - if(sym_num > all_syms_count) + U64 sym_idx = ins_atomic_u64_inc_eval(sym_take_counter_ptr) - 1; + if(sym_idx >= all_syms_count) { break; } - U64 sym_idx = sym_num-1; //- rjf: unpack sym Temp scratch = scratch_begin(&arena, 1); @@ -3602,9 +3679,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { U64 voff = procedure_root_scope->voff_ranges.min; U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%link_name_map.buckets_count; + U64 bucket_idx = hash%link_name_map->buckets_count; P2R_LinkNameNode *node = 0; - for(P2R_LinkNameNode *n = link_name_map.buckets[bucket_idx]; n != 0; n = n->next) + for(P2R_LinkNameNode *n = link_name_map->buckets[bucket_idx]; n != 0; n = n->next) { if(n->voff == voff) { @@ -4261,9 +4338,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { for EachIndex(idx, all_syms_count) { - rdim_type_chunk_list_concat_in_place(&p2r_shared->all_types__pre_typedefs, &p2r_shared->syms_typedefs[idx]); + rdim_type_chunk_list_concat_in_place(&all_types__pre_typedefs, &p2r_shared->syms_typedefs[idx]); } - p2r_shared->all_types = p2r_shared->all_types__pre_typedefs; + p2r_shared->all_types = all_types__pre_typedefs; } } lane_sync(); @@ -4331,5 +4408,6 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) result.inline_sites = all_inline_sites; } + scratch_end(scratch); return result; } diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index 64939815..7352bba9 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -92,69 +92,6 @@ struct P2R_TypeIdChain typedef struct P2R_Shared P2R_Shared; struct P2R_Shared { - MSF_RawStreamTable *msf_raw_stream_table; - U64 msf_stream_lane_counter; - MSF_Parsed *msf; - - PDB_Info *pdb_info; - PDB_NamedStreamTable *named_streams; - - PDB_Strtbl *strtbl; - String8 raw_strtbl; - PDB_DbiParsed *dbi; - PDB_TpiParsed *tpi; - PDB_TpiParsed *ipi; - - COFF_SectionHeaderArray coff_sections; - PDB_GsiParsed *gsi; - PDB_GsiParsed *psi_gsi_part; - - U64 exe_hash; - PDB_TpiHashParsed *tpi_hash; - CV_LeafParsed *tpi_leaf; - PDB_TpiHashParsed *ipi_hash; - CV_LeafParsed *ipi_leaf; - PDB_CompUnitArray *comp_units; - PDB_CompUnitContributionArray comp_unit_contributions; - RDIM_Rng1U64ChunkList *unit_ranges; - - U64 sym_c13_unit_lane_counter; - U64 all_syms_count; - CV_SymParsed **all_syms; // [0] -> global; rest are unit nums - CV_C13Parsed **all_c13s; // [0] -> blank (global); rest are unit nums - - U64 exe_voff_max; - RDI_Arch arch; - U64 symbol_count_prediction; - - P2R_LinkNameMap link_name_map; - - U64 sym_lane_take_counter; - - P2R_SrcFileStubArray *unit_file_stubs; - U64Array *unit_file_paths_hashes; - - U64 total_path_count; - - RDIM_SrcFileChunkList all_src_files__sequenceless; - P2R_SrcFileMap src_file_map; - - RDIM_UnitChunkList all_units; - RDIM_LineTableChunkList *units_line_tables; - RDIM_LineTable **units_first_inline_site_line_tables; - - RDIM_LineTableChunkList all_line_tables; - - CV_TypeId *itype_fwd_map; - CV_TypeId itype_first; - CV_TypeId itype_opl; - - P2R_TypeIdChain **itype_chains; - - RDIM_Type **itype_type_ptrs; - RDIM_Type **basic_type_ptrs; - RDIM_TypeChunkList all_types__pre_typedefs; - RDIM_UDTChunkList *lanes_udts; RDIM_UDTChunkList all_udts; @@ -178,11 +115,6 @@ struct P2R_Shared RDIM_TypeChunkList all_types; }; -//////////////////////////////// -//~ rjf: Globals - -global P2R_Shared *p2r_shared = 0; - //////////////////////////////// //~ rjf: Basic Helpers From 9377efbe13a78716acc1cac1d16d735c895b24b1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 14:21:32 -0700 Subject: [PATCH 114/133] eliminate rest of p2r_shared usage, just use lane syncs --- src/rdi_from_pdb/rdi_from_pdb.c | 157 +++++++++++++++++++------------- src/rdi_from_pdb/rdi_from_pdb.h | 28 ------ 2 files changed, 93 insertions(+), 92 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index c81a175d..48df49be 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -408,16 +408,6 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { Temp scratch = scratch_begin(&arena, 1); - ////////////////////////////////////////////////////////////// - //- rjf: setup shared state - // - P2R_Shared *p2r_shared = 0; - if(lane_idx() == 0) - { - p2r_shared = push_array(scratch.arena, P2R_Shared, 1); - } - lane_sync_u64(&p2r_shared, 0); - ////////////////////////////////////////////////////////////// //- rjf: do base MSF parse // @@ -2660,23 +2650,18 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) ////////////////////////////////////////////////////////////// //- rjf: types pass 4: build UDTs // + RDIM_UDTChunkList *lanes_udts = 0; ProfScope("types pass 4: build UDTs") { #define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < tpi_leaf->itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - //- rjf: set up - if(lane_idx() == 0) - { - p2r_shared->lanes_udts = push_array(arena, RDIM_UDTChunkList, lane_count()); - } - lane_sync(); - - //- rjf: do wide fill + //- rjf: gather this lane's UDTs + RDIM_UDTChunkList lane_udts = {0}; if(params->subset_flags & RDIM_SubsetFlag_Types && params->subset_flags & RDIM_SubsetFlag_UDTs) { U64 udts_chunk_cap = 4096; - RDIM_UDTChunkList *udts = &p2r_shared->lanes_udts[lane_idx()]; + RDIM_UDTChunkList *udts = &lane_udts; Rng1U64 range = lane_range(itype_opl); for EachInRange(idx, range) { @@ -3296,27 +3281,45 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } } + + //- rjf: collect all lanes + if(lane_idx() == 0) + { + lanes_udts = push_array(scratch.arena, RDIM_UDTChunkList, lane_count()); + } + lane_sync_u64(&lanes_udts, 0); + lanes_udts[lane_idx()] = lane_udts; #undef p2r_type_ptr_from_itype } lane_sync(); - RDIM_UDTChunkList *lanes_udts = p2r_shared->lanes_udts; ////////////////////////////////////////////////////////////// //- rjf: join all UDTs // + RDIM_UDTChunkList all_udts = {0}; ProfScope("join all UDTs") if(lane_idx() == 0) { for EachIndex(idx, lane_count()) { - rdim_udt_chunk_list_concat_in_place(&p2r_shared->all_udts, &lanes_udts[idx]); + rdim_udt_chunk_list_concat_in_place(&all_udts, &lanes_udts[idx]); } } lane_sync(); - RDIM_UDTChunkList all_udts = p2r_shared->all_udts; + RDIM_UDTChunkList *all_udts_ptr = &all_udts; + lane_sync_u64(&all_udts_ptr, 0); + all_udts = *all_udts_ptr; ////////////////////////////////////////////////////////////// //- rjf: produce symbols from all streams // + RDIM_LocationChunkList *syms_locations = 0; + RDIM_SymbolChunkList *syms_procedures = 0; + RDIM_SymbolChunkList *syms_global_variables = 0; + RDIM_SymbolChunkList *syms_thread_variables = 0; + RDIM_SymbolChunkList *syms_constants = 0; + RDIM_ScopeChunkList *syms_scopes = 0; + RDIM_InlineSiteChunkList *syms_inline_sites = 0; + RDIM_TypeChunkList *syms_typedefs = 0; ProfScope("produce symbols from all streams") { #define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) @@ -3326,16 +3329,23 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // if(lane_idx() == 0) { - p2r_shared->syms_locations = push_array(arena, RDIM_LocationChunkList, all_syms_count); - p2r_shared->syms_procedures = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r_shared->syms_global_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r_shared->syms_thread_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r_shared->syms_constants = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r_shared->syms_scopes = push_array(arena, RDIM_ScopeChunkList, all_syms_count); - p2r_shared->syms_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, all_syms_count); - p2r_shared->syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); + syms_locations = push_array(arena, RDIM_LocationChunkList, all_syms_count); + syms_procedures = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + syms_global_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + syms_thread_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + syms_constants = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + syms_scopes = push_array(arena, RDIM_ScopeChunkList, all_syms_count); + syms_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, all_syms_count); + syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); } - lane_sync(); + lane_sync_u64(&syms_locations, 0); + lane_sync_u64(&syms_procedures, 0); + lane_sync_u64(&syms_global_variables, 0); + lane_sync_u64(&syms_thread_variables, 0); + lane_sync_u64(&syms_constants, 0); + lane_sync_u64(&syms_scopes, 0); + lane_sync_u64(&syms_inline_sites, 0); + lane_sync_u64(&syms_typedefs, 0); //////////////////////////// //- rjf: fill outputs for all unit sym blocks in this lane @@ -3375,14 +3385,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) U64 sym_constants_chunk_cap = 16384; U64 sym_scopes_chunk_cap = 16384; U64 sym_inline_sites_chunk_cap = 16384; - RDIM_LocationChunkList *sym_locations = &p2r_shared->syms_locations[sym_idx]; - RDIM_SymbolChunkList *sym_procedures = &p2r_shared->syms_procedures[sym_idx]; - RDIM_SymbolChunkList *sym_global_variables = &p2r_shared->syms_global_variables[sym_idx]; - RDIM_SymbolChunkList *sym_thread_variables = &p2r_shared->syms_thread_variables[sym_idx]; - RDIM_SymbolChunkList *sym_constants = &p2r_shared->syms_constants[sym_idx]; - RDIM_ScopeChunkList *sym_scopes = &p2r_shared->syms_scopes[sym_idx]; - RDIM_InlineSiteChunkList *sym_inline_sites = &p2r_shared->syms_inline_sites[sym_idx]; - RDIM_TypeChunkList *typedefs = &p2r_shared->syms_typedefs[sym_idx]; + RDIM_LocationChunkList *sym_locations = &syms_locations[sym_idx]; + RDIM_SymbolChunkList *sym_procedures = &syms_procedures[sym_idx]; + RDIM_SymbolChunkList *sym_global_variables = &syms_global_variables[sym_idx]; + RDIM_SymbolChunkList *sym_thread_variables = &syms_thread_variables[sym_idx]; + RDIM_SymbolChunkList *sym_constants = &syms_constants[sym_idx]; + RDIM_ScopeChunkList *sym_scopes = &syms_scopes[sym_idx]; + RDIM_InlineSiteChunkList *sym_inline_sites = &syms_inline_sites[sym_idx]; + RDIM_TypeChunkList *typedefs = &syms_typedefs[sym_idx]; ////////////////////////// //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) @@ -4284,74 +4294,93 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) ////////////////////////////////////////////////////////////// //- rjf: join all lane symbols // + RDIM_LocationChunkList *all_locations = 0; + RDIM_SymbolChunkList *all_procedures = 0; + RDIM_SymbolChunkList *all_global_variables = 0; + RDIM_SymbolChunkList *all_thread_variables = 0; + RDIM_SymbolChunkList *all_constants = 0; + RDIM_ScopeChunkList *all_scopes = 0; + RDIM_InlineSiteChunkList *all_inline_sites = 0; + RDIM_TypeChunkList *all_types = 0; { + if(lane_idx() == 0) + { + all_locations = push_array(scratch.arena, RDIM_LocationChunkList, 1); + all_procedures = push_array(scratch.arena, RDIM_SymbolChunkList, 1); + all_global_variables = push_array(scratch.arena, RDIM_SymbolChunkList, 1); + all_thread_variables = push_array(scratch.arena, RDIM_SymbolChunkList, 1); + all_constants = push_array(scratch.arena, RDIM_SymbolChunkList, 1); + all_scopes = push_array(scratch.arena, RDIM_ScopeChunkList, 1); + all_inline_sites = push_array(scratch.arena, RDIM_InlineSiteChunkList, 1); + all_types = push_array(scratch.arena, RDIM_TypeChunkList, 1); + } + lane_sync_u64(&all_locations, 0); + lane_sync_u64(&all_procedures, 0); + lane_sync_u64(&all_global_variables, 0); + lane_sync_u64(&all_thread_variables, 0); + lane_sync_u64(&all_constants, 0); + lane_sync_u64(&all_scopes, 0); + lane_sync_u64(&all_inline_sites, 0); + lane_sync_u64(&all_types, 0); if(lane_idx() == lane_from_task_idx(0)) ProfScope("join locations") { for EachIndex(idx, all_syms_count) { - rdim_location_chunk_list_concat_in_place(&p2r_shared->all_locations, &p2r_shared->syms_locations[idx]); + rdim_location_chunk_list_concat_in_place(all_locations, &syms_locations[idx]); } } if(lane_idx() == lane_from_task_idx(1)) ProfScope("join procedures") { for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r_shared->all_procedures, &p2r_shared->syms_procedures[idx]); + rdim_symbol_chunk_list_concat_in_place(all_procedures, &syms_procedures[idx]); } } if(lane_idx() == lane_from_task_idx(2)) ProfScope("join global variables") { for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r_shared->all_global_variables, &p2r_shared->syms_global_variables[idx]); + rdim_symbol_chunk_list_concat_in_place(all_global_variables, &syms_global_variables[idx]); } } if(lane_idx() == lane_from_task_idx(3)) ProfScope("join thread variables") { for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r_shared->all_thread_variables, &p2r_shared->syms_thread_variables[idx]); + rdim_symbol_chunk_list_concat_in_place(all_thread_variables, &syms_thread_variables[idx]); } } if(lane_idx() == lane_from_task_idx(4)) ProfScope("join constants") { for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r_shared->all_constants, &p2r_shared->syms_constants[idx]); + rdim_symbol_chunk_list_concat_in_place(all_constants, &syms_constants[idx]); } } if(lane_idx() == lane_from_task_idx(5)) ProfScope("join scopes") { for EachIndex(idx, all_syms_count) { - rdim_scope_chunk_list_concat_in_place(&p2r_shared->all_scopes, &p2r_shared->syms_scopes[idx]); + rdim_scope_chunk_list_concat_in_place(all_scopes, &syms_scopes[idx]); } } if(lane_idx() == lane_from_task_idx(6)) ProfScope("join inline sites") { for EachIndex(idx, all_syms_count) { - rdim_inline_site_chunk_list_concat_in_place(&p2r_shared->all_inline_sites, &p2r_shared->syms_inline_sites[idx]); + rdim_inline_site_chunk_list_concat_in_place(all_inline_sites, &syms_inline_sites[idx]); } } if(lane_idx() == lane_from_task_idx(7)) ProfScope("join typedefs") { for EachIndex(idx, all_syms_count) { - rdim_type_chunk_list_concat_in_place(&all_types__pre_typedefs, &p2r_shared->syms_typedefs[idx]); + rdim_type_chunk_list_concat_in_place(&all_types__pre_typedefs, &syms_typedefs[idx]); } - p2r_shared->all_types = all_types__pre_typedefs; + *all_types = all_types__pre_typedefs; } } lane_sync(); - RDIM_LocationChunkList all_locations = p2r_shared->all_locations; - RDIM_SymbolChunkList all_procedures = p2r_shared->all_procedures; - RDIM_SymbolChunkList all_global_variables = p2r_shared->all_global_variables; - RDIM_SymbolChunkList all_thread_variables = p2r_shared->all_thread_variables; - RDIM_SymbolChunkList all_constants = p2r_shared->all_constants; - RDIM_ScopeChunkList all_scopes = p2r_shared->all_scopes; - RDIM_InlineSiteChunkList all_inline_sites = p2r_shared->all_inline_sites; - RDIM_TypeChunkList all_types = p2r_shared->all_types; ////////////////////////////////////////////////////////////// //- rjf: bundle all outputs @@ -4395,17 +4424,17 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) result.top_level_info = top_level_info; result.binary_sections = binary_sections; result.units = all_units; - result.types = all_types; + result.types = *all_types; result.udts = all_udts; result.src_files = all_src_files; result.line_tables = all_line_tables; - result.locations = all_locations; - result.global_variables = all_global_variables; - result.thread_variables = all_thread_variables; - result.constants = all_constants; - result.procedures = all_procedures; - result.scopes = all_scopes; - result.inline_sites = all_inline_sites; + result.locations = *all_locations; + result.global_variables = *all_global_variables; + result.thread_variables = *all_thread_variables; + result.constants = *all_constants; + result.procedures = *all_procedures; + result.scopes = *all_scopes; + result.inline_sites = *all_inline_sites; } scratch_end(scratch); diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index 7352bba9..2f39dd91 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -87,34 +87,6 @@ struct P2R_TypeIdChain CV_TypeId itype; }; -//- rjf: main state bundle - -typedef struct P2R_Shared P2R_Shared; -struct P2R_Shared -{ - RDIM_UDTChunkList *lanes_udts; - - RDIM_UDTChunkList all_udts; - - RDIM_LocationChunkList *syms_locations; - RDIM_SymbolChunkList *syms_procedures; - RDIM_SymbolChunkList *syms_global_variables; - RDIM_SymbolChunkList *syms_thread_variables; - RDIM_SymbolChunkList *syms_constants; - RDIM_ScopeChunkList *syms_scopes; - RDIM_InlineSiteChunkList *syms_inline_sites; - RDIM_TypeChunkList *syms_typedefs; - - RDIM_LocationChunkList all_locations; - RDIM_SymbolChunkList all_procedures; - RDIM_SymbolChunkList all_global_variables; - RDIM_SymbolChunkList all_thread_variables; - RDIM_SymbolChunkList all_constants; - RDIM_ScopeChunkList all_scopes; - RDIM_InlineSiteChunkList all_inline_sites; - RDIM_TypeChunkList all_types; -}; - //////////////////////////////// //~ rjf: Basic Helpers From d6a7c8bd0029d8d545d735f5161ddb1e4b60eaa0 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 15:21:42 -0700 Subject: [PATCH 115/133] adjust chunk sizes for per-sym-stream symbol chunk lists --- src/rdi_from_pdb/rdi_from_pdb.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 48df49be..9724bebb 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -1109,7 +1109,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) hit_path_node = push_array(scratch2.arena, String8Node, 1); SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); hit_path_node->string = file_path_sanitized; - P2R_SrcFileStubNode *stub_n = push_array(arena, P2R_SrcFileStubNode, 1); + P2R_SrcFileStubNode *stub_n = push_array(scratch2.arena, P2R_SrcFileStubNode, 1); SLLQueuePush(first_src_file_stub, last_src_file_stub, stub_n); src_file_stub_count += 1; stub_n->v.file_path = str8_copy(scratch.arena, file_path_sanitized); @@ -1122,7 +1122,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: merge into array for this unit unit_file_stubs[unit_idx].count = src_file_stub_count; - unit_file_stubs[unit_idx].v = push_array_no_zero(arena, P2R_SrcFileStub, unit_file_stubs[unit_idx].count); + unit_file_stubs[unit_idx].v = push_array_no_zero(scratch.arena, P2R_SrcFileStub, unit_file_stubs[unit_idx].count); { U64 idx = 0; for EachNode(n, P2R_SrcFileStubNode, first_src_file_stub) @@ -1135,7 +1135,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: hash this unit's file paths U64Array hashes = {0}; hashes.count = unit_file_stubs[unit_idx].count; - hashes.v = push_array(arena, U64, hashes.count); + hashes.v = push_array(scratch.arena, U64, hashes.count); for EachIndex(idx, unit_file_stubs[unit_idx].count) { hashes.v[idx] = rdi_hash(unit_file_stubs[unit_idx].v[idx].file_path.str, unit_file_stubs[unit_idx].v[idx].file_path.size); @@ -3378,13 +3378,13 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) Temp scratch = scratch_begin(&arena, 1); CV_SymParsed *sym = all_syms[sym_idx]; Rng1U64 sym_rec_range = r1u64(0, sym->sym_ranges.count); - U64 sym_locations_chunk_cap = 16384; - U64 sym_procedures_chunk_cap = 16384; - U64 sym_global_variables_chunk_cap = 16384; - U64 sym_thread_variables_chunk_cap = 16384; - U64 sym_constants_chunk_cap = 16384; - U64 sym_scopes_chunk_cap = 16384; - U64 sym_inline_sites_chunk_cap = 16384; + U64 sym_locations_chunk_cap = 4096; + U64 sym_procedures_chunk_cap = 2048; + U64 sym_global_variables_chunk_cap = 2048; + U64 sym_thread_variables_chunk_cap = 2048; + U64 sym_constants_chunk_cap = 2048; + U64 sym_scopes_chunk_cap = 4096; + U64 sym_inline_sites_chunk_cap = 2048; RDIM_LocationChunkList *sym_locations = &syms_locations[sym_idx]; RDIM_SymbolChunkList *sym_procedures = &syms_procedures[sym_idx]; RDIM_SymbolChunkList *sym_global_variables = &syms_global_variables[sym_idx]; From d9d321c0741f0349f7919f17a7545115df49695e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 15:34:08 -0700 Subject: [PATCH 116/133] mask off name map builds --- src/lib_rdi_make/rdi_make.h | 1 + src/rdi_from_dwarf/rdi_from_dwarf.c | 2 +- src/rdi_from_pdb/rdi_from_pdb.c | 1 + src/rdi_make/rdi_make_local.c | 16 ++++++++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 034b9599..92664267 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -996,6 +996,7 @@ struct RDIM_ScopeChunkList typedef struct RDIM_BakeParams RDIM_BakeParams; struct RDIM_BakeParams { + RDIM_SubsetFlags subset_flags; RDIM_TopLevelInfo top_level_info; RDIM_BinarySectionList binary_sections; RDIM_UnitChunkList units; diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 8c7b1053..f8a067f0 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -2849,6 +2849,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) lane_sync(); RDIM_BakeParams bake_params = {0}; + bake_params.subset_flags = params->subset_flags; bake_params.top_level_info = top_level_info; bake_params.binary_sections = binary_sections; bake_params.units = units; @@ -2866,4 +2867,3 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) scratch_end(scratch); return bake_params; } - diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 9724bebb..455e4e52 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -4421,6 +4421,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } //- rjf: fill + result.subset_flags = params->subset_flags; result.top_level_info = top_level_info; result.binary_sections = binary_sections; result.units = all_units; diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 3cc1ecb3..ff5cfe42 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -1039,6 +1039,16 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build name maps // + B32 name_maps_need_build[RDI_NameMapKind_COUNT] = {0}; + { + name_maps_need_build[RDI_NameMapKind_GlobalVariables] = !!(params->subset_flags & RDIM_SubsetFlag_GlobalVariableNameMap); + name_maps_need_build[RDI_NameMapKind_ThreadVariables] = !!(params->subset_flags & RDIM_SubsetFlag_ThreadVariableNameMap); + name_maps_need_build[RDI_NameMapKind_Constants] = !!(params->subset_flags & RDIM_SubsetFlag_ConstantNameMap); + name_maps_need_build[RDI_NameMapKind_Procedures] = !!(params->subset_flags & RDIM_SubsetFlag_ProcedureNameMap); + name_maps_need_build[RDI_NameMapKind_Types] = !!(params->subset_flags & RDIM_SubsetFlag_TypeNameMap); + name_maps_need_build[RDI_NameMapKind_LinkNameProcedures] = !!(params->subset_flags & RDIM_SubsetFlag_LinkNameProcedureNameMap); + name_maps_need_build[RDI_NameMapKind_NormalSourcePaths] = !!(params->subset_flags & RDIM_SubsetFlag_NormalSourcePathNameMap); + } RDIM_BakeNameMapTopology *bake_name_maps_tops = 0; RDIM_BakeNameMap **bake_name_maps = 0; ProfScope("build name maps") @@ -1081,6 +1091,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: wide build for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) { + if(!name_maps_need_build[k]) { continue; } RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; lane_maps[k][lane_idx()] = rdim_bake_name_map_make(scratch.arena, top); RDIM_BakeNameMap *map = lane_maps[k][lane_idx()]; @@ -1144,12 +1155,14 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { for EachNonZeroEnumVal(RDI_NameMapKind, k) { + if(!name_maps_need_build[k]) { continue; } bake_name_maps[k] = rdim_bake_name_map_make(arena, &bake_name_maps_tops[k]); } } lane_sync(); for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) { + if(!name_maps_need_build[k]) { continue; } RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; RDIM_BakeNameMap *map = bake_name_maps[k]; @@ -1261,6 +1274,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: bake runs of name map match lists for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) { + if(!name_maps_need_build[k]) { continue; } RDIM_BakeNameMapTopology *name_map_top = &bake_name_maps_tops[k]; RDIM_BakeNameMap *name_map = bake_name_maps[k]; Rng1U64 slot_idx_range = lane_range(name_map_top->slots_count); @@ -1537,6 +1551,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); for EachNonZeroEnumVal(RDI_NameMapKind, k) { + if(!name_maps_need_build[k]) { continue; } RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; RDIM_BakeNameMap *map = bake_name_maps[k]; Rng1U64 range = lane_range(top->slots_count); @@ -1613,6 +1628,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) { for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("wide fill (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) { + if(!name_maps_need_build[k]) { continue; } RDI_U64 write_node_off = rdim_shared->lane_name_map_node_offs[k][lane_idx()]; RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; U64 slots_count = top->slots_count; From 25beda50ca48fa846d243efadbbf3290e8ef5134 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 15:44:04 -0700 Subject: [PATCH 117/133] mask off more work based on subset flags from baker --- src/lib_rdi_make/rdi_make.h | 23 ++++++++++++++++------- src/radbin/radbin.c | 6 ++++++ src/rdi_make/rdi_make_local.c | 6 ++++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 92664267..1aea0530 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -325,19 +325,21 @@ X(Types, types)\ X(UDTs, udts)\ X(LineInfo, line_info)\ X(InlineLineInfo, inline_line_info)\ -X(GlobalVariableNameMap, global_variable_name_map)\ -X(ThreadVariableNameMap, thread_variable_name_map)\ -X(ProcedureNameMap, procedure_name_map)\ -X(ConstantNameMap, constant_name_map)\ -X(TypeNameMap, type_name_map)\ -X(LinkNameProcedureNameMap, link_name_procedure_name_map)\ -X(NormalSourcePathNameMap, normal_source_path_name_map)\ +Y(GlobalVariableNameMap, global_variable_name_map)\ +Y(ThreadVariableNameMap, thread_variable_name_map)\ +Y(ProcedureNameMap, procedure_name_map)\ +Y(ConstantNameMap, constant_name_map)\ +Y(TypeNameMap, type_name_map)\ +Y(LinkNameProcedureNameMap, link_name_procedure_name_map)\ +Y(NormalSourcePathNameMap, normal_source_path_name_map)\ typedef enum RDIM_Subset { #define X(name, name_lower) RDIM_Subset_##name, +#define Y(name, name_lower) RDIM_Subset_##name, RDIM_Subset_XList #undef X +#undef Y } RDIM_Subset; @@ -345,8 +347,15 @@ typedef U32 RDIM_SubsetFlags; enum { #define X(name, name_lower) RDIM_SubsetFlag_##name = (1<string, str8_lit(#name_lower), 0)) { subset_flags |= RDIM_SubsetFlag_##name; } +#define Y(name, name_lower) X(name, name_lower) RDIM_Subset_XList #undef X +#undef Y } String8List omit_names = cmd_line_strings(cmdline, str8_lit("omit")); for(String8Node *n = omit_names.first; n != 0; n = n->next) { if(0){} #define X(name, name_lower) else if(str8_match(n->string, str8_lit(#name_lower), 0)) { subset_flags &= ~RDIM_SubsetFlag_##name; } +#define Y(name, name_lower) X(name, name_lower) RDIM_Subset_XList #undef X +#undef Y } }break; case OutputKind_Breakpad: diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index ff5cfe42..c9b307d8 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -1212,7 +1212,9 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build index runs // - ProfScope("build index runs") + B32 need_index_runs = (!!(params->subset_flags & RDIM_SubsetFlag_NameMaps) || + !!(params->subset_flags & RDIM_SubsetFlag_Types)); + if(need_index_runs) ProfScope("build index runs") { Temp scratch = scratch_begin(&arena, 1); @@ -1501,7 +1503,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake idx runs // - ProfScope("bake idx runs") + if(need_index_runs) ProfScope("bake idx runs") { // rjf: set up if(lane_idx() == 0) From ac9d6e861c6fbd88fcc4907461034f1848e6342d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 16:33:59 -0700 Subject: [PATCH 118/133] first pass at list view, w/ asynchronous offset chain gathering --- src/ctrl/ctrl_core.c | 1 - src/eval/eval_core.h | 1 - src/eval/eval_interpret.c | 8 +- src/eval/eval_interpret.h | 2 - src/eval/eval_types.c | 223 ++++++++++++++++++++++++++++++++++-- src/lib_rdi_make/rdi_make.c | 1 + src/mule/mule_main.cpp | 12 ++ src/raddbg/raddbg_core.c | 3 +- 8 files changed, 229 insertions(+), 22 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 66e3d0c3..7c9a2a78 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -4443,7 +4443,6 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C // { E_InterpretCtx *ctx = &scope->interpret_ctx; - ctx->space_read = ctrl_eval_space_read; ctx->primary_space = eval_modules_primary->space; ctx->reg_arch = eval_modules_primary->arch; ctx->reg_space = e_space_make(CTRL_EvalSpaceKind_Entity); diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index a0a35717..19e35783 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -766,7 +766,6 @@ struct E_BaseCtx E_Module *primary_module; // rjf: space hooks - void *space_rw_user_data; E_SpaceGenFunction *space_gen; E_SpaceRWFunction *space_read; E_SpaceRWFunction *space_write; diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index 74fffeda..53710f16 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -130,9 +130,9 @@ e_space_read(E_Space space, void *out, Rng1U64 range) //- rjf: default -> use hooks default: - if(e_interpret_ctx->space_read != 0) + if(e_base_ctx->space_read != 0) { - result = e_interpret_ctx->space_read(space, out, range); + result = e_base_ctx->space_read(space, out, range); }break; } } @@ -145,13 +145,13 @@ e_space_write(E_Space space, void *in, Rng1U64 range) { ProfBeginFunction(); B32 result = 0; - if(e_interpret_ctx->space_write != 0) + if(e_base_ctx->space_write != 0) { switch(space.kind) { default: { - result = e_interpret_ctx->space_write(space, in, range); + result = e_base_ctx->space_write(space, in, range); }break; } } diff --git a/src/eval/eval_interpret.h b/src/eval/eval_interpret.h index 4151a837..590d4e4e 100644 --- a/src/eval/eval_interpret.h +++ b/src/eval/eval_interpret.h @@ -10,8 +10,6 @@ typedef struct E_InterpretCtx E_InterpretCtx; struct E_InterpretCtx { - E_SpaceRWFunction *space_read; - E_SpaceRWFunction *space_write; E_Space primary_space; Arch reg_arch; E_Space reg_space; diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 23deef63..ffc9c747 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -2573,47 +2573,246 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(array) //////////////////////////////// //~ rjf: (Built-In Type Hooks) `list` lens -typedef struct E_ListGatherArtifact E_ListGatherArtifact; -struct E_ListGatherArtifact -{ - U64 *node_vaddrs; - U64 node_vaddrs_count; -}; - internal AC_Artifact e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) { + Temp scratch = scratch_begin(0, 0); + //- rjf: unpack key + E_Space space = {0}; + U64 base_off = 0; + U64 member_element_off = 0; + U64 member_size = 0; + E_SpaceRWFunction *space_read = 0; + { + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, &space); + key_read_off += str8_deserial_read_struct(key, key_read_off, &base_off); + key_read_off += str8_deserial_read_struct(key, key_read_off, &member_element_off); + key_read_off += str8_deserial_read_struct(key, key_read_off, &member_size); + key_read_off += str8_deserial_read_struct(key, key_read_off, &space_read); + } + + //- rjf: gather chain + typedef struct HitOffsetNode HitOffsetNode; + struct HitOffsetNode + { + HitOffsetNode *next; + U64 off; + }; + typedef struct OffsetChunk OffsetChunk; + struct OffsetChunk + { + OffsetChunk *next; + U64 *v; + U64 count; + U64 cap; + }; + OffsetChunk *first_chunk = 0; + OffsetChunk *last_chunk = 0; + U64 total_count = 0; + { + U64 hit_slots_count = 4096; + HitOffsetNode **hit_slots = push_array(scratch.arena, HitOffsetNode *, hit_slots_count); + for(U64 off = base_off, next_off = 0;; off = next_off) + { + //- rjf: see if we've cycled + B32 hit_cycle = 0; + { + U64 hash = u64_hash_from_str8(str8_struct(&off)); + U64 slot_idx = hash%hit_slots_count; + for(HitOffsetNode *n = hit_slots[slot_idx]; n != 0; n = n->next) + { + if(n->off == off) + { + hit_cycle = 1; + break; + } + } + } + + //- rjf: terminate loop + B32 terminated = (hit_cycle || off == 0); + if(terminated) + { + break; + } + + //- rjf: another node -> push offset to chunk list + OffsetChunk *chunk = last_chunk; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(scratch.arena, OffsetChunk, 1); + SLLQueuePush(first_chunk, last_chunk, chunk); + chunk->cap = 1024; + chunk->v = push_array_no_zero(scratch.arena, U64, chunk->cap); + } + chunk->v[chunk->count] = off; + chunk->count += 1; + total_count += 1; + + //- rjf: read next offset, advance + if(!space_read(space, &next_off, r1u64(off + member_element_off, off + member_element_off + member_size))) + { + break; + } + } + } + + //- rjf: flatten + Arena *arena = 0; + U64 node_offs_count = 0; + U64 *node_offs = 0; + if(total_count != 0) + { + arena = arena_alloc(); + node_offs_count = total_count; + node_offs = push_array_no_zero(arena, U64, node_offs_count); + { + U64 idx = 0; + for EachNode(n, OffsetChunk, first_chunk) + { + MemoryCopy(node_offs + idx, n->v, n->count * sizeof(n->v[0])); + idx += n->count; + } + } + } + + //- rjf: package + AC_Artifact artifact = {0}; + { + artifact.u64[0] = (U64)arena; + artifact.u64[1] = (U64)node_offs; + artifact.u64[2] = node_offs_count; + } + + scratch_end(scratch); + return artifact; } internal void e_list_gather_artifact_destroy(AC_Artifact artifact) { - + Arena *arena = (Arena *)artifact.u64[0]; + if(arena != 0) + { + arena_release(arena); + } } -E_TYPE_EXPAND_INFO_FUNCTION_DEF(list) +typedef struct E_ListIRExt E_ListIRExt; +struct E_ListIRExt { - E_Type *type = e_type_from_key(eval.irtree.type_key); + U64 *offs; + U64 offs_count; +}; + +E_TYPE_IREXT_FUNCTION_DEF(list) +{ + E_IRExt result = {0}; + E_Type *type = e_type_from_key(irtree->type_key); String8 next_link_member_name = str8_lit("next"); if(type->args != 0 && type->count > 0) { next_link_member_name = type->args[0]->string; } - E_TypeKey node_type_key = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_All); + E_TypeKey node_type_key = e_type_key_unwrap(irtree->type_key, E_TypeUnwrapFlag_All); E_Member next_link_member = e_type_member_from_key_name__cached(node_type_key, next_link_member_name); + E_TypeExpandInfo info = {0, 0}; if(next_link_member.kind != E_MemberKind_DataField) { // TODO(rjf): error reporting } else { + Temp scratch = scratch_begin(&arena, 1); + Access *access = access_open(); + // rjf: evaluate first offset + E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree->root); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation base_off_interpret = e_interpret(bytecode); + + // rjf: get artifact +#pragma pack(push, 1) + struct + { + E_Space space; + U64 base_off; + U64 member_element_off; + U64 member_size; + E_SpaceRWFunction *space_read; + } + key_data = + { + base_off_interpret.space, + base_off_interpret.value.u64, + next_link_member.off, + e_type_byte_size_from_key(next_link_member.type_key), + e_base_ctx->space_read, + }; +#pragma pack(pop) + AC_Artifact gather_artifact = ac_artifact_from_key(access, str8_struct(&key_data), e_list_gather_artifact_create, e_list_gather_artifact_destroy, 0); + U64 *offs = (U64 *)gather_artifact.u64[1]; + U64 offs_count = gather_artifact.u64[2]; + + // rjf: fill info from artifact + E_ListIRExt *ext = push_array(arena, E_ListIRExt, 1); + ext->offs = offs; + ext->offs_count = offs_count; + result.user_data = ext; + + access_close(access); + scratch_end(scratch); } - E_TypeExpandInfo info = {0, 0}; + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(list) +{ + E_ListIRExt *ext = (E_ListIRExt *)eval.irtree.user_data; + U64 count = 0; + if(ext != 0) + { + count = ext->offs_count; + } + E_TypeExpandInfo info = {0, count}; return info; } +E_TYPE_ACCESS_FUNCTION_DEF(list) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + E_ListIRExt *ext = (E_ListIRExt *)lhs_irtree->user_data; + if(ext != 0 && expr->kind == E_ExprKind_ArrayIndex) + { + Temp scratch = scratch_begin(&arena, 1); + + // rjf: compute index + E_Expr *rhs_expr = expr->last; + E_IRTreeAndType rhs_irtree = e_push_irtree_and_type_from_expr(scratch.arena, overridden, &e_default_identifier_resolution_rule, 0, 0, rhs_expr); + E_OpList rhs_oplist = e_oplist_from_irtree(scratch.arena, rhs_irtree.root); + String8 rhs_bytecode = e_bytecode_from_oplist(scratch.arena, &rhs_oplist); + E_Interpretation rhs_interpret = e_interpret(rhs_bytecode); + U64 idx = rhs_interpret.value.u64; + + // rjf: get offset + U64 off = 0; + if(idx < ext->offs_count) + { + off = ext->offs[idx]; + } + + // rjf: generate IR tree to compute this offset w/ the node type + result.root = e_irtree_const_u(arena, off); + result.type_key = e_type_key_unwrap(lhs_irtree->type_key, E_TypeUnwrapFlag_AllDecorative); + result.mode = E_Mode_Offset; + + scratch_end(scratch); + } + return result; +} + E_TYPE_EXPAND_RANGE_FUNCTION_DEF(list) { U64 read_range_count = dim_1u64(idx_range); diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index ead2004e..8a506373 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1179,6 +1179,7 @@ rdim_bake_params_concat_in_place(RDIM_BakeParams *dst, RDIM_BakeParams *src) { // rjf: join top-level info (deduplicate - throw away conflicts) { + dst->subset_flags |= src->subset_flags; if(dst->top_level_info.arch == RDI_Arch_NULL) { dst->top_level_info.arch = src->top_level_info.arch; diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index 19f70cb2..c363a09e 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -569,6 +569,18 @@ type_coverage_eval_tests(void) Linked_List list = {&list, &list, 0}; + struct SLLNode + { + SLLNode *next; + int x; + }; + SLLNode node6 = {0, 6}; + SLLNode node5 = {&node6, 5}; + SLLNode node4 = {&node5, 4}; + SLLNode node3 = {&node4, 3}; + SLLNode node2 = {&node3, 2}; + SLLNode node1 = {&node2, 1}; + Alias1 a1 = has_enums.kind; Alias2 a2 = has_enums.flags; Alias3 a3 = has_enums; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index a5ab4c9b..d7d09916 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -12511,6 +12511,7 @@ rd_frame(void) {str8_lit("range1"), 0, 0, 0, 0, 0, {0}}, {str8_lit("array"), 0, 0, 1, 0, 0, {E_TYPE_EXPAND_INFO_FUNCTION_NAME(array), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(array)}}, {str8_lit("slice"), 0, 0, 1, E_TYPE_IREXT_FUNCTION_NAME(slice), E_TYPE_ACCESS_FUNCTION_NAME(slice), {E_TYPE_EXPAND_INFO_FUNCTION_NAME(slice), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(slice)}}, + {str8_lit("list"), 0, 0, 1, E_TYPE_IREXT_FUNCTION_NAME(list), E_TYPE_ACCESS_FUNCTION_NAME(list), {E_TYPE_EXPAND_INFO_FUNCTION_NAME(list), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(list)}}, {str8_lit("text"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(text), EV_EXPAND_RULE_INFO_FUNCTION_NAME(text)}, {str8_lit("disasm"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(disasm), EV_EXPAND_RULE_INFO_FUNCTION_NAME(disasm)}, {str8_lit("memory"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(memory), EV_EXPAND_RULE_INFO_FUNCTION_NAME(memory)}, @@ -12685,8 +12686,6 @@ rd_frame(void) E_InterpretCtx *interpret_ctx = push_array(scratch.arena, E_InterpretCtx, 1); { E_InterpretCtx *ctx = interpret_ctx; - ctx->space_read = rd_eval_space_read; - ctx->space_write = rd_eval_space_write; ctx->primary_space = eval_modules_primary->space; ctx->reg_arch = eval_modules_primary->arch; ctx->reg_space = rd_eval_space_from_ctrl_entity(thread, CTRL_EvalSpaceKind_Entity); From 410837d26db7500ddb28f7d80360507df54596d1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 16:44:30 -0700 Subject: [PATCH 119/133] key list gather artifact lookups by space gen --- src/eval/eval_types.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index ffc9c747..208686e5 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -2752,7 +2752,7 @@ E_TYPE_IREXT_FUNCTION_DEF(list) e_base_ctx->space_read, }; #pragma pack(pop) - AC_Artifact gather_artifact = ac_artifact_from_key(access, str8_struct(&key_data), e_list_gather_artifact_create, e_list_gather_artifact_destroy, 0); + AC_Artifact gather_artifact = ac_artifact_from_key(access, str8_struct(&key_data), e_list_gather_artifact_create, e_list_gather_artifact_destroy, 0, .gen = e_space_gen(base_off_interpret.space)); U64 *offs = (U64 *)gather_artifact.u64[1]; U64 offs_count = gather_artifact.u64[2]; From 891eaec5cb73988e40b5449ef26398b6479f638b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 15 Oct 2025 17:56:10 -0700 Subject: [PATCH 120/133] bucket active conversion tasks by priority; adjust thread cap for bg conversion processes, don't flood cores with work while target is doing things --- src/config/config.c | 62 +++++ src/config/config.h | 178 +++++++++++++++ src/dbg_info/dbg_info.c | 482 ++++++++++++++++++++------------------- src/dbg_info/dbg_info.h | 4 +- src/raddbg/raddbg_main.c | 8 +- 5 files changed, 492 insertions(+), 242 deletions(-) create mode 100644 src/config/config.c create mode 100644 src/config/config.h diff --git a/src/config/config.c b/src/config/config.c new file mode 100644 index 00000000..e374ac97 --- /dev/null +++ b/src/config/config.c @@ -0,0 +1,62 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: ID Functions + +internal void cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id); +internal CFG_IDList cfg_id_list_copy(Arena *arena, CFG_IDList *src); + +//////////////////////////////// +//~ rjf: Node Pointer Data Structure Functions + +internal void cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node); +internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node); +#define cfg_node_ptr_list_first(list) ((list)->count ? (list)->first->v : &cfg_nil_node) +#define cfg_node_ptr_list_last(list) ((list)->count ? (list)->last->v : &cfg_nil_node) +internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list); + +//////////////////////////////// +//~ rjf: Config Reading Functions + +//- rjf: context selection +internal void cfg_ctx_select(CFG_Ctx *ctx); + +//- rjf: tree navigations +internal CFG_Node *cfg_node_from_id(CFG_ID id); +internal CFG_Node *cfg_node_child_from_string(CFG_Node *parent, String8 string); +internal CFG_Node *cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string); +internal CFG_NodePtrList cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string); +internal CFG_NodePtrList cfg_node_top_level_list_from_string(Arena *arena, String8 string); +internal CFG_NodeRec cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node); + +//- rjf: serialization +internal String8 cfg_string_from_tree(Arena *arena, String8 root_path, CFG_Node *root); + +//////////////////////////////// +//~ rjf: Config Writing Functions + +//- rjf: state creation / destroying +internal CFG_State *cfg_state_alloc(void); +internal void cfg_state_release(CFG_State *state); + +//- rjf: state -> ctx +internal CFG_Ctx *cfg_state_ctx(CFG_State *state); + +//- rjf: tree building +internal CFG_Node *cfg_node_alloc(CFG_State *state); +internal void cfg_node_release(CFG_State *state, CFG_Node *node); +internal void cfg_node_release_all_children(CFG_State *state, CFG_Node *node); +internal CFG_Node *cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string); +internal CFG_Node *cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...); +internal CFG_Node *cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string); +internal CFG_Node *cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...); +internal CFG_Node *cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root); +internal void cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string); +internal void cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...); +internal void cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child); +internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child); +internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string); + +//- rjf: deserialization +internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, String8 root_path, String8 string); diff --git a/src/config/config.h b/src/config/config.h new file mode 100644 index 00000000..e0b12ed0 --- /dev/null +++ b/src/config/config.h @@ -0,0 +1,178 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CONFIG_H +#define CONFIG_H + +//////////////////////////////// +//~ rjf: IDs + +typedef U64 CFG_ID; + +typedef struct CFG_IDNode CFG_IDNode; +struct CFG_IDNode +{ + CFG_IDNode *next; + CFG_ID v; +}; + +typedef struct CFG_IDList CFG_IDList; +struct CFG_IDList +{ + CFG_IDNode *first; + CFG_IDNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Tree Types + +typedef struct CFG_Node CFG_Node; +struct CFG_Node +{ + CFG_Node *first; + CFG_Node *last; + CFG_Node *next; + CFG_Node *prev; + CFG_Node *parent; + CFG_ID id; + String8 string; +}; + +typedef struct CFG_NodePtrNode CFG_NodePtrNode; +struct CFG_NodePtrNode +{ + CFG_NodePtrNode *next; + CFG_NodePtrNode *prev; + CFG_Node *v; +}; + +typedef struct CFG_NodePtrSlot CFG_NodePtrSlot; +struct CFG_NodePtrSlot +{ + CFG_NodePtrNode *first; + CFG_NodePtrNode *last; +}; + +typedef struct CFG_NodePtrList CFG_NodePtrList; +struct CFG_NodePtrList +{ + CFG_NodePtrNode *first; + CFG_NodePtrNode *last; + U64 count; +}; + +typedef struct CFG_NodePtrArray CFG_NodePtrArray; +struct CFG_NodePtrArray +{ + CFG_Node **v; + U64 count; +}; + +typedef struct CFG_NodeRec CFG_NodeRec; +struct CFG_NodeRec +{ + CFG_Node *next; + S32 push_count; + S32 pop_count; +}; + +//////////////////////////////// +//~ rjf: Config State Bundles + +typedef struct CFG_Ctx CFG_Ctx; +struct CFG_Ctx +{ + CFG_Node *root; + U64 id_slots_count; + CFG_NodePtrSlot *id_slots; + U64 change_gen; + CFG_ID last_accessed_id; + CFG_Node *last_accessed; +}; + +typedef struct CFG_State CFG_State; +struct CFG_State +{ + Arena *arena; + CFG_Node *free; + CFG_NodePtrNode *free_id_node; + U64 id_gen; + CFG_Ctx ctx; +}; + +//////////////////////////////// +//~ rjf: Globals + +read_only global CFG_Node cfg_nil_node = +{ + &cfg_nil_node, + &cfg_nil_node, + &cfg_nil_node, + &cfg_nil_node, + &cfg_nil_node, +}; + +thread_static CFG_Ctx *cfg_ctx = 0; + +//////////////////////////////// +//~ rjf: ID Functions + +internal void cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id); +internal CFG_IDList cfg_id_list_copy(Arena *arena, CFG_IDList *src); + +//////////////////////////////// +//~ rjf: Node Pointer Data Structure Functions + +internal void cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node); +internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node); +#define cfg_node_ptr_list_first(list) ((list)->count ? (list)->first->v : &cfg_nil_node) +#define cfg_node_ptr_list_last(list) ((list)->count ? (list)->last->v : &cfg_nil_node) +internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list); + +//////////////////////////////// +//~ rjf: Config Reading Functions + +//- rjf: context selection +internal void cfg_ctx_select(CFG_Ctx *ctx); + +//- rjf: tree navigations +internal CFG_Node *cfg_node_from_id(CFG_ID id); +internal CFG_Node *cfg_node_child_from_string(CFG_Node *parent, String8 string); +internal CFG_Node *cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string); +internal CFG_NodePtrList cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string); +internal CFG_NodePtrList cfg_node_top_level_list_from_string(Arena *arena, String8 string); +internal CFG_NodeRec cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node); + +//- rjf: serialization +internal String8 cfg_string_from_tree(Arena *arena, String8 root_path, CFG_Node *root); + +//////////////////////////////// +//~ rjf: Config Writing Functions + +//- rjf: state creation / destroying +internal CFG_State *cfg_state_alloc(void); +internal void cfg_state_release(CFG_State *state); + +//- rjf: state -> ctx +internal CFG_Ctx *cfg_state_ctx(CFG_State *state); + +//- rjf: tree building +internal CFG_Node *cfg_node_alloc(CFG_State *state); +internal void cfg_node_release(CFG_State *state, CFG_Node *node); +internal void cfg_node_release_all_children(CFG_State *state, CFG_Node *node); +internal CFG_Node *cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string); +internal CFG_Node *cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...); +internal CFG_Node *cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string); +internal CFG_Node *cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...); +internal CFG_Node *cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root); +internal void cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string); +internal void cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...); +internal void cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child); +internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child); +internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string); + +//- rjf: deserialization +internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, String8 root_path, String8 string); + +#endif // CONFIG_H diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index aaa6f86f..35130803 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -553,8 +553,8 @@ di_async_tick(void) //////////////////////////// //- rjf: pop all requests, high priority first // - DI_RequestNode *first_req = 0; - DI_RequestNode *last_req = 0; + DI_RequestNode *first_req[2] = {0}; + DI_RequestNode *last_req[2] = {0}; for EachElement(idx, di_shared->req_batches) { DI_RequestBatch *b = &di_shared->req_batches[idx]; @@ -564,7 +564,7 @@ di_async_tick(void) { DI_RequestNode *n_copy = push_array(scratch.arena, DI_RequestNode, 1); MemoryCopyStruct(&n_copy->v, &n->v); - SLLQueuePush(first_req, last_req, n_copy); + SLLQueuePush(first_req[idx], last_req[idx], n_copy); } arena_clear(b->arena); b->first = b->last = 0; @@ -591,261 +591,271 @@ di_async_tick(void) //////////////////////////// //- rjf: generate load tasks for all unique requests - // - for EachNode(n, DI_RequestNode, first_req) - { - // rjf: unpack request - DI_Key key = n->v.key; - - // rjf: determine if this request is a duplicate - B32 request_is_duplicate = 1; + // + for EachElement(priority_idx, first_req) + { + for EachNode(n, DI_RequestNode, first_req[priority_idx]) { - U64 hash = u64_hash_from_str8(str8_struct(&key)); - U64 slot_idx = hash%di_shared->slots_count; - DI_Slot *slot = &di_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di_shared->stripes, slot_idx); - RWMutexScope(stripe->rw_mutex, 0) + // rjf: unpack request + DI_Key key = n->v.key; + + // rjf: determine if this request is a duplicate + B32 request_is_duplicate = 1; { - for(DI_Node *n = slot->first; n != 0; n = n->next) + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di_shared->slots_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 0) { - if(di_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) == 0) + for(DI_Node *n = slot->first; n != 0; n = n->next) { - request_is_duplicate = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) != 0); - break; + if(di_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) == 0) + { + request_is_duplicate = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) != 0); + break; + } } } } - } - - // rjf: if not a duplicate, create new task - if(!request_is_duplicate) - { - DI_LoadTask *t = di_shared->free_load_task; - if(t) + + // rjf: if not a duplicate, create new task + if(!request_is_duplicate) { - SLLStackPop(di_shared->free_load_task); + DI_LoadTask *t = di_shared->free_load_task; + if(t) + { + SLLStackPop(di_shared->free_load_task); + } + else + { + t = push_array_no_zero(di_shared->arena, DI_LoadTask, 1); + } + MemoryZeroStruct(t); + DLLPushBack(di_shared->first_load_task[priority_idx], di_shared->last_load_task[priority_idx], t); + t->key = key; } - else - { - t = push_array_no_zero(di_shared->arena, DI_LoadTask, 1); - } - MemoryZeroStruct(t); - DLLPushBack(di_shared->first_load_task, di_shared->last_load_task, t); - t->key = key; - } - } + } + } //////////////////////////// //- rjf: update tasks: configure, launch if we can, & retire if we can - // - for(DI_LoadTask *t = di_shared->first_load_task, *next = 0; t != 0; t = next) - { - next = t->next; - - //- rjf: unpack key - DI_Key key = t->key; - U64 key_hash = u64_hash_from_str8(str8_struct(&key)); - U64 key_slot_idx = key_hash%di_shared->key2path_slots_count; - DI_KeySlot *key_slot = &di_shared->key2path_slots[key_slot_idx]; - Stripe *key_stripe = stripe_from_slot_idx(&di_shared->key2path_stripes, key_slot_idx); - - //- rjf: get key's O.G. path - String8 og_path = {0}; - U64 og_min_timestamp = 0; - RWMutexScope(key_stripe->rw_mutex, 0) + // + for EachElement(priority_idx, di_shared->first_load_task) + { + for(DI_LoadTask *t = di_shared->first_load_task[priority_idx], *next = 0; t != 0; t = next) { - for(DI_KeyPathNode *n = key_slot->first; n != 0; n = n->next) + next = t->next; + + //- rjf: unpack key + DI_Key key = t->key; + U64 key_hash = u64_hash_from_str8(str8_struct(&key)); + U64 key_slot_idx = key_hash%di_shared->key2path_slots_count; + DI_KeySlot *key_slot = &di_shared->key2path_slots[key_slot_idx]; + Stripe *key_stripe = stripe_from_slot_idx(&di_shared->key2path_stripes, key_slot_idx); + + //- rjf: get key's O.G. path + String8 og_path = {0}; + U64 og_min_timestamp = 0; + RWMutexScope(key_stripe->rw_mutex, 0) { - if(di_key_match(n->key, key)) + for(DI_KeyPathNode *n = key_slot->first; n != 0; n = n->next) { - og_path = str8_copy(scratch.arena, n->path); - og_min_timestamp = n->min_timestamp; - break; - } - } - } - - //- rjf: analyze O.G. debug info - if(!t->og_analyzed) - { - t->og_analyzed = 1; - OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, og_path); - FileProperties props = os_properties_from_file(file); - t->og_size = props.size; - U64 rdi_magic_maybe = 0; - if(os_file_read_struct(file, 0, &rdi_magic_maybe) == 8 && - rdi_magic_maybe == RDI_MAGIC_CONSTANT) - { - t->og_is_rdi = 1; - } - os_file_close(file); - } - U64 og_size = t->og_size; - B32 og_is_rdi = t->og_is_rdi; - - //- rjf: compute key's RDI path - String8 rdi_path = {0}; - { - if(og_is_rdi) - { - rdi_path = og_path; - } - else - { - rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); - } - } - - //- rjf: determine if RDI is stale - if(!t->rdi_analyzed) - { - t->rdi_analyzed = 1; - OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, rdi_path); - FileProperties props = os_properties_from_file(file); - if(props.modified < og_min_timestamp) - { - t->rdi_is_stale = 1; - } - else - { - t->rdi_is_stale = 1; - RDI_Header header = {0}; - if(os_file_read_struct(file, 0, &header) == sizeof(header)) - { - t->rdi_is_stale = (header.encoding_version != RDI_ENCODING_VERSION); - } - } - os_file_close(file); - } - B32 rdi_is_stale = t->rdi_is_stale; - - //- rjf: calculate thread counts for conversion processes - if(!og_is_rdi && rdi_is_stale && t->thread_count == 0) - { - U64 thread_count = 1; - U64 max_thread_count = os_get_system_info()->logical_processor_count; - { - if(0){} - else if(og_size <= MB(4)) {thread_count = 1;} - else if(og_size <= MB(256)) {thread_count = max_thread_count/4;} - else if(og_size <= MB(512)) {thread_count = max_thread_count/3;} - else if(og_size <= GB(1)) {thread_count = max_thread_count/2;} - else {thread_count = max_thread_count;} - } - thread_count = Max(1, thread_count); - t->thread_count = thread_count; - } - - //- rjf: determine if there are threads available - B32 threads_available = 0; - { - U64 max_threads = os_get_system_info()->logical_processor_count*2; - U64 current_threads = di_shared->conversion_thread_count; - U64 needed_threads = (current_threads + t->thread_count); - threads_available = (max_threads >= needed_threads); - } - - //- rjf: launch conversion processes - if(threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI_LoadTaskStatus_Active) - { - B32 should_compress = 0; - OS_ProcessLaunchParams params = {0}; - params.path = os_get_process_info()->binary_path; - params.inherit_env = 1; - params.consoleless = 1; - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "raddbg"); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--bin"); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--quiet"); - if(should_compress) - { - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--compress"); - } - // str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--capture"); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--rdi"); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--out:%S", rdi_path); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--thread_count:%I64u", t->thread_count); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_pid:%I64u", (U64)os_get_process_info()->pid); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_code:%I64u", (U64)t); - str8_list_pushf(scratch.arena, ¶ms.cmd_line, "%S", og_path); - ProfMsg("launch creation for %.*s", str8_varg(rdi_path)); - t->process = os_process_launch(¶ms); - t->status = DI_LoadTaskStatus_Active; - di_shared->conversion_process_count += 1; - di_shared->conversion_thread_count += t->thread_count; - - // rjf: send event - MutexScope(di_shared->event_mutex) - { - DI_EventNode *n = push_array(di_shared->event_arena, DI_EventNode, 1); - SLLQueuePush(di_shared->events.first, di_shared->events.last, n); - di_shared->events.count += 1; - n->v.kind = DI_EventKind_ConversionStarted; - n->v.string = str8_copy(di_shared->event_arena, rdi_path); - } - } - - //- rjf: if active & process has completed, mark as done - { - U64 exit_code = 0; - if(t->status == DI_LoadTaskStatus_Active) - { - B32 task_is_done = 0; - for(DI_LoadCompletion *c = first_completion; c != 0; c = c->next) - { - if(c->code == (U64)t) + if(di_key_match(n->key, key)) { - task_is_done = 1; + og_path = str8_copy(scratch.arena, n->path); + og_min_timestamp = n->min_timestamp; break; } } - if(!task_is_done) - { - task_is_done = os_process_join(t->process, 0, 0); - } - if(task_is_done) - { - t->status = DI_LoadTaskStatus_Done; - di_shared->conversion_process_count -= 1; - di_shared->conversion_thread_count -= t->thread_count; - } } - } - - //- rjf: if the RDI for this task is not stale, then we're already done - mark this - // task as done & prepped for storing into the cache - if(!rdi_is_stale) - { - t->status = DI_LoadTaskStatus_Done; - } - - //- rjf: if the RDI for this task *is* stale, but the O.G. path is actually RDI, - // then we can't actually re-convert to produce a non-stale RDI. in this case, just - // mark as done. - if(rdi_is_stale && og_is_rdi) - { - t->status = DI_LoadTaskStatus_Done; - } - - //- rjf: if task is done, retire & recycle task; gather path to load - if(t->status == DI_LoadTaskStatus_Done) - { - if(!os_handle_match(t->process, os_handle_zero())) MutexScope(di_shared->event_mutex) + + //- rjf: analyze O.G. debug info + if(!t->og_analyzed) { - DI_EventNode *n = push_array(di_shared->event_arena, DI_EventNode, 1); - SLLQueuePush(di_shared->events.first, di_shared->events.last, n); - di_shared->events.count += 1; - n->v.kind = DI_EventKind_ConversionEnded; - n->v.string = str8_copy(di_shared->event_arena, rdi_path); + t->og_analyzed = 1; + OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, og_path); + FileProperties props = os_properties_from_file(file); + t->og_size = props.size; + U64 rdi_magic_maybe = 0; + if(os_file_read_struct(file, 0, &rdi_magic_maybe) == 8 && + rdi_magic_maybe == RDI_MAGIC_CONSTANT) + { + t->og_is_rdi = 1; + } + os_file_close(file); } - DLLRemove(di_shared->first_load_task, di_shared->last_load_task, t); - SLLStackPush(di_shared->free_load_task, t); - ParseTaskNode *n = push_array(scratch.arena, ParseTaskNode, 1); - n->v.key = key; - n->v.rdi_path = rdi_path; - SLLQueuePush(first_parse_task, last_parse_task, n); - parse_tasks_count += 1; - } - } + U64 og_size = t->og_size; + B32 og_is_rdi = t->og_is_rdi; + + //- rjf: compute key's RDI path + String8 rdi_path = {0}; + { + if(og_is_rdi) + { + rdi_path = og_path; + } + else + { + rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); + } + } + + //- rjf: determine if RDI is stale + if(!t->rdi_analyzed) + { + t->rdi_analyzed = 1; + OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, rdi_path); + FileProperties props = os_properties_from_file(file); + if(props.modified < og_min_timestamp) + { + t->rdi_is_stale = 1; + } + else + { + t->rdi_is_stale = 1; + RDI_Header header = {0}; + if(os_file_read_struct(file, 0, &header) == sizeof(header)) + { + t->rdi_is_stale = (header.encoding_version != RDI_ENCODING_VERSION); + } + } + os_file_close(file); + } + B32 rdi_is_stale = t->rdi_is_stale; + + //- rjf: calculate thread counts for conversion processes + if(!og_is_rdi && rdi_is_stale && t->thread_count == 0) + { + U64 thread_count = 1; + U64 max_thread_count = os_get_system_info()->logical_processor_count; + if(priority_idx > 0) + { + max_thread_count = Max(1, max_thread_count/2); + } + { + if(0){} + else if(og_size <= MB(4)) {thread_count = 1;} + else if(og_size <= MB(256)) {thread_count = max_thread_count/4;} + else if(og_size <= MB(512)) {thread_count = max_thread_count/3;} + else if(og_size <= GB(1)) {thread_count = max_thread_count/2;} + else {thread_count = max_thread_count;} + } + thread_count = Max(1, thread_count); + t->thread_count = thread_count; + } + + //- rjf: determine if there are threads available + B32 threads_available = 0; + { + U64 max_threads = os_get_system_info()->logical_processor_count; + U64 current_threads = di_shared->conversion_thread_count; + U64 needed_threads = (current_threads + t->thread_count); + threads_available = (max_threads >= needed_threads); + } + + //- rjf: launch conversion processes + if(threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI_LoadTaskStatus_Active) + { + B32 should_compress = 0; + OS_ProcessLaunchParams params = {0}; + params.path = os_get_process_info()->binary_path; + params.inherit_env = 1; + params.consoleless = 1; + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "raddbg"); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--bin"); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--quiet"); + if(should_compress) + { + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--compress"); + } + // str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--capture"); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--rdi"); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--out:%S", rdi_path); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--thread_count:%I64u", t->thread_count); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_pid:%I64u", (U64)os_get_process_info()->pid); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_code:%I64u", (U64)t); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "%S", og_path); + ProfMsg("launch creation for %.*s", str8_varg(rdi_path)); + t->process = os_process_launch(¶ms); + t->status = DI_LoadTaskStatus_Active; + di_shared->conversion_process_count += 1; + di_shared->conversion_thread_count += t->thread_count; + + // rjf: send event + MutexScope(di_shared->event_mutex) + { + DI_EventNode *n = push_array(di_shared->event_arena, DI_EventNode, 1); + SLLQueuePush(di_shared->events.first, di_shared->events.last, n); + di_shared->events.count += 1; + n->v.kind = DI_EventKind_ConversionStarted; + n->v.string = str8_copy(di_shared->event_arena, rdi_path); + } + } + + //- rjf: if active & process has completed, mark as done + { + U64 exit_code = 0; + if(t->status == DI_LoadTaskStatus_Active) + { + B32 task_is_done = 0; + for(DI_LoadCompletion *c = first_completion; c != 0; c = c->next) + { + if(c->code == (U64)t) + { + task_is_done = 1; + break; + } + } + if(!task_is_done) + { + task_is_done = os_process_join(t->process, 0, 0); + } + if(task_is_done) + { + t->status = DI_LoadTaskStatus_Done; + di_shared->conversion_process_count -= 1; + di_shared->conversion_thread_count -= t->thread_count; + } + } + } + + //- rjf: if the RDI for this task is not stale, then we're already done - mark this + // task as done & prepped for storing into the cache + if(!rdi_is_stale) + { + t->status = DI_LoadTaskStatus_Done; + } + + //- rjf: if the RDI for this task *is* stale, but the O.G. path is actually RDI, + // then we can't actually re-convert to produce a non-stale RDI. in this case, just + // mark as done. + if(rdi_is_stale && og_is_rdi) + { + t->status = DI_LoadTaskStatus_Done; + } + + //- rjf: if task is done, retire & recycle task; gather path to load + if(t->status == DI_LoadTaskStatus_Done) + { + if(!os_handle_match(t->process, os_handle_zero())) MutexScope(di_shared->event_mutex) + { + DI_EventNode *n = push_array(di_shared->event_arena, DI_EventNode, 1); + SLLQueuePush(di_shared->events.first, di_shared->events.last, n); + di_shared->events.count += 1; + n->v.kind = DI_EventKind_ConversionEnded; + n->v.string = str8_copy(di_shared->event_arena, rdi_path); + } + DLLRemove(di_shared->first_load_task[priority_idx], di_shared->last_load_task[priority_idx], t); + SLLStackPush(di_shared->free_load_task, t); + ParseTaskNode *n = push_array(scratch.arena, ParseTaskNode, 1); + n->v.key = key; + n->v.rdi_path = rdi_path; + SLLQueuePush(first_parse_task, last_parse_task, n); + parse_tasks_count += 1; + } + } + } //////////////////////////// //- rjf: join all parse tasks diff --git a/src/dbg_info/dbg_info.h b/src/dbg_info/dbg_info.h index 0002088a..8280a8a0 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -267,8 +267,8 @@ struct DI_Shared DI_RequestBatch req_batches[2]; // [0] -> high priority, [1] -> low priority // rjf: conversion tasks - DI_LoadTask *first_load_task; - DI_LoadTask *last_load_task; + DI_LoadTask *first_load_task[2]; + DI_LoadTask *last_load_task[2]; DI_LoadTask *free_load_task; U64 conversion_process_count; U64 conversion_thread_count; diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 3861c3f4..7099d25f 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -148,13 +148,13 @@ // [ ] step-out-of-loop // //- late-conversion performance improvements -// [ ] investigate wide-conversion performance -// [ ] oversubscribing cores? -// [ ] conversion crashes? +// [x] investigate wide-conversion performance +// [x] oversubscribing cores? +// [x] conversion crashes? // [ ] live++ investigations - ctrl+alt+f11 in UE? // //- memory usage improvements -// [ ] "root" concept in hash store, which buckets keys & allows usage code to +// [x] "root" concept in hash store, which buckets keys & allows usage code to // jettison a collection of keys in retained mode fashion // //- short-to-medium term future features From a2522c00fabd662da588d7995970698cbb37c0d9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 10:33:53 -0700 Subject: [PATCH 121/133] tweak debug info conversion balancing - we want to give a bit more to debuggees... --- src/dbg_info/dbg_info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 35130803..994fcb39 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -728,7 +728,7 @@ di_async_tick(void) if(!og_is_rdi && rdi_is_stale && t->thread_count == 0) { U64 thread_count = 1; - U64 max_thread_count = os_get_system_info()->logical_processor_count; + U64 max_thread_count = os_get_system_info()->logical_processor_count/2; if(priority_idx > 0) { max_thread_count = Max(1, max_thread_count/2); @@ -748,7 +748,7 @@ di_async_tick(void) //- rjf: determine if there are threads available B32 threads_available = 0; { - U64 max_threads = os_get_system_info()->logical_processor_count; + U64 max_threads = os_get_system_info()->logical_processor_count/2; U64 current_threads = di_shared->conversion_thread_count; U64 needed_threads = (current_threads + t->thread_count); threads_available = (max_threads >= needed_threads); From 8dbfa97c71c0571071ab5668f7cc3f23c8894819 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 11:10:00 -0700 Subject: [PATCH 122/133] adjust list lens member picking rules - use default argument, then fall back to `next`, `prev`, or the first pointer to an identical type --- CHANGELOG.md | 12 ++++++++++ src/ctrl/ctrl_core.c | 16 +++++++++++++ src/ctrl/ctrl_core.h | 3 ++- src/eval/eval_ir.c | 7 +----- src/eval/eval_types.c | 52 ++++++++++++++++++++++++++++++++++++---- src/mule/mule_main.cpp | 14 ++++++----- src/raddbg/raddbg_core.c | 4 ++++ 7 files changed, 90 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c21e4e0..92924ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# v0.9.23-alpha + +## Debugger Changes + +- Further improved PDB -> RDI conversion performance & memory usage. +- Adjusted limits for the amount of PDB -> RDI conversion work that the + debugger will kick off, to prevent PDB -> RDI conversion interfering with + debuggee performance. +- Reintroduced the `list` lens, which gathers all nodes in a linked list, and + visualizes them as a flat list of pointers (the same as how an array of + pointers is visualized). + # v0.9.22-alpha ## Debugger Changes diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 7c9a2a78..3bd826ce 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -4200,6 +4200,21 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, //- rjf: eval helpers +internal U64 +ctrl_eval_space_gen(E_Space space) +{ + U64 result = 0; + switch(space.kind) + { + default:{}break; + case CTRL_EvalSpaceKind_Entity: + { + result = ctrl_mem_gen(); + }break; + } + return result; +} + internal B32 ctrl_eval_space_read(E_Space space, void *out, Rng1U64 range) { @@ -4418,6 +4433,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C ctx->primary_module = eval_modules_primary; //- rjf: fill space hooks + ctx->space_gen = ctrl_eval_space_gen; ctx->space_read = ctrl_eval_space_read; } e_select_base_ctx(&scope->base_ctx); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 9879a71a..f7304452 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -980,7 +980,8 @@ internal void ctrl_thread__module_close(CTRL_Handle process, CTRL_Handle module, //- rjf: attached process running/event gathering internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); -//- rjf: eval helpers +//- rjf: eval helpers +internal U64 ctrl_eval_space_gen(E_Space space); internal B32 ctrl_eval_space_read(E_Space space, void *out, Rng1U64 vaddr_range); //- rjf: control thread eval scopes diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 5575990d..cdf5a029 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -2422,12 +2422,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } if(irext != 0 && result.user_data == 0) { - E_IRTreeAndType irtree_stripped = result; - if(type->kind == E_TypeKind_Lens) - { - irtree_stripped.type_key = e_type_key_direct(irtree_stripped.type_key); - } - E_IRExt ext = irext(arena, expr, &irtree_stripped); + E_IRExt ext = irext(arena, expr, &result); result.user_data = ext.user_data; } } diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 208686e5..1d29a8d9 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -2711,13 +2711,54 @@ E_TYPE_IREXT_FUNCTION_DEF(list) { E_IRExt result = {0}; E_Type *type = e_type_from_key(irtree->type_key); - String8 next_link_member_name = str8_lit("next"); - if(type->args != 0 && type->count > 0) + + //- rjf: get member encoding the link to the next node + E_Member next_link_member = {0}; { - next_link_member_name = type->args[0]->string; + E_TypeKey node_type_key = e_type_key_unwrap(irtree->type_key, E_TypeUnwrapFlag_All); + + // rjf: try explicitly-passed name + if(next_link_member.kind == E_MemberKind_Null && type->args != 0 && type->count > 0 && type->args[0]->kind == E_ExprKind_LeafIdentifier) + { + String8 name = type->args[0]->string; + next_link_member = e_type_member_from_key_name__cached(node_type_key, name); + } + + // rjf: try `next` + if(next_link_member.kind == E_MemberKind_Null) + { + next_link_member = e_type_member_from_key_name__cached(node_type_key, str8_lit("next")); + } + + // rjf: try `prev` + if(next_link_member.kind == E_MemberKind_Null) + { + next_link_member = e_type_member_from_key_name__cached(node_type_key, str8_lit("prev")); + } + + // rjf: try any pointer to the same type + if(next_link_member.kind == E_MemberKind_Null) + { + E_Type *node_type = e_type_from_key(node_type_key); + if(node_type->members != 0) + { + for EachIndex(idx, node_type->count) + { + E_TypeKey member_type_key = node_type->members[idx].type_key; + E_TypeKey member_type_key_undecorated = e_type_key_unwrap(member_type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKey member_ptee_type_key = e_type_key_unwrap(member_type_key_undecorated, E_TypeUnwrapFlag_All); + if(e_type_kind_from_key(member_type_key_undecorated) == E_TypeKind_Ptr && + e_type_key_match(member_ptee_type_key, node_type_key)) + { + next_link_member = node_type->members[idx]; + break; + } + } + } + } } - E_TypeKey node_type_key = e_type_key_unwrap(irtree->type_key, E_TypeUnwrapFlag_All); - E_Member next_link_member = e_type_member_from_key_name__cached(node_type_key, next_link_member_name); + + //- rjf: generate expansion info E_TypeExpandInfo info = {0, 0}; if(next_link_member.kind != E_MemberKind_DataField) { @@ -2765,6 +2806,7 @@ E_TYPE_IREXT_FUNCTION_DEF(list) access_close(access); scratch_end(scratch); } + return result; } diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index c363a09e..28bb2355 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -572,14 +572,16 @@ type_coverage_eval_tests(void) struct SLLNode { SLLNode *next; + SLLNode *the_real_next_ptr; int x; }; - SLLNode node6 = {0, 6}; - SLLNode node5 = {&node6, 5}; - SLLNode node4 = {&node5, 4}; - SLLNode node3 = {&node4, 3}; - SLLNode node2 = {&node3, 2}; - SLLNode node1 = {&node2, 1}; + SLLNode node6 = {0, 0, 6}; + SLLNode node5 = {0, &node6, 5}; + SLLNode node4 = {0, &node5, 4}; + SLLNode node3 = {0, &node4, 3}; + SLLNode node2 = {0, &node3, 2}; + SLLNode node1 = {0, &node2, 1}; + raddbg_pin(list(node1, the_real_next_ptr)); Alias1 a1 = has_enums.kind; Alias2 a2 = has_enums.flags; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index d7d09916..7b3cb5c7 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1726,6 +1726,10 @@ rd_eval_space_gen(E_Space space) U64 result = 0; switch(space.kind) { + default: + { + result = ctrl_eval_space_gen(space); + }break; case RD_EvalSpaceKind_MetaCfg: case RD_EvalSpaceKind_MetaQuery: { From 02c7aaec85306731127074420edbdda9cbfc8f35 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 12:02:06 -0700 Subject: [PATCH 123/133] progress on config layer untangled from debugger frontend, to do eval on config on ctrl or async threads; turn off metaprogram by default --- build.bat | 5 +- src/config/config.c | 489 ++++++++++++++++++++++++++++++++++++--- src/config/config.h | 24 ++ src/raddbg/raddbg_main.c | 8 +- 4 files changed, 488 insertions(+), 38 deletions(-) diff --git a/build.bat b/build.bat index 9236ea1f..abe5f279 100644 --- a/build.bat +++ b/build.bat @@ -47,7 +47,6 @@ if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info] if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview if "%pgo%"=="1" ( - if "%no_meta%"=="" echo ERROR: PGO build must have no_meta argument || exit /b 1 where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1 if "%clang%"=="1" ( if "%pgo_run%" == "1" ( @@ -120,8 +119,8 @@ for /f %%i in ('call git describe --always --dirty') do set compile=%compile% for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\" :: --- Build & Run Metaprogram ------------------------------------------------ -if "%no_meta%"=="1" echo [skipping metagen] -if not "%no_meta%"=="1" ( +if "%meta%"=="1" ( + echo [doing metagen] pushd build %compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1 metagen.exe || exit /b 1 diff --git a/src/config/config.c b/src/config/config.c index e374ac97..1fb3e85d 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -4,59 +4,484 @@ //////////////////////////////// //~ rjf: ID Functions -internal void cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id); -internal CFG_IDList cfg_id_list_copy(Arena *arena, CFG_IDList *src); +internal void +cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id) +{ + CFG_IDNode *n = push_array(arena, CFG_IDNode, 1); + SLLQueuePush(list->first, list->last, n); + list->count += 1; + n->v = id; +} + +internal CFG_IDList +cfg_id_list_copy(Arena *arena, CFG_IDList *src) +{ + CFG_IDList dst = {0}; + for EachNode(n, CFG_IDNode, src->first) + { + cfg_id_list_push(arena, &dst, n->v); + } + return dst; +} //////////////////////////////// //~ rjf: Node Pointer Data Structure Functions -internal void cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node); -internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node); -#define cfg_node_ptr_list_first(list) ((list)->count ? (list)->first->v : &cfg_nil_node) -#define cfg_node_ptr_list_last(list) ((list)->count ? (list)->last->v : &cfg_nil_node) -internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list); +internal void +cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node) +{ + CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1); + SLLQueuePush(list->first, list->last, n); + list->count += 1; + n->v = node; +} + +internal void +cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node) +{ + CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1); + SLLQueuePushFront(list->first, list->last, n); + list->count += 1; + n->v = node; +} + +internal CFG_NodePtrArray +cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list) +{ + CFG_NodePtrArray array = {0}; + array.count = list->count; + array.v = push_array_no_zero(arena, CFG_Node *, array.count); + { + U64 idx = 0; + for EachNode(n, CFG_NodePtrNode, list->first) + { + array.v[idx] = n->v; + idx += 1; + } + } + return array; +} + +//////////////////////////////// +//~ rjf: Schema Data Structure Functions + +internal void +cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema) +{ + +} + +internal MD_NodePtrList +cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name) +{ + +} //////////////////////////////// //~ rjf: Config Reading Functions //- rjf: context selection -internal void cfg_ctx_select(CFG_Ctx *ctx); + +internal void +cfg_ctx_select(CFG_Ctx *ctx) +{ + cfg_ctx = ctx; +} //- rjf: tree navigations -internal CFG_Node *cfg_node_from_id(CFG_ID id); -internal CFG_Node *cfg_node_child_from_string(CFG_Node *parent, String8 string); -internal CFG_Node *cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string); -internal CFG_NodePtrList cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string); -internal CFG_NodePtrList cfg_node_top_level_list_from_string(Arena *arena, String8 string); -internal CFG_NodeRec cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node); + +internal CFG_Node * +cfg_node_from_id(CFG_ID id) +{ + CFG_Node *result = &cfg_nil_node; + if(id != 0 && + id == cfg_ctx->last_accessed_id && + id == cfg_ctx->last_accessed->id) + { + result = cfg_ctx->last_accessed; + } + else + { + U64 hash = u64_hash_from_str8(str8_struct(&id)); + U64 slot_idx = hash%cfg_ctx->id_slots_count; + for(CFG_NodePtrNode *n = cfg_ctx->id_slots[slot_idx].first; n != 0; n = n->next) + { + if(n->v->id == id) + { + result = n->v; + break; + } + } + } + cfg_ctx->last_accessed_id = id; + cfg_ctx->last_accessed = result; + return result; +} + +internal CFG_Node * +cfg_node_child_from_string(CFG_Node *parent, String8 string) +{ + CFG_Node *child = &cfg_nil_node; + if(string.size != 0) + { + for(CFG_Node *c = parent->first; c != &cfg_nil_node; c = c->next) + { + if(str8_match(c->string, string, 0)) + { + child = c; + break; + } + } + } + return child; +} + +internal CFG_Node * +cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string) +{ + CFG_Node *result = cfg_node_child_from_string(parent, string); + if(result == &cfg_nil_node) + { + result = parent; + } + return result; +} + +internal CFG_NodePtrList +cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string) +{ + CFG_NodePtrList result = {0}; + for(CFG_Node *child = parent->first; child != &cfg_nil_node; child = child->next) + { + if(str8_match(child->string, string, 0)) + { + cfg_node_ptr_list_push(arena, &result, child); + } + } + return result; +} + +internal CFG_NodePtrList +cfg_node_top_level_list_from_string(Arena *arena, String8 string) +{ + CFG_NodePtrList result = {0}; + for(CFG_Node *bucket = cfg_ctx->root->first; bucket != &cfg_nil_node; bucket = bucket->next) + { + for(CFG_Node *tln = bucket->first; tln != &cfg_nil_node; tln = tln->next) + { + if(str8_match(tln->string, string, 0)) + { + cfg_node_ptr_list_push(arena, &result, tln); + } + } + } + return result; +} + +internal CFG_NodeRec +cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node) +{ + CFG_NodeRec rec = {&cfg_nil_node}; + if(node->first != &cfg_nil_node) + { + rec.next = node->first; + rec.push_count = 1; + } + else for(CFG_Node *p = node; p != root; p = p->parent, rec.pop_count += 1) + { + if(p->next != &cfg_nil_node) + { + rec.next = p->next; + break; + } + } + return rec; +} //- rjf: serialization -internal String8 cfg_string_from_tree(Arena *arena, String8 root_path, CFG_Node *root); + +internal String8 +cfg_string_from_tree(Arena *arena, String8 root_path, CFG_Node *root) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List strings = {0}; + { + typedef struct NestTask NestTask; + struct NestTask + { + NestTask *next; + CFG_Node *cfg; + MD_Node *schema; + B32 is_simple; + }; + NestTask *top_nest_task = 0; + CFG_NodeRec rec = {0}; + for(CFG_Node *c = root; c != &cfg_nil_node; c = rec.next) + { + // rjf: look up parent's schemas + MD_NodePtrList schemas = {0}; + if(top_nest_task != 0) + { + CFG_Node *parent = top_nest_task->cfg; + schemas = rd_schemas_from_name(parent->string); + } + + // rjf: look up child schema + MD_Node *c_schema = &md_nil_node; + for(MD_NodePtrNode *n = schemas.first; n != 0 && c_schema == &md_nil_node; n = n->next) + { + c_schema = md_child_from_string(n->v, c->string, 0); + } + + // rjf: push name of this node + if(c->string.size != 0 || c->first == &cfg_nil_node) + { + // rjf: extract the textualized form for this string (we may need to escape / relativize) + String8 c_serialized_string = c->string; + { + MD_Node *c_schema = &md_nil_node; + if(top_nest_task != 0) + { + c_schema = top_nest_task->schema; + } + + // rjf: paths -> relativize + if(!md_node_has_tag(c_schema->first, str8_lit("no_relativize"), 0)) + { + if(str8_match(c_schema->first->string, str8_lit("path"), 0)) + { + String8 path_absolute = c->string; + String8 path_relative = path_relative_dst_from_absolute_dst_src(arena, path_absolute, root_path); + c_serialized_string = path_relative; + } + else if(str8_match(c_schema->first->string, str8_lit("path_pt"), 0)) + { + String8 value = c->string; + String8TxtPtPair parts = str8_txt_pt_pair_from_string(value); + String8 path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, parts.string, root_path); + c_serialized_string = push_str8f(arena, "%S:%I64d:%I64d", path_relative, parts.pt.line, parts.pt.column); + } + } + + // rjf: all strings -> escape + c_serialized_string = escaped_from_raw_str8(arena, c_serialized_string); + } + + // rjf: generate all strings for this node's string + String8List c_name_strings = {0}; + { + B32 name_can_be_pushed_standalone = 0; + { + Temp temp = temp_begin(scratch.arena); + MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c_serialized_string); + name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier| + MD_TokenFlag_Numeric| + MD_TokenFlag_StringLiteral| + MD_TokenFlag_Symbol)); + temp_end(temp); + } + if(name_can_be_pushed_standalone) + { + str8_list_push(scratch.arena, &c_name_strings, c_serialized_string); + } + else + { + str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + str8_list_push(scratch.arena, &c_name_strings, c_serialized_string); + str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + } + } + + // rjf: if we're in a simple nesting task, then just break children by space + if(top_nest_task != 0 && top_nest_task->is_simple) + { + str8_list_push(scratch.arena, &strings, str8_lit(" ")); + } + + // rjf: join c's strings with main string list + str8_list_concat_in_place(&strings, &c_name_strings); + } + + // rjf: grab next recursion + rec = cfg_node_rec__depth_first(root, c); + + // rjf: push a new nesting task before descending to children + if(c->first != &cfg_nil_node) + { + B32 is_simple_children_list = 1; + for(CFG_Node *child = c->first; child != &cfg_nil_node; child = child->next) + { + if(child->first != &cfg_nil_node && child != c->last) + { + is_simple_children_list = 0; + break; + } + } + NestTask *task = push_array(scratch.arena, NestTask, 1); + task->cfg = c; + task->schema = c_schema; + task->is_simple = is_simple_children_list; + SLLStackPush(top_nest_task, task); + } + + // rjf: tree navigations -> encode hierarchy + if(rec.push_count > 0) + { + if(top_nest_task->is_simple && c->string.size != 0) + { + str8_list_push(scratch.arena, &strings, str8_lit(":")); + } + else + { + if(c->string.size != 0) + { + str8_list_push(scratch.arena, &strings, str8_lit(":\n")); + } + str8_list_push(scratch.arena, &strings, str8_lit("{")); + } + } + else + { + for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, SLLStackPop(top_nest_task)) + { + if(top_nest_task->is_simple) + { + if(top_nest_task->cfg->string.size == 0) + { + str8_list_push(scratch.arena, &strings, str8_lit(" }")); + } + } + else + { + str8_list_push(scratch.arena, &strings, str8_lit("\n}")); + } + } + } + if(!top_nest_task || top_nest_task->is_simple == 0) + { + str8_list_push(scratch.arena, &strings, str8_lit("\n")); + } + } + } + String8 result_unindented = str8_list_join(scratch.arena, &strings, 0); + String8 result = indented_from_string(arena, result_unindented); + scratch_end(scratch); + return result; +} //////////////////////////////// //~ rjf: Config Writing Functions //- rjf: state creation / destroying -internal CFG_State *cfg_state_alloc(void); -internal void cfg_state_release(CFG_State *state); + +internal CFG_State * +cfg_state_alloc(void) +{ + Arena *arena = arena_alloc(); + CFG_State *state = push_array(arena, CFG_State, 1); + state->arena = arena; + return state; +} + +internal void +cfg_state_release(CFG_State *state) +{ + arena_release(state->arena); +} //- rjf: state -> ctx -internal CFG_Ctx *cfg_state_ctx(CFG_State *state); + +internal CFG_Ctx * +cfg_state_ctx(CFG_State *state) +{ + CFG_Ctx *ctx = &state->ctx; + return ctx; +} //- rjf: tree building -internal CFG_Node *cfg_node_alloc(CFG_State *state); -internal void cfg_node_release(CFG_State *state, CFG_Node *node); -internal void cfg_node_release_all_children(CFG_State *state, CFG_Node *node); -internal CFG_Node *cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string); -internal CFG_Node *cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...); -internal CFG_Node *cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string); -internal CFG_Node *cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...); -internal CFG_Node *cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root); -internal void cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string); -internal void cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...); -internal void cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child); -internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child); -internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string); + +internal CFG_Node * +cfg_node_alloc(CFG_State *state) +{ + +} + +internal void +cfg_node_release(CFG_State *state, CFG_Node *node) +{ + +} + +internal void +cfg_node_release_all_children(CFG_State *state, CFG_Node *node) +{ + +} + +internal CFG_Node * +cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string) +{ + +} + +internal CFG_Node * +cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...) +{ + +} + +internal CFG_Node * +cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string) +{ + +} + +internal CFG_Node * +cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...) +{ + +} + +internal CFG_Node * +cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root) +{ + +} + +internal void +cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string) +{ + +} + +internal void +cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...) +{ + +} + +internal void +cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child) +{ + +} + +internal void +cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child) +{ + +} + +internal CFG_Node * +cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string) +{ + +} //- rjf: deserialization -internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, String8 root_path, String8 string); + +internal CFG_NodePtrList +cfg_node_ptr_list_from_string(Arena *arena, String8 root_path, String8 string) +{ + +} diff --git a/src/config/config.h b/src/config/config.h index e0b12ed0..03495f80 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -101,6 +101,24 @@ struct CFG_State CFG_Ctx ctx; }; +//////////////////////////////// +//~ rjf: Schema Table + +typedef struct CFG_SchemaNode CFG_SchemaNode; +struct CFG_SchemaNode +{ + CFG_SchemaNode *next; + String8 name; + MD_Node *schema; +}; + +typedef struct CFG_SchemaTable CFG_SchemaTable; +struct CFG_SchemaTable +{ + CFG_SchemaNode **slots; + U64 slots_count; +}; + //////////////////////////////// //~ rjf: Globals @@ -130,6 +148,12 @@ internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, #define cfg_node_ptr_list_last(list) ((list)->count ? (list)->last->v : &cfg_nil_node) internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list); +//////////////////////////////// +//~ rjf: Schema Data Structure Functions + +internal void cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema); +internal MD_NodePtrList cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name); + //////////////////////////////// //~ rjf: Config Reading Functions diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 7099d25f..62e01c46 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -24,7 +24,7 @@ // [ ] fix type intepretations of cursor in bottom pane // //- bug fixes -// [ ] disassembly sometimes has a problem where source line annotations are +// [x] disassembly sometimes has a problem where source line annotations are // periodically removed/inserted... maybe updating on fs change when we // shouldn't, non-deterministic line annotation path? // @@ -110,10 +110,10 @@ // //- visualizer improvements // [ ] disasm starting address - need to use debug info for more correct results... -// [ ] linked list view // [ ] multidimensional `array` // [ ] 2-vector, 3-vector, quaternion // [ ] audio waveform views +// [x] linked list view // //- eval improvements // [ ] maybe add extra caching layer to process memory querying? we pay a pretty @@ -148,10 +148,10 @@ // [ ] step-out-of-loop // //- late-conversion performance improvements +// [ ] live++ investigations - ctrl+alt+f11 in UE? // [x] investigate wide-conversion performance // [x] oversubscribing cores? // [x] conversion crashes? -// [ ] live++ investigations - ctrl+alt+f11 in UE? // //- memory usage improvements // [x] "root" concept in hash store, which buckets keys & allows usage code to @@ -223,6 +223,7 @@ #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" #include "mdesk/mdesk.h" +#include "config/config.h" #include "content/content.h" #include "file_stream/file_stream.h" #include "text/text.h" @@ -270,6 +271,7 @@ #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" #include "mdesk/mdesk.c" +#include "config/config.c" #include "content/content.c" #include "file_stream/file_stream.c" #include "text/text.c" From 78c8aeaf4c1e27f34c051bd1992c6dce0ccaa377 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 12:18:29 -0700 Subject: [PATCH 124/133] config layer schemas --- src/config/config.c | 68 ++++++++++++++++++++++++++++++++++++++++++--- src/config/config.h | 3 +- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/config/config.c b/src/config/config.c index 1fb3e85d..9bd7260b 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -68,13 +68,73 @@ cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list) internal void cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema) { - + U64 hash = u64_hash_from_str8(name); + U64 slot_idx = hash%table->slots_count; + CFG_SchemaNode *node = 0; + for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next) + { + if(str8_match(n->name, name, 0)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(arena, CFG_SchemaNode, 1); + node->name = str8_copy(arena, name); + node->schema = schema; + SLLStackPush(table->slots[slot_idx], node); + } +} + +internal MD_Node * +cfg_schema_from_name(CFG_SchemaTable *table, String8 name) +{ + MD_Node *result = &md_nil_node; + { + U64 hash = u64_hash_from_str8(name); + U64 slot_idx = hash%table->slots_count; + CFG_SchemaNode *node = 0; + for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next) + { + if(str8_match(n->name, name, 0)) + { + result = n->schema; + break; + } + } + } + return result; } internal MD_NodePtrList cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name) { - + MD_NodePtrList result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + String8List tasks = {0}; + String8Node seed_task = {0, name}; + str8_list_push_node(&tasks, &seed_task); + for EachNode(task, String8Node, tasks.first) + { + MD_Node *schema = cfg_schema_from_name(table, task->string); + if(!md_node_is_nil(schema)) + { + md_node_ptr_list_push_front(arena, &result, schema); + for MD_EachNode(tag, schema->first_tag) + { + if(str8_match(tag->string, str8_lit("inherit"), 0)) + { + str8_list_push(scratch.arena, &tasks, tag->first->string); + } + } + } + } + scratch_end(scratch); + } + return result; } //////////////////////////////// @@ -201,7 +261,7 @@ cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node) //- rjf: serialization internal String8 -cfg_string_from_tree(Arena *arena, String8 root_path, CFG_Node *root) +cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root) { Temp scratch = scratch_begin(&arena, 1); String8List strings = {0}; @@ -223,7 +283,7 @@ cfg_string_from_tree(Arena *arena, String8 root_path, CFG_Node *root) if(top_nest_task != 0) { CFG_Node *parent = top_nest_task->cfg; - schemas = rd_schemas_from_name(parent->string); + schemas = cfg_schemas_from_name(scratch.arena, schema_table, parent->string); } // rjf: look up child schema diff --git a/src/config/config.h b/src/config/config.h index 03495f80..806f3633 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -152,6 +152,7 @@ internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtr //~ rjf: Schema Data Structure Functions internal void cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema); +internal MD_Node *cfg_schema_from_name(CFG_SchemaTable *table, String8 name); internal MD_NodePtrList cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name); //////////////////////////////// @@ -169,7 +170,7 @@ internal CFG_NodePtrList cfg_node_top_level_list_from_string(Arena *arena, Strin internal CFG_NodeRec cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node); //- rjf: serialization -internal String8 cfg_string_from_tree(Arena *arena, String8 root_path, CFG_Node *root); +internal String8 cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root); //////////////////////////////// //~ rjf: Config Writing Functions From 05e096d8b74e7fbc8d91e290c72b8714df786150 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 13:56:26 -0700 Subject: [PATCH 125/133] further port of rd cfg --- src/config/config.c | 351 ++++++++++++++++++++++++++++++++++++++++++-- src/config/config.h | 30 +++- 2 files changed, 368 insertions(+), 13 deletions(-) diff --git a/src/config/config.c b/src/config/config.c index 9bd7260b..b4f01b98 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -440,6 +440,9 @@ cfg_state_alloc(void) Arena *arena = arena_alloc(); CFG_State *state = push_array(arena, CFG_State, 1); state->arena = arena; + state->ctx.id_slots_count = 4096; + state->ctx.id_slots = push_array(arena, CFG_NodePtrSlot, state->ctx.id_slots_count); + state->ctx.root = cfg_node_alloc(state); return state; } @@ -458,90 +461,414 @@ cfg_state_ctx(CFG_State *state) return ctx; } +//- rjf: string allocations + +internal U64 +cfg_string_bucket_num_from_size(U64 size) +{ + U64 bucket_num = 0; + if(size > 0) + { + for EachElement(idx, cfg_string_bucket_chunk_sizes) + { + if(size <= cfg_string_bucket_chunk_sizes[idx]) + { + bucket_num = idx+1; + break; + } + } + } + return bucket_num; +} + +internal String8 +cfg_string_alloc(CFG_State *state, String8 string) +{ + //- rjf: allocate node + CFG_StringChunkNode *node = 0; + { + U64 bucket_num = cfg_string_bucket_num_from_size(string.size); + if(bucket_num == ArrayCount(cfg_string_bucket_chunk_sizes)) + { + CFG_StringChunkNode *best_node = 0; + CFG_StringChunkNode *best_node_prev = 0; + U64 best_node_size = max_U64; + { + for(CFG_StringChunkNode *n = state->free_string_chunks[bucket_num-1], *prev = 0; n != 0; (prev = n, n = n->next)) + { + if(n->size >= string.size && n->size < best_node_size) + { + best_node = n; + best_node_prev = prev; + best_node_size = n->size; + } + } + } + if(best_node != 0) + { + node = best_node; + if(best_node_prev) + { + best_node_prev->next = best_node->next; + } + else + { + state->free_string_chunks[bucket_num-1] = best_node->next; + } + } + else + { + U64 chunk_size = u64_up_to_pow2(string.size); + node = (CFG_StringChunkNode *)push_array(state->arena, U8, chunk_size); + } + } + else if(bucket_num != 0) + { + node = state->free_string_chunks[bucket_num-1]; + if(node != 0) + { + SLLStackPop(state->free_string_chunks[bucket_num-1]); + } + else + { + node = (CFG_StringChunkNode *)push_array(state->arena, U8, cfg_string_bucket_chunk_sizes[bucket_num-1]); + } + } + } + + //- rjf: fill node + String8 result = {0}; + if(node != 0) + { + result.str = (U8 *)node; + result.size = string.size; + MemoryCopy(result.str, string.str, result.size); + } + return result; +} + +internal void +cfg_string_release(CFG_State *state, String8 string) +{ + U64 bucket_num = cfg_string_bucket_num_from_size(string.size); + if(1 <= bucket_num && bucket_num <= ArrayCount(cfg_string_bucket_chunk_sizes)) + { + U64 bucket_idx = bucket_num-1; + CFG_StringChunkNode *node = (CFG_StringChunkNode *)string.str; + SLLStackPush(state->free_string_chunks[bucket_idx], node); + node->size = u64_up_to_pow2(string.size); + } +} + //- rjf: tree building internal CFG_Node * cfg_node_alloc(CFG_State *state) { + state->ctx.change_gen += 1; + // rjf: allocate + CFG_Node *result = state->free; + { + if(result) + { + SLLStackPop(state->free); + } + else + { + result = push_array_no_zero(state->arena, CFG_Node, 1); + } + } + + // rjf: generate ID & fill + state->id_gen += 1; + MemoryZeroStruct(result); + result->first = result->last = result->next = result->prev = result->parent = &cfg_nil_node; + result->id = state->id_gen; + + // rjf: store to ID -> cfg map + { + CFG_NodePtrNode *cfg_id_node = state->free_id_node; + if(cfg_id_node != 0) + { + SLLStackPop(state->free_id_node); + } + else + { + cfg_id_node = push_array(state->arena, CFG_NodePtrNode, 1); + } + U64 hash = u64_hash_from_str8(str8_struct(&result->id)); + U64 slot_idx = hash%state->ctx.id_slots_count; + DLLPushBack(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, cfg_id_node); + cfg_id_node->v = result; + } + + return result; } internal void cfg_node_release(CFG_State *state, CFG_Node *node) { + state->ctx.change_gen += 1; + Temp scratch = scratch_begin(0, 0); + + // rjf: unhook from context + cfg_node_unhook(state, node->parent, node); + + // rjf: gather root & all descendants + CFG_NodePtrList nodes = {0}; + for(CFG_Node *c = node; c != &cfg_nil_node; c = cfg_node_rec__depth_first(node, c).next) + { + cfg_node_ptr_list_push(scratch.arena, &nodes, c); + } + + // rjf: release all nodes + for(CFG_NodePtrNode *n = nodes.first; n != 0; n = n->next) + { + CFG_Node *c = n->v; + cfg_string_release(state, c->string); + SLLStackPush(state->free, c); + c->first = c->last = c->prev = c->parent = 0; + c->id = 0; + c->string = str8_zero(); + U64 hash = u64_hash_from_str8(str8_struct(&c->id)); + U64 slot_idx = hash%state->ctx.id_slots_count; + for(CFG_NodePtrNode *n = state->ctx.id_slots[slot_idx].first; n != 0; n = n->next) + { + if(n->v == c) + { + DLLRemove(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, n); + SLLStackPush(state->free_id_node, n); + break; + } + } + } + + scratch_end(scratch); } internal void cfg_node_release_all_children(CFG_State *state, CFG_Node *node) { - + for(CFG_Node *child = node->first, *next = &cfg_nil_node; child != &cfg_nil_node; child = next) + { + next = child->next; + cfg_node_release(state, child); + } } internal CFG_Node * cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string) { - + CFG_Node *node = cfg_node_alloc(state); + cfg_node_insert_child(state, parent, parent->last, node); + cfg_node_equip_string(state, node, string); + return node; } internal CFG_Node * cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...) { - + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + CFG_Node *result = cfg_node_new(state, parent, string); + va_end(args); + scratch_end(scratch); + return result; } internal CFG_Node * cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string) { - + Temp scratch = scratch_begin(0, 0); + string = push_str8_copy(scratch.arena, string); + for(CFG_Node *child = parent->first->next, *next = &cfg_nil_node; child != &cfg_nil_node; child = next) + { + next = child->next; + cfg_node_release(state, child); + } + if(parent->first == &cfg_nil_node) + { + cfg_node_new(state, parent, str8_zero()); + } + CFG_Node *child = parent->first; + cfg_node_equip_string(state, child, string); + scratch_end(scratch); + return child; } internal CFG_Node * cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...) { - + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + CFG_Node *result = cfg_node_new_replace(state, parent, string); + va_end(args); + scratch_end(scratch); + return result; } internal CFG_Node * cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root) { - + CFG_NodeRec rec = {0}; + CFG_Node *dst_root = &cfg_nil_node; + CFG_Node *dst_parent = &cfg_nil_node; + for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next) + { + CFG_Node *dst = cfg_node_new(state, dst_parent, src->string); + if(dst_root == &cfg_nil_node) + { + dst_root = dst; + } + rec = cfg_node_rec__depth_first(src_root, src); + if(rec.push_count > 0) + { + dst_parent = dst; + } + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + dst_parent = dst_parent->parent; + } + } + return dst_root; } internal void cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string) { - + cfg_string_release(state, node->string); + node->string = cfg_string_alloc(state, string); + state->ctx.change_gen += 1; } internal void cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...) { - + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + cfg_node_equip_string(state, node, string); + va_end(args); + scratch_end(scratch); } internal void cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child) { - + if(parent != &cfg_nil_node) + { + if(new_child->parent != &cfg_nil_node) + { + cfg_node_unhook(state, new_child->parent, new_child); + } + DLLInsert_NPZ(&cfg_nil_node, parent->first, parent->last, prev_child, new_child, next, prev); + new_child->parent = parent; + } } internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child) { - + if(child != &cfg_nil_node && parent == child->parent && parent != &cfg_nil_node) + { + DLLRemove_NPZ(&cfg_nil_node, parent->first, parent->last, child, next, prev); + child->parent = &cfg_nil_node; + } } internal CFG_Node * cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string) { - + CFG_Node *node = cfg_node_child_from_string(parent, string); + if(node == &cfg_nil_node) + { + node = cfg_node_new(state, parent, string); + } + return node; } //- rjf: deserialization internal CFG_NodePtrList -cfg_node_ptr_list_from_string(Arena *arena, String8 root_path, String8 string) +cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string) { + CFG_NodePtrList result = {0}; + Temp scratch = scratch_begin(&arena, 1); + //- rjf: parse the string as metadesk + MD_Node *root = md_tree_from_string(scratch.arena, string); + + //- rjf: iterate the top-level metadesk trees, generate new cfg trees for each + for MD_EachNode(tln, root->first) + { + CFG_Node *dst_root_n = &cfg_nil_node; + CFG_Node *dst_active_parent_n = &cfg_nil_node; + MD_NodeRec rec = {0}; + for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next) + { + // rjf: lookup schema for this string + MD_Node *schema = &md_nil_node; + { + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, schema_table, dst_active_parent_n->parent->string); + for(MD_NodePtrNode *n = schemas.first; n != 0 && schema == &md_nil_node; n = n->next) + { + schema = md_child_from_string(n->v, dst_active_parent_n->string, 0); + } + } + + // rjf: extract & transform metadesk node's string (it is raw textual data, so we need to + // go escaped -> raw, and derelativize paths) + String8 dst_n_string = {0}; + { + String8 src_n_string = src_n->string; + String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string); + if(!md_node_has_tag(schema->first, str8_lit("no_relativize"), 0)) + { + if(str8_match(schema->first->string, str8_lit("path"), 0)) + { + src_n_string__raw = path_absolute_dst_from_relative_dst_src(scratch.arena, src_n_string__raw, root_path); + } + else if(str8_match(schema->first->string, str8_lit("path_pt"), 0)) + { + String8TxtPtPair parts = str8_txt_pt_pair_from_string(src_n_string__raw); + src_n_string__raw = push_str8f(scratch.arena, "%S:%I64d:%I64d", path_absolute_dst_from_relative_dst_src(scratch.arena, parts.string, root_path), parts.pt.line, parts.pt.column); + } + } + dst_n_string = src_n_string__raw; + } + + // rjf: allocate, fill, & insert new cfg for this metadesk node + CFG_Node *dst_n = cfg_node_alloc(state); + cfg_node_equip_string(state, dst_n, dst_n_string); + if(dst_active_parent_n != &cfg_nil_node) + { + cfg_node_insert_child(state, dst_active_parent_n, dst_active_parent_n->last, dst_n); + } + + // rjf: recurse + rec = md_node_rec_depth_first_pre(src_n, tln); + if(dst_active_parent_n == &cfg_nil_node) + { + dst_root_n = dst_n; + } + if(rec.push_count > 0) + { + dst_active_parent_n = dst_n; + } + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + dst_active_parent_n = dst_active_parent_n->parent; + } + } + cfg_node_list_push(arena, &result, dst_root_n); + } + scratch_end(scratch); + return result; } diff --git a/src/config/config.h b/src/config/config.h index 806f3633..430065d9 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -77,6 +77,28 @@ struct CFG_NodeRec S32 pop_count; }; +//////////////////////////////// +//~ rjf: String Allocator + +read_only global U64 cfg_string_bucket_chunk_sizes[] = +{ + 16, + 64, + 256, + 1024, + 4096, + 16384, + 65536, + 0xffffffffffffffffull, +}; + +typedef struct CFG_StringChunkNode CFG_StringChunkNode; +struct CFG_StringChunkNode +{ + CFG_StringChunkNode *next; + U64 size; +}; + //////////////////////////////// //~ rjf: Config State Bundles @@ -97,6 +119,7 @@ struct CFG_State Arena *arena; CFG_Node *free; CFG_NodePtrNode *free_id_node; + CFG_StringChunkNode *free_string_chunks[ArrayCount(cfg_string_bucket_chunk_sizes)]; U64 id_gen; CFG_Ctx ctx; }; @@ -182,6 +205,11 @@ internal void cfg_state_release(CFG_State *state); //- rjf: state -> ctx internal CFG_Ctx *cfg_state_ctx(CFG_State *state); +//- rjf: string allocations +internal U64 cfg_string_bucket_num_from_size(U64 size); +internal String8 cfg_string_alloc(CFG_State *state, String8 string); +internal void cfg_string_release(CFG_State *state, String8 string); + //- rjf: tree building internal CFG_Node *cfg_node_alloc(CFG_State *state); internal void cfg_node_release(CFG_State *state, CFG_Node *node); @@ -198,6 +226,6 @@ internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *chil internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string); //- rjf: deserialization -internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, String8 root_path, String8 string); +internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string); #endif // CONFIG_H From edb186302023eac961414b4f329f621583ba780b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 14:06:12 -0700 Subject: [PATCH 126/133] rd_cfgid -> cfg_id --- project.4coder | 2 +- src/raddbg/generated/raddbg.meta.c | 16 ++++----- src/raddbg/generated/raddbg.meta.h | 16 ++++----- src/raddbg/raddbg.mdesk | 16 ++++----- src/raddbg/raddbg_core.c | 43 ++++++------------------ src/raddbg/raddbg_core.h | 54 ++++++++---------------------- src/raddbg/raddbg_eval.c | 4 +-- src/raddbg/raddbg_views.c | 2 +- 8 files changed, 52 insertions(+), 101 deletions(-) diff --git a/project.4coder b/project.4coder index 9dc98bf1..6abaea66 100644 --- a/project.4coder +++ b/project.4coder @@ -46,7 +46,7 @@ load_paths = commands = { //- rjf: [raddbg] - .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg meta telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 140275af..875b6d11 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -503,14 +503,14 @@ Rng1U64 rd_reg_slot_range_table[47] = {OffsetOf(RD_Regs, process), OffsetOf(RD_Regs, process) + sizeof(CTRL_Handle)}, {OffsetOf(RD_Regs, thread), OffsetOf(RD_Regs, thread) + sizeof(CTRL_Handle)}, {OffsetOf(RD_Regs, ctrl_entity), OffsetOf(RD_Regs, ctrl_entity) + sizeof(CTRL_Handle)}, -{OffsetOf(RD_Regs, window), OffsetOf(RD_Regs, window) + sizeof(RD_CfgID)}, -{OffsetOf(RD_Regs, panel), OffsetOf(RD_Regs, panel) + sizeof(RD_CfgID)}, -{OffsetOf(RD_Regs, tab), OffsetOf(RD_Regs, tab) + sizeof(RD_CfgID)}, -{OffsetOf(RD_Regs, view), OffsetOf(RD_Regs, view) + sizeof(RD_CfgID)}, -{OffsetOf(RD_Regs, prev_tab), OffsetOf(RD_Regs, prev_tab) + sizeof(RD_CfgID)}, -{OffsetOf(RD_Regs, dst_panel), OffsetOf(RD_Regs, dst_panel) + sizeof(RD_CfgID)}, -{OffsetOf(RD_Regs, cfg), OffsetOf(RD_Regs, cfg) + sizeof(RD_CfgID)}, -{OffsetOf(RD_Regs, cfg_list), OffsetOf(RD_Regs, cfg_list) + sizeof(RD_CfgIDList)}, +{OffsetOf(RD_Regs, window), OffsetOf(RD_Regs, window) + sizeof(CFG_ID)}, +{OffsetOf(RD_Regs, panel), OffsetOf(RD_Regs, panel) + sizeof(CFG_ID)}, +{OffsetOf(RD_Regs, tab), OffsetOf(RD_Regs, tab) + sizeof(CFG_ID)}, +{OffsetOf(RD_Regs, view), OffsetOf(RD_Regs, view) + sizeof(CFG_ID)}, +{OffsetOf(RD_Regs, prev_tab), OffsetOf(RD_Regs, prev_tab) + sizeof(CFG_ID)}, +{OffsetOf(RD_Regs, dst_panel), OffsetOf(RD_Regs, dst_panel) + sizeof(CFG_ID)}, +{OffsetOf(RD_Regs, cfg), OffsetOf(RD_Regs, cfg) + sizeof(CFG_ID)}, +{OffsetOf(RD_Regs, cfg_list), OffsetOf(RD_Regs, cfg_list) + sizeof(CFG_IDList)}, {OffsetOf(RD_Regs, eval_space), OffsetOf(RD_Regs, eval_space) + sizeof(E_Space)}, {OffsetOf(RD_Regs, unwind_count), OffsetOf(RD_Regs, unwind_count) + sizeof(U64)}, {OffsetOf(RD_Regs, inline_depth), OffsetOf(RD_Regs, inline_depth) + sizeof(U64)}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index 14e419f0..da4c5954 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -449,14 +449,14 @@ CTRL_Handle module; CTRL_Handle process; CTRL_Handle thread; CTRL_Handle ctrl_entity; -RD_CfgID window; -RD_CfgID panel; -RD_CfgID tab; -RD_CfgID view; -RD_CfgID prev_tab; -RD_CfgID dst_panel; -RD_CfgID cfg; -RD_CfgIDList cfg_list; +CFG_ID window; +CFG_ID panel; +CFG_ID tab; +CFG_ID view; +CFG_ID prev_tab; +CFG_ID dst_panel; +CFG_ID cfg; +CFG_IDList cfg_list; E_Space eval_space; U64 unwind_count; U64 inline_depth; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 2e24874c..143b0a78 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -713,14 +713,14 @@ RD_RegTable: {CTRL_Handle ctrl_entity CtrlEntity } // rjf: cfgs - {RD_CfgID window Window } - {RD_CfgID panel Panel } - {RD_CfgID tab Tab } - {RD_CfgID view View } - {RD_CfgID prev_tab PrevTab } - {RD_CfgID dst_panel DstPanel } - {RD_CfgID cfg Cfg } - {RD_CfgIDList cfg_list CfgList } + {CFG_ID window Window } + {CFG_ID panel Panel } + {CFG_ID tab Tab } + {CFG_ID view View } + {CFG_ID prev_tab PrevTab } + {CFG_ID dst_panel DstPanel } + {CFG_ID cfg Cfg } + {CFG_IDList cfg_list CfgList } // rjf: evaluation space {E_Space eval_space EvalSpace } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 7b3cb5c7..98c750a9 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -9,29 +9,6 @@ #include "generated/raddbg.meta.c" -//////////////////////////////// -//~ rjf: Config ID Type Functions - -internal void -rd_cfg_id_list_push(Arena *arena, RD_CfgIDList *list, RD_CfgID id) -{ - RD_CfgIDNode *n = push_array(arena, RD_CfgIDNode, 1); - n->v = id; - SLLQueuePush(list->first, list->last, n); - list->count += 1; -} - -internal RD_CfgIDList -rd_cfg_id_list_copy(Arena *arena, RD_CfgIDList *src) -{ - RD_CfgIDList result = {0}; - for(RD_CfgIDNode *n = src->first; n != 0; n = n->next) - { - rd_cfg_id_list_push(arena, &result, n->v); - } - return result; -} - //////////////////////////////// //~ rjf: Registers Type Functions @@ -39,7 +16,7 @@ internal void rd_regs_copy_contents(Arena *arena, RD_Regs *dst, RD_Regs *src) { MemoryCopyStruct(dst, src); - dst->cfg_list = rd_cfg_id_list_copy(arena, &src->cfg_list); + dst->cfg_list = cfg_id_list_copy(arena, &src->cfg_list); dst->file_path = push_str8_copy(arena, src->file_path); dst->lines = d_line_list_copy(arena, &src->lines); dst->expr = push_str8_copy(arena, src->expr); @@ -47,7 +24,7 @@ rd_regs_copy_contents(Arena *arena, RD_Regs *dst, RD_Regs *src) dst->cmd_name = push_str8_copy(arena, src->cmd_name); if(dst->cfg_list.count == 0 && dst->cfg != 0) { - rd_cfg_id_list_push(arena, &dst->cfg_list, dst->cfg); + cfg_id_list_push(arena, &dst->cfg_list, dst->cfg); } } @@ -368,7 +345,7 @@ rd_cfg_release_all_children(RD_Cfg *cfg) } internal RD_Cfg * -rd_cfg_from_id(RD_CfgID id) +rd_cfg_from_id(CFG_ID id) { RD_Cfg *result = &rd_nil_cfg; if(id != 0 && @@ -1664,7 +1641,7 @@ rd_cfg_from_eval_space(E_Space space) RD_Cfg *cfg = &rd_nil_cfg; if(space.kind == RD_EvalSpaceKind_MetaCfg) { - RD_CfgID id = space.u64s[0]; + CFG_ID id = space.u64s[0]; cfg = rd_cfg_from_id(id); } return cfg; @@ -2454,7 +2431,7 @@ internal RD_ViewState * rd_view_state_from_cfg(RD_Cfg *cfg) { RD_ViewState *view_state = &rd_nil_view_state; - RD_CfgID id = cfg->id; + CFG_ID id = cfg->id; if(id != 0 && id == rd_state->view_state_last_accessed_id && id == rd_state->view_state_last_accessed->cfg_id) @@ -5803,7 +5780,7 @@ rd_window_state_from_cfg(RD_Cfg *cfg) { //- rjf: unpack RD_Cfg *window_cfg = rd_window_from_cfg(cfg); - RD_CfgID id = window_cfg->id; + CFG_ID id = window_cfg->id; //- rjf: scan for existing window RD_WindowState *ws = &rd_nil_window_state; @@ -10660,7 +10637,7 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 query_expr, String8 strin if(!good && str8_match(str8_prefix(string, 1), str8_lit("$"), 0)) { String8 numeric_part = str8_skip(string, 1); - RD_CfgID id = u64_from_str8(numeric_part, 16); + CFG_ID id = u64_from_str8(numeric_part, 16); rd_regs()->cfg = id; good = 1; } @@ -17317,15 +17294,15 @@ rd_frame(void) // if(rd_state->frame_depth == 1) { - RD_CfgIDList windows_to_show = {0}; + CFG_IDList windows_to_show = {0}; for(RD_WindowState *w = rd_state->first_window_state; w != &rd_nil_window_state; w = w->order_next) { if(w->frames_alive == 1) { - rd_cfg_id_list_push(scratch.arena, &windows_to_show, w->cfg_id); + cfg_id_list_push(scratch.arena, &windows_to_show, w->cfg_id); } } - for(RD_CfgIDNode *n = windows_to_show.first; n != 0; n = n->next) + for(CFG_IDNode *n = windows_to_show.first; n != 0; n = n->next) { RD_Cfg *window = rd_cfg_from_id(n->v); RD_WindowState *ws = rd_window_state_from_cfg(window); diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 1f54172d..dcc4a6b9 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -4,26 +4,6 @@ #ifndef RADDBG_CORE_H #define RADDBG_CORE_H -//////////////////////////////// -//~ rjf: Config IDs - -typedef U64 RD_CfgID; - -typedef struct RD_CfgIDNode RD_CfgIDNode; -struct RD_CfgIDNode -{ - RD_CfgIDNode *next; - RD_CfgID v; -}; - -typedef struct RD_CfgIDList RD_CfgIDList; -struct RD_CfgIDList -{ - RD_CfgIDNode *first; - RD_CfgIDNode *last; - U64 count; -}; - //////////////////////////////// //~ rjf: Key Bindings @@ -39,7 +19,7 @@ struct RD_KeyMapNode { RD_KeyMapNode *name_hash_next; RD_KeyMapNode *binding_hash_next; - RD_CfgID cfg_id; + CFG_ID cfg_id; String8 name; RD_Binding binding; }; @@ -197,7 +177,7 @@ struct RD_ViewState // rjf: hash links & key RD_ViewState *hash_next; RD_ViewState *hash_prev; - RD_CfgID cfg_id; + CFG_ID cfg_id; // rjf: touch info U64 last_frame_index_touched; @@ -278,7 +258,7 @@ struct RD_Cfg RD_Cfg *next; RD_Cfg *prev; RD_Cfg *parent; - RD_CfgID id; + CFG_ID id; String8 string; }; @@ -432,7 +412,7 @@ struct RD_WindowState RD_WindowState *order_prev; RD_WindowState *hash_next; RD_WindowState *hash_prev; - RD_CfgID cfg_id; + CFG_ID cfg_id; U64 frames_alive; U64 last_frame_index_touched; @@ -470,8 +450,8 @@ struct RD_WindowState B32 query_is_active; Arena *query_arena; RD_Regs *query_regs; - RD_CfgID query_view_id; - RD_CfgID query_last_view_id; + CFG_ID query_view_id; + CFG_ID query_last_view_id; // rjf: hover eval state B32 hover_eval_focused; @@ -674,7 +654,7 @@ struct RD_State RD_CfgSlot *cfg_id_slots; RD_CfgNode *free_cfg_id_node; U64 cfg_id_gen; - RD_CfgID cfg_last_accessed_id; + CFG_ID cfg_last_accessed_id; RD_Cfg *cfg_last_accessed; U64 cfg_change_gen; @@ -682,23 +662,23 @@ struct RD_State U64 window_state_slots_count; RD_WindowStateSlot *window_state_slots; RD_WindowState *free_window_state; - RD_CfgID last_focused_window; + CFG_ID last_focused_window; RD_WindowState *first_window_state; RD_WindowState *last_window_state; - RD_CfgID window_state_last_accessed_id; + CFG_ID window_state_last_accessed_id; RD_WindowState *window_state_last_accessed; // rjf: view state cache U64 view_state_slots_count; RD_ViewStateSlot *view_state_slots; RD_ViewState *free_view_state; - RD_CfgID view_state_last_accessed_id; + CFG_ID view_state_last_accessed_id; RD_ViewState *view_state_last_accessed; // rjf: bind change Arena *bind_change_arena; B32 bind_change_active; - RD_CfgID bind_change_binding_id; + CFG_ID bind_change_binding_id; String8 bind_change_cmd_name; // rjf: pre-stop focused window @@ -755,14 +735,8 @@ read_only global RD_WindowState rd_nil_window_state = }; global RD_State *rd_state = 0; -global RD_CfgID rd_last_drag_drop_panel = 0; -global RD_CfgID rd_last_drag_drop_prev_tab = 0; - -//////////////////////////////// -//~ rjf: Config ID Type Functions - -internal void rd_cfg_id_list_push(Arena *arena, RD_CfgIDList *list, RD_CfgID id); -internal RD_CfgIDList rd_cfg_id_list_copy(Arena *arena, RD_CfgIDList *src); +global CFG_ID rd_last_drag_drop_panel = 0; +global CFG_ID rd_last_drag_drop_prev_tab = 0; //////////////////////////////// //~ rjf: Registers Type Functions @@ -807,7 +781,7 @@ internal void rd_name_release(String8 string); internal RD_Cfg *rd_cfg_alloc(void); internal void rd_cfg_release(RD_Cfg *cfg); internal void rd_cfg_release_all_children(RD_Cfg *cfg); -internal RD_Cfg *rd_cfg_from_id(RD_CfgID id); +internal RD_Cfg *rd_cfg_from_id(CFG_ID id); internal RD_Cfg *rd_cfg_new(RD_Cfg *parent, String8 string); internal RD_Cfg *rd_cfg_newf(RD_Cfg *parent, char *fmt, ...); internal RD_Cfg *rd_cfg_new_replace(RD_Cfg *parent, String8 string); diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index d07597b5..785f1475 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -636,7 +636,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(cfgs) str8_match(str8_prefix(rhs->string, 1), str8_lit("$"), 0)) { String8 numeric_part = str8_skip(rhs->string, 1); - RD_CfgID id = u64_from_str8(numeric_part, 16); + CFG_ID id = u64_from_str8(numeric_part, 16); RD_Cfg *cfg = rd_cfg_from_id(id); E_Space space = rd_eval_space_from_cfg(cfg); result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, 0)); @@ -739,7 +739,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(cfgs_slice) case E_ExprKind_MemberAccess: { String8 rhs_name = expr->first->next->string; - RD_CfgID id = 0; + CFG_ID id = 0; if(str8_match(str8_prefix(rhs_name, 1), str8_lit("$"), 0)) { id = u64_from_str8(str8_skip(rhs_name, 1), 16); diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 1f832c49..68653c29 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1089,7 +1089,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) block_type->expand.id_from_num == E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches) || block_type->expand.id_from_num == E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment))) { - RD_CfgID id = row->key.child_id; + CFG_ID id = row->key.child_id; info.group_cfg_child = rd_cfg_from_id(id); } } From 46634f547f7e6f1c57cc4b419ea4245a78e743a8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 14:08:50 -0700 Subject: [PATCH 127/133] remove old frame call stack tree cache - supplanted by artifact cache --- src/raddbg/raddbg_core.c | 1 - src/raddbg/raddbg_core.h | 2 -- src/raddbg/raddbg_eval.c | 12 +++++------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 98c750a9..8c560241 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -11459,7 +11459,6 @@ rd_frame(void) // Access *frame_access_restore = rd_state->frame_access; rd_state->frame_access = access_open(); - rd_state->got_frame_call_stack_tree = 0; ////////////////////////////// //- rjf: calculate avg length in us of last many frames diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index dcc4a6b9..7afccd02 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -579,8 +579,6 @@ struct RD_State // rjf: frame parameters F32 frame_dt; Access *frame_access; - CTRL_CallStackTree frame_call_stack_tree; - B32 got_frame_call_stack_tree; // rjf: evaluation cache E_Cache *eval_cache; diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 785f1475..291ac872 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1558,17 +1558,15 @@ struct RD_CallStackTreeExpandAccel E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree) { - if(!rd_state->got_frame_call_stack_tree) - { - rd_state->got_frame_call_stack_tree = 1; - rd_state->frame_call_stack_tree = ctrl_call_stack_tree(rd_state->frame_access, 0); - } + Access *access = access_open(); + CTRL_CallStackTree call_stack_tree = ctrl_call_stack_tree(access, 0); + access_close(access); RD_CallStackTreeExpandAccel *accel = push_array(arena, RD_CallStackTreeExpandAccel, 1); accel->node = &ctrl_call_stack_tree_node_nil; U64 id = e_value_eval_from_eval(eval).value.u64; - if(rd_state->frame_call_stack_tree.slots_count != 0) + if(call_stack_tree.slots_count != 0) { - for(CTRL_CallStackTreeNode *n = rd_state->frame_call_stack_tree.slots[id%rd_state->frame_call_stack_tree.slots_count]; + for(CTRL_CallStackTreeNode *n = call_stack_tree.slots[id%call_stack_tree.slots_count]; n != 0; n = n->hash_next) { From 2f315911a52ecd2c538edf3a694fa4d6aa5ad941 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 14:59:06 -0700 Subject: [PATCH 128/133] switch off rd_cfg to cfg layer --- src/config/config.c | 24 +- src/config/config.h | 2 + src/ctrl/ctrl_core.c | 2 +- src/raddbg/raddbg_core.c | 2998 +++++++++++------------------ src/raddbg/raddbg_core.h | 181 +- src/raddbg/raddbg_eval.c | 106 +- src/raddbg/raddbg_legacy_config.c | 40 +- src/raddbg/raddbg_legacy_config.h | 2 +- src/raddbg/raddbg_main.c | 2 +- src/raddbg/raddbg_views.c | 104 +- src/raddbg/raddbg_views.h | 6 +- src/raddbg/raddbg_widgets.c | 78 +- src/raddbg/raddbg_widgets.h | 6 +- 13 files changed, 1341 insertions(+), 2210 deletions(-) diff --git a/src/config/config.c b/src/config/config.c index b4f01b98..e41f8ed1 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -150,6 +150,28 @@ cfg_ctx_select(CFG_Ctx *ctx) //- rjf: tree navigations +internal U64 +cfg_change_gen(void) +{ + U64 result = 0; + if(cfg_ctx != 0) + { + result = cfg_ctx->change_gen; + } + return result; +} + +internal CFG_Node * +cfg_node_root(void) +{ + CFG_Node *result = &cfg_nil_node; + if(cfg_ctx != 0) + { + result = cfg_ctx->root; + } + return result; +} + internal CFG_Node * cfg_node_from_id(CFG_ID id) { @@ -867,7 +889,7 @@ cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *s dst_active_parent_n = dst_active_parent_n->parent; } } - cfg_node_list_push(arena, &result, dst_root_n); + cfg_node_ptr_list_push(arena, &result, dst_root_n); } scratch_end(scratch); return result; diff --git a/src/config/config.h b/src/config/config.h index 430065d9..3099ccc4 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -185,6 +185,8 @@ internal MD_NodePtrList cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *tab internal void cfg_ctx_select(CFG_Ctx *ctx); //- rjf: tree navigations +internal U64 cfg_change_gen(void); +internal CFG_Node *cfg_node_root(void); internal CFG_Node *cfg_node_from_id(CFG_ID id); internal CFG_Node *cfg_node_child_from_string(CFG_Node *parent, String8 string); internal CFG_Node *cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string); diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 3bd826ce..d7627784 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -979,7 +979,7 @@ internal void ctrl_entity_string_release(CTRL_EntityCtxRWStore *store, String8 string) { U64 bucket_num = ctrl_name_bucket_num_from_string_size(string.size); - if(1 <= bucket_num && bucket_num <= ArrayCount(rd_name_bucket_chunk_sizes)) + if(1 <= bucket_num && bucket_num <= ArrayCount(ctrl_entity_string_bucket_chunk_sizes)) { U64 bucket_idx = bucket_num-1; CTRL_EntityStringChunkNode *node = (CTRL_EntityStringChunkNode *)string.str; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 8c560241..c9651f03 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -146,747 +146,21 @@ rd_get_hover_regs(void) } //////////////////////////////// -//~ rjf: Name Allocation - -internal U64 -rd_name_bucket_num_from_string_size(U64 size) -{ - U64 bucket_num = 0; - if(size > 0) - { - for EachElement(idx, rd_name_bucket_chunk_sizes) - { - if(size <= rd_name_bucket_chunk_sizes[idx]) - { - bucket_num = idx+1; - break; - } - } - } - return bucket_num; -} - -internal String8 -rd_name_alloc(String8 string) -{ - //- rjf: allocate node - RD_NameChunkNode *node = 0; - { - U64 bucket_num = rd_name_bucket_num_from_string_size(string.size); - if(bucket_num == ArrayCount(rd_name_bucket_chunk_sizes)) - { - RD_NameChunkNode *best_node = 0; - RD_NameChunkNode *best_node_prev = 0; - U64 best_node_size = max_U64; - { - for(RD_NameChunkNode *n = rd_state->free_name_chunks[bucket_num-1], *prev = 0; n != 0; (prev = n, n = n->next)) - { - if(n->size >= string.size && n->size < best_node_size) - { - best_node = n; - best_node_prev = prev; - best_node_size = n->size; - } - } - } - if(best_node != 0) - { - node = best_node; - if(best_node_prev) - { - best_node_prev->next = best_node->next; - } - else - { - rd_state->free_name_chunks[bucket_num-1] = best_node->next; - } - } - else - { - U64 chunk_size = u64_up_to_pow2(string.size); - node = (RD_NameChunkNode *)push_array(rd_state->arena, U8, chunk_size); - } - } - else if(bucket_num != 0) - { - node = rd_state->free_name_chunks[bucket_num-1]; - if(node != 0) - { - SLLStackPop(rd_state->free_name_chunks[bucket_num-1]); - } - else - { - node = (RD_NameChunkNode *)push_array(rd_state->arena, U8, rd_name_bucket_chunk_sizes[bucket_num-1]); - } - } - } - - //- rjf: fill node - String8 result = {0}; - if(node != 0) - { - result.str = (U8 *)node; - result.size = string.size; - MemoryCopy(result.str, string.str, result.size); - } - return result; -} - -internal void -rd_name_release(String8 string) -{ - U64 bucket_num = rd_name_bucket_num_from_string_size(string.size); - if(1 <= bucket_num && bucket_num <= ArrayCount(rd_name_bucket_chunk_sizes)) - { - U64 bucket_idx = bucket_num-1; - RD_NameChunkNode *node = (RD_NameChunkNode *)string.str; - SLLStackPush(rd_state->free_name_chunks[bucket_idx], node); - node->size = u64_up_to_pow2(string.size); - } -} - -//////////////////////////////// -//~ rjf: Config Tree Functions - -internal RD_Cfg * -rd_cfg_alloc(void) -{ - rd_state->cfg_change_gen += 1; - - // rjf: allocate - RD_Cfg *result = rd_state->free_cfg; - { - if(result) - { - SLLStackPop(rd_state->free_cfg); - } - else - { - result = push_array_no_zero(rd_state->arena, RD_Cfg, 1); - } - } - - // rjf: generate ID & fill - rd_state->cfg_id_gen += 1; - MemoryZeroStruct(result); - result->first = result->last = result->next = result->prev = result->parent = &rd_nil_cfg; - result->id = rd_state->cfg_id_gen; - - // rjf: store to ID -> cfg map - { - RD_CfgNode *cfg_id_node = rd_state->free_cfg_id_node; - if(cfg_id_node != 0) - { - SLLStackPop(rd_state->free_cfg_id_node); - } - else - { - cfg_id_node = push_array(rd_state->arena, RD_CfgNode, 1); - } - U64 hash = d_hash_from_string(str8_struct(&result->id)); - U64 slot_idx = hash%rd_state->cfg_id_slots_count; - DLLPushBack(rd_state->cfg_id_slots[slot_idx].first, rd_state->cfg_id_slots[slot_idx].last, cfg_id_node); - cfg_id_node->v = result; - } - - return result; -} - -internal void -rd_cfg_release(RD_Cfg *cfg) -{ - rd_state->cfg_change_gen += 1; - - Temp scratch = scratch_begin(0, 0); - - // rjf: unhook from context - rd_cfg_unhook(cfg->parent, cfg); - - // rjf: gather root & all descendants - RD_CfgList nodes = {0}; - for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rd_cfg_rec__depth_first(cfg, c).next) - { - rd_cfg_list_push(scratch.arena, &nodes, c); - } - - // rjf: release all nodes - for(RD_CfgNode *n = nodes.first; n != 0; n = n->next) - { - RD_Cfg *c = n->v; - rd_name_release(c->string); - SLLStackPush(rd_state->free_cfg, c); - c->first = c->last = c->prev = c->parent = 0; - c->id = 0; - c->string = str8_zero(); - U64 hash = d_hash_from_string(str8_struct(&c->id)); - U64 slot_idx = hash%rd_state->cfg_id_slots_count; - for(RD_CfgNode *n = rd_state->cfg_id_slots[slot_idx].first; n != 0; n = n->next) - { - if(n->v == c) - { - DLLRemove(rd_state->cfg_id_slots[slot_idx].first, rd_state->cfg_id_slots[slot_idx].last, n); - SLLStackPush(rd_state->free_cfg_id_node, n); - break; - } - } - } - - scratch_end(scratch); -} - -internal void -rd_cfg_release_all_children(RD_Cfg *cfg) -{ - for(RD_Cfg *child = cfg->first, *next = &rd_nil_cfg; child != &rd_nil_cfg; child = next) - { - next = child->next; - rd_cfg_release(child); - } -} - -internal RD_Cfg * -rd_cfg_from_id(CFG_ID id) -{ - RD_Cfg *result = &rd_nil_cfg; - if(id != 0 && - id == rd_state->cfg_last_accessed_id && - id == rd_state->cfg_last_accessed->id) - { - result = rd_state->cfg_last_accessed; - } - else - { - U64 hash = d_hash_from_string(str8_struct(&id)); - U64 slot_idx = hash%rd_state->cfg_id_slots_count; - for(RD_CfgNode *n = rd_state->cfg_id_slots[slot_idx].first; n != 0; n = n->next) - { - if(n->v->id == id) - { - result = n->v; - break; - } - } - } - rd_state->cfg_last_accessed_id = id; - rd_state->cfg_last_accessed = result; - return result; -} - -internal RD_Cfg * -rd_cfg_new(RD_Cfg *parent, String8 string) -{ - RD_Cfg *cfg = rd_cfg_alloc(); - rd_cfg_insert_child(parent, parent->last, cfg); - rd_cfg_equip_string(cfg, string); - return cfg; -} - -internal RD_Cfg * -rd_cfg_newf(RD_Cfg *parent, char *fmt, ...) -{ - Temp scratch = scratch_begin(0, 0); - va_list args; - va_start(args, fmt); - String8 string = push_str8fv(scratch.arena, fmt, args); - RD_Cfg *result = rd_cfg_new(parent, string); - va_end(args); - scratch_end(scratch); - return result; -} - -internal RD_Cfg * -rd_cfg_new_replace(RD_Cfg *parent, String8 string) -{ - Temp scratch = scratch_begin(0, 0); - string = push_str8_copy(scratch.arena, string); - for(RD_Cfg *child = parent->first->next, *next = &rd_nil_cfg; child != &rd_nil_cfg; child = next) - { - next = child->next; - rd_cfg_release(child); - } - if(parent->first == &rd_nil_cfg) - { - rd_cfg_new(parent, str8_zero()); - } - RD_Cfg *child = parent->first; - rd_cfg_equip_string(child, string); - scratch_end(scratch); - return child; -} - -internal RD_Cfg * -rd_cfg_new_replacef(RD_Cfg *parent, char *fmt, ...) -{ - Temp scratch = scratch_begin(0, 0); - va_list args; - va_start(args, fmt); - String8 string = push_str8fv(scratch.arena, fmt, args); - RD_Cfg *result = rd_cfg_new_replace(parent, string); - va_end(args); - scratch_end(scratch); - return result; -} - -internal RD_Cfg * -rd_cfg_deep_copy(RD_Cfg *src_root) -{ - RD_CfgRec rec = {0}; - RD_Cfg *dst_root = &rd_nil_cfg; - RD_Cfg *dst_parent = &rd_nil_cfg; - for(RD_Cfg *src = src_root; src != &rd_nil_cfg; src = rec.next) - { - RD_Cfg *dst = rd_cfg_new(dst_parent, src->string); - if(dst_root == &rd_nil_cfg) - { - dst_root = dst; - } - rec = rd_cfg_rec__depth_first(src_root, src); - if(rec.push_count > 0) - { - dst_parent = dst; - } - else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) - { - dst_parent = dst_parent->parent; - } - } - return dst_root; -} - -internal void -rd_cfg_equip_string(RD_Cfg *cfg, String8 string) -{ - rd_name_release(cfg->string); - cfg->string = rd_name_alloc(string); - rd_state->cfg_change_gen += 1; -} - -internal void -rd_cfg_equip_stringf(RD_Cfg *cfg, char *fmt, ...) -{ - Temp scratch = scratch_begin(0, 0); - va_list args; - va_start(args, fmt); - String8 string = push_str8fv(scratch.arena, fmt, args); - rd_cfg_equip_string(cfg, string); - va_end(args); - scratch_end(scratch); -} - -internal void -rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child) -{ - if(parent != &rd_nil_cfg) - { - if(new_child->parent != &rd_nil_cfg) - { - rd_cfg_unhook(new_child->parent, new_child); - } - DLLInsert_NPZ(&rd_nil_cfg, parent->first, parent->last, prev_child, new_child, next, prev); - new_child->parent = parent; - } -} - -internal void -rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child) -{ - if(child != &rd_nil_cfg && parent == child->parent && parent != &rd_nil_cfg) - { - DLLRemove_NPZ(&rd_nil_cfg, parent->first, parent->last, child, next, prev); - child->parent = &rd_nil_cfg; - } -} - -internal RD_Cfg * -rd_cfg_child_from_string(RD_Cfg *parent, String8 string) -{ - RD_Cfg *child = &rd_nil_cfg; - if(string.size != 0) - { - for(RD_Cfg *c = parent->first; c != &rd_nil_cfg; c = c->next) - { - if(str8_match(c->string, string, 0)) - { - child = c; - break; - } - } - } - return child; -} - -internal RD_Cfg * -rd_cfg_child_from_string_or_alloc(RD_Cfg *parent, String8 string) -{ - RD_Cfg *child = rd_cfg_child_from_string(parent, string); - if(child == &rd_nil_cfg) - { - child = rd_cfg_new(parent, string); - } - return child; -} - -internal RD_Cfg * -rd_cfg_child_from_string_or_parent(RD_Cfg *parent, String8 string) -{ - RD_Cfg *result = rd_cfg_child_from_string(parent, string); - if(result == &rd_nil_cfg) - { - result = parent; - } - return result; -} - -internal RD_CfgList -rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string) -{ - RD_CfgList result = {0}; - for(RD_Cfg *child = parent->first; child != &rd_nil_cfg; child = child->next) - { - if(str8_match(child->string, string, 0)) - { - rd_cfg_list_push(arena, &result, child); - } - } - return result; -} - -internal RD_CfgList -rd_cfg_top_level_list_from_string(Arena *arena, String8 string) -{ - RD_CfgList result = {0}; - for(RD_Cfg *bucket = rd_state->root_cfg->first; bucket != &rd_nil_cfg; bucket = bucket->next) - { - for(RD_Cfg *tln = bucket->first; tln != &rd_nil_cfg; tln = tln->next) - { - if(str8_match(tln->string, string, 0)) - { - rd_cfg_list_push(arena, &result, tln); - } - } - } - return result; -} - -internal RD_CfgArray -rd_cfg_array_from_list(Arena *arena, RD_CfgList *list) -{ - RD_CfgArray array = {0}; - array.count = list->count; - array.v = push_array_no_zero(arena, RD_Cfg *, array.count); - U64 idx = 0; - for(RD_CfgNode *n = list->first; n != 0; n = n->next, idx += 1) - { - array.v[idx] = n->v; - } - return array; -} - -internal RD_CfgList -rd_cfg_tree_list_from_string(Arena *arena, String8 root_path, String8 string) -{ - RD_CfgList result = {0}; - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: parse the string as metadesk - MD_Node *root = md_tree_from_string(scratch.arena, string); - - //- rjf: iterate the top-level metadesk trees, generate new cfg trees for each - for MD_EachNode(tln, root->first) - { - RD_Cfg *dst_root_n = &rd_nil_cfg; - RD_Cfg *dst_active_parent_n = &rd_nil_cfg; - MD_NodeRec rec = {0}; - for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next) - { - // rjf: lookup schema for this string - MD_Node *schema = &md_nil_node; - { - MD_NodePtrList schemas = rd_schemas_from_name(dst_active_parent_n->parent->string); - for(MD_NodePtrNode *n = schemas.first; n != 0 && schema == &md_nil_node; n = n->next) - { - schema = md_child_from_string(n->v, dst_active_parent_n->string, 0); - } - } - - // rjf: extract & transform metadesk node's string (it is raw textual data, so we need to - // go escaped -> raw, and derelativize paths) - String8 dst_n_string = {0}; - { - String8 src_n_string = src_n->string; - String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string); - if(!md_node_has_tag(schema->first, str8_lit("no_relativize"), 0)) - { - if(str8_match(schema->first->string, str8_lit("path"), 0)) - { - src_n_string__raw = path_absolute_dst_from_relative_dst_src(scratch.arena, src_n_string__raw, root_path); - } - else if(str8_match(schema->first->string, str8_lit("path_pt"), 0)) - { - String8TxtPtPair parts = str8_txt_pt_pair_from_string(src_n_string__raw); - src_n_string__raw = push_str8f(scratch.arena, "%S:%I64d:%I64d", path_absolute_dst_from_relative_dst_src(scratch.arena, parts.string, root_path), parts.pt.line, parts.pt.column); - } - } - dst_n_string = src_n_string__raw; - } - - // rjf: allocate, fill, & insert new cfg for this metadesk node - RD_Cfg *dst_n = rd_cfg_alloc(); - rd_cfg_equip_string(dst_n, dst_n_string); - if(dst_active_parent_n != &rd_nil_cfg) - { - rd_cfg_insert_child(dst_active_parent_n, dst_active_parent_n->last, dst_n); - } - - // rjf: recurse - rec = md_node_rec_depth_first_pre(src_n, tln); - if(dst_active_parent_n == &rd_nil_cfg) - { - dst_root_n = dst_n; - } - if(rec.push_count > 0) - { - dst_active_parent_n = dst_n; - } - else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) - { - dst_active_parent_n = dst_active_parent_n->parent; - } - } - rd_cfg_list_push(arena, &result, dst_root_n); - } - scratch_end(scratch); - return result; -} - -internal String8 -rd_string_from_cfg_tree(Arena *arena, String8 root_path, RD_Cfg *cfg) -{ - Temp scratch = scratch_begin(&arena, 1); - String8List strings = {0}; - { - typedef struct NestTask NestTask; - struct NestTask - { - NestTask *next; - RD_Cfg *cfg; - MD_Node *schema; - B32 is_simple; - }; - NestTask *top_nest_task = 0; - RD_CfgRec rec = {0}; - for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rec.next) - { - // rjf: look up parent's schemas - MD_NodePtrList schemas = {0}; - if(top_nest_task != 0) - { - RD_Cfg *parent = top_nest_task->cfg; - schemas = rd_schemas_from_name(parent->string); - } - - // rjf: look up child schema - MD_Node *c_schema = &md_nil_node; - for(MD_NodePtrNode *n = schemas.first; n != 0 && c_schema == &md_nil_node; n = n->next) - { - c_schema = md_child_from_string(n->v, c->string, 0); - } - - // rjf: push name of this node - if(c->string.size != 0 || c->first == &rd_nil_cfg) - { - // rjf: extract the textualized form for this string (we may need to escape / relativize) - String8 c_serialized_string = c->string; - { - MD_Node *c_schema = &md_nil_node; - if(top_nest_task != 0) - { - c_schema = top_nest_task->schema; - } - - // rjf: paths -> relativize - if(!md_node_has_tag(c_schema->first, str8_lit("no_relativize"), 0)) - { - if(str8_match(c_schema->first->string, str8_lit("path"), 0)) - { - String8 path_absolute = c->string; - String8 path_relative = path_relative_dst_from_absolute_dst_src(arena, path_absolute, root_path); - c_serialized_string = path_relative; - } - else if(str8_match(c_schema->first->string, str8_lit("path_pt"), 0)) - { - String8 value = c->string; - String8TxtPtPair parts = str8_txt_pt_pair_from_string(value); - String8 path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, parts.string, root_path); - c_serialized_string = push_str8f(arena, "%S:%I64d:%I64d", path_relative, parts.pt.line, parts.pt.column); - } - } - - // rjf: all strings -> escape - c_serialized_string = escaped_from_raw_str8(arena, c_serialized_string); - } - - // rjf: generate all strings for this node's string - String8List c_name_strings = {0}; - { - B32 name_can_be_pushed_standalone = 0; - { - Temp temp = temp_begin(scratch.arena); - MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c_serialized_string); - name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier| - MD_TokenFlag_Numeric| - MD_TokenFlag_StringLiteral| - MD_TokenFlag_Symbol)); - temp_end(temp); - } - if(name_can_be_pushed_standalone) - { - str8_list_push(scratch.arena, &c_name_strings, c_serialized_string); - } - else - { - str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); - str8_list_push(scratch.arena, &c_name_strings, c_serialized_string); - str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); - } - } - - // rjf: if we're in a simple nesting task, then just break children by space - if(top_nest_task != 0 && top_nest_task->is_simple) - { - str8_list_push(scratch.arena, &strings, str8_lit(" ")); - } - - // rjf: join c's strings with main string list - str8_list_concat_in_place(&strings, &c_name_strings); - } - - // rjf: grab next recursion - rec = rd_cfg_rec__depth_first(cfg, c); - - // rjf: push a new nesting task before descending to children - if(c->first != &rd_nil_cfg) - { - B32 is_simple_children_list = 1; - for(RD_Cfg *child = c->first; child != &rd_nil_cfg; child = child->next) - { - if(child->first != &rd_nil_cfg && child != c->last) - { - is_simple_children_list = 0; - break; - } - } - NestTask *task = push_array(scratch.arena, NestTask, 1); - task->cfg = c; - task->schema = c_schema; - task->is_simple = is_simple_children_list; - SLLStackPush(top_nest_task, task); - } - - // rjf: tree navigations -> encode hierarchy - if(rec.push_count > 0) - { - if(top_nest_task->is_simple && c->string.size != 0) - { - str8_list_push(scratch.arena, &strings, str8_lit(":")); - } - else - { - if(c->string.size != 0) - { - str8_list_push(scratch.arena, &strings, str8_lit(":\n")); - } - str8_list_push(scratch.arena, &strings, str8_lit("{")); - } - } - else - { - for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, SLLStackPop(top_nest_task)) - { - if(top_nest_task->is_simple) - { - if(top_nest_task->cfg->string.size == 0) - { - str8_list_push(scratch.arena, &strings, str8_lit(" }")); - } - } - else - { - str8_list_push(scratch.arena, &strings, str8_lit("\n}")); - } - } - } - if(!top_nest_task || top_nest_task->is_simple == 0) - { - str8_list_push(scratch.arena, &strings, str8_lit("\n")); - } - } - } - String8 result_unindented = str8_list_join(scratch.arena, &strings, 0); - String8 result = indented_from_string(arena, result_unindented); - scratch_end(scratch); - return result; -} - -internal RD_CfgRec -rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg) -{ - RD_CfgRec rec = {&rd_nil_cfg}; - if(cfg->first != &rd_nil_cfg) - { - rec.next = cfg->first; - rec.push_count = 1; - } - else for(RD_Cfg *p = cfg; p != root; p = p->parent, rec.pop_count += 1) - { - if(p->next != &rd_nil_cfg) - { - rec.next = p->next; - break; - } - } - return rec; -} - -internal void -rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg) -{ - RD_CfgNode *n = push_array(arena, RD_CfgNode, 1); - n->v = cfg; - DLLPushBack(list->first, list->last, n); - list->count += 1; -} - -internal void -rd_cfg_list_push_front(Arena *arena, RD_CfgList *list, RD_Cfg *cfg) -{ - RD_CfgNode *n = push_array(arena, RD_CfgNode, 1); - n->v = cfg; - if(list->first != 0) - { - n->next = list->first; - } - else - { - list->last = n; - } - list->first = n; - list->count += 1; -} +//~ rjf: Config Functions internal RD_PanelTree -rd_panel_tree_from_cfg(Arena *arena, RD_Cfg *cfg) +rd_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root) { Temp scratch = scratch_begin(&arena, 1); - RD_Cfg *wcfg = rd_window_from_cfg(cfg); - RD_Cfg *src_root = rd_cfg_child_from_string(wcfg, str8_lit("panels")); + CFG_Node *wcfg = rd_window_from_cfg(cfg_root); + CFG_Node *src_root = cfg_node_child_from_string(wcfg, str8_lit("panels")); RD_PanelNode *dst_root = &rd_nil_panel_node; RD_PanelNode *dst_focused = &rd_nil_panel_node; { - Axis2 active_split_axis = rd_cfg_child_from_string(wcfg, str8_lit("split_x")) != &rd_nil_cfg ? Axis2_X : Axis2_Y; - RD_CfgRec rec = {0}; + Axis2 active_split_axis = cfg_node_child_from_string(wcfg, str8_lit("split_x")) != &cfg_nil_node ? Axis2_X : Axis2_Y; + CFG_NodeRec rec = {0}; RD_PanelNode *dst_active_parent = &rd_nil_panel_node; - for(RD_Cfg *src = src_root; src != &rd_nil_cfg; src = rec.next) + for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next) { // rjf: build a panel node RD_PanelNode *dst = push_array(arena, RD_PanelNode, 1); @@ -906,9 +180,9 @@ rd_panel_tree_from_cfg(Arena *arena, RD_Cfg *cfg) B32 panel_has_children = 0; dst->cfg = src; dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string)); - dst->tab_side = (rd_cfg_child_from_string(src, str8_lit("tabs_on_bottom")) != &rd_nil_cfg ? Side_Max : Side_Min); + dst->tab_side = (cfg_node_child_from_string(src, str8_lit("tabs_on_bottom")) != &cfg_nil_node ? Side_Max : Side_Min); dst->split_axis = active_split_axis; - for(RD_Cfg *src_child = src->first; src_child != &rd_nil_cfg; src_child = src_child->next) + for(CFG_Node *src_child = src->first; src_child != &cfg_nil_node; src_child = src_child->next) { MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string); if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric) @@ -925,8 +199,8 @@ rd_panel_tree_from_cfg(Arena *arena, RD_Cfg *cfg) } else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier) { - rd_cfg_list_push(arena, &dst->tabs, src_child); - if(rd_cfg_child_from_string(src_child, str8_lit("selected")) != &rd_nil_cfg) + cfg_node_ptr_list_push(arena, &dst->tabs, src_child); + if(cfg_node_child_from_string(src_child, str8_lit("selected")) != &cfg_nil_node) { dst->selected_tab = src_child; } @@ -934,14 +208,14 @@ rd_panel_tree_from_cfg(Arena *arena, RD_Cfg *cfg) } // rjf: recurse - rec = rd_cfg_rec__depth_first(src_root, src); + rec = cfg_node_rec__depth_first(src_root, src); if(!panel_has_children) { MemoryZeroStruct(&rec); - rec.next = &rd_nil_cfg; - for(RD_Cfg *p = src; p != src_root && p != &rd_nil_cfg; p = p->parent, rec.pop_count += 1) + rec.next = &cfg_nil_node; + for(CFG_Node *p = src; p != src_root && p != &cfg_nil_node; p = p->parent, rec.pop_count += 1) { - if(p->next != &rd_nil_cfg) + if(p->next != &cfg_nil_node) { rec.next = p->next; break; @@ -986,7 +260,7 @@ rd_panel_node_rec__depth_first(RD_PanelNode *root, RD_PanelNode *panel, U64 sib_ } internal RD_PanelNode * -rd_panel_node_from_tree_cfg(RD_PanelNode *root, RD_Cfg *cfg) +rd_panel_node_from_tree_cfg(RD_PanelNode *root, CFG_Node *cfg) { RD_PanelNode *result = &rd_nil_panel_node; for(RD_PanelNode *p = root; @@ -1075,10 +349,10 @@ rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNo } internal B32 -rd_cfg_is_project_filtered(RD_Cfg *cfg) +rd_cfg_is_project_filtered(CFG_Node *cfg) { - RD_Cfg *project = rd_cfg_child_from_string(cfg, str8_lit("project")); - B32 result = (project != &rd_nil_cfg && !path_match_normalized(rd_state->project_path, project->first->string)); + CFG_Node *project = cfg_node_child_from_string(cfg, str8_lit("project")); + B32 result = (project != &cfg_nil_node && !path_match_normalized(rd_state->project_path, project->first->string)); return result; } @@ -1125,14 +399,14 @@ rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding) } internal Vec4F32 -rd_hsva_from_cfg(RD_Cfg *cfg) +rd_hsva_from_cfg(CFG_Node *cfg) { Vec4F32 hsva = {0}; - RD_Cfg *hsva_root = rd_cfg_child_from_string(cfg, str8_lit("hsva")); - RD_Cfg *h = hsva_root->first; - RD_Cfg *s = h->next; - RD_Cfg *v = s->next; - RD_Cfg *a = v->next; + CFG_Node *hsva_root = cfg_node_child_from_string(cfg, str8_lit("hsva")); + CFG_Node *h = hsva_root->first; + CFG_Node *s = h->next; + CFG_Node *v = s->next; + CFG_Node *a = v->next; hsva.x = (F32)f64_from_str8(h->string); hsva.y = (F32)f64_from_str8(s->string); hsva.z = (F32)f64_from_str8(v->string); @@ -1141,7 +415,7 @@ rd_hsva_from_cfg(RD_Cfg *cfg) } internal Vec4F32 -rd_color_from_cfg(RD_Cfg *cfg) +rd_color_from_cfg(CFG_Node *cfg) { Vec4F32 hsva = rd_hsva_from_cfg(cfg); Vec4F32 rgba = linear_from_srgba(rgba_from_hsva(hsva)); @@ -1149,16 +423,17 @@ rd_color_from_cfg(RD_Cfg *cfg) } internal B32 -rd_disabled_from_cfg(RD_Cfg *cfg) +rd_disabled_from_cfg(CFG_Node *cfg) { + Temp scratch = scratch_begin(0, 0); MD_Node *child_schema = &md_nil_node; - MD_NodePtrList schemas = rd_schemas_from_name(cfg->string); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, cfg->string); for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) { child_schema = md_child_from_string(n->v, str8_lit("enabled"), 0); } MD_Node *default_tag = md_tag_from_string(child_schema, str8_lit("default"), 0); - String8 value_string = rd_cfg_child_from_string(cfg, str8_lit("enabled"))->first->string; + String8 value_string = cfg_node_child_from_string(cfg, str8_lit("enabled"))->first->string; if(value_string.size == 0) { value_string = default_tag->first->string; @@ -1169,23 +444,24 @@ rd_disabled_from_cfg(RD_Cfg *cfg) { is_disabled = 0; } + scratch_end(scratch); return is_disabled; } internal RD_Location -rd_location_from_cfg(RD_Cfg *cfg) +rd_location_from_cfg(CFG_Node *cfg) { RD_Location dst_loc = {0}; { - RD_Cfg *src_loc = rd_cfg_child_from_string(cfg, str8_lit("source_location")); - RD_Cfg *addr_loc = rd_cfg_child_from_string(cfg, str8_lit("address_location")); - if(src_loc != &rd_nil_cfg) + CFG_Node *src_loc = cfg_node_child_from_string(cfg, str8_lit("source_location")); + CFG_Node *addr_loc = cfg_node_child_from_string(cfg, str8_lit("address_location")); + if(src_loc != &cfg_nil_node) { String8TxtPtPair loc_description = str8_txt_pt_pair_from_string(src_loc->first->string); dst_loc.file_path = loc_description.string; dst_loc.pt = loc_description.pt; } - else if(addr_loc != &rd_nil_cfg) + else if(addr_loc != &cfg_nil_node) { dst_loc.expr = addr_loc->first->string; } @@ -1194,42 +470,42 @@ rd_location_from_cfg(RD_Cfg *cfg) } internal String8 -rd_label_from_cfg(RD_Cfg *cfg) +rd_label_from_cfg(CFG_Node *cfg) { - RD_Cfg *label_root = rd_cfg_child_from_string(cfg, str8_lit("label")); + CFG_Node *label_root = cfg_node_child_from_string(cfg, str8_lit("label")); String8 result = label_root->first->string; return result; } internal String8 -rd_expr_from_cfg(RD_Cfg *cfg) +rd_expr_from_cfg(CFG_Node *cfg) { - RD_Cfg *expr_root = rd_cfg_child_from_string(cfg, str8_lit("expression")); + CFG_Node *expr_root = cfg_node_child_from_string(cfg, str8_lit("expression")); String8 result = expr_root->first->string; return result; } internal String8 -rd_path_from_cfg(RD_Cfg *cfg) +rd_path_from_cfg(CFG_Node *cfg) { - RD_Cfg *root = rd_cfg_child_from_string(cfg, str8_lit("path")); + CFG_Node *root = cfg_node_child_from_string(cfg, str8_lit("path")); String8 result = root->first->string; return result; } internal D_Target -rd_target_from_cfg(Arena *arena, RD_Cfg *cfg) +rd_target_from_cfg(Arena *arena, CFG_Node *cfg) { D_Target target = {0}; - target.exe = rd_cfg_child_from_string(cfg, str8_lit("executable"))->first->string; - target.args = rd_cfg_child_from_string(cfg, str8_lit("arguments"))->first->string; - target.working_directory = rd_cfg_child_from_string(cfg, str8_lit("working_directory"))->first->string; - target.custom_entry_point_name = rd_cfg_child_from_string(cfg, str8_lit("entry_point"))->first->string; - target.stdout_path = rd_cfg_child_from_string(cfg, str8_lit("stdout_path"))->first->string; - target.stderr_path = rd_cfg_child_from_string(cfg, str8_lit("stderr_path"))->first->string; - target.stdin_path = rd_cfg_child_from_string(cfg, str8_lit("stdin_path"))->first->string; - target.debug_subprocesses = !!e_value_from_string(rd_cfg_child_from_string(cfg, str8_lit("debug_subprocesses"))->first->string).u64; - for(RD_Cfg *child = cfg->first; child != &rd_nil_cfg; child = child->next) + target.exe = cfg_node_child_from_string(cfg, str8_lit("executable"))->first->string; + target.args = cfg_node_child_from_string(cfg, str8_lit("arguments"))->first->string; + target.working_directory = cfg_node_child_from_string(cfg, str8_lit("working_directory"))->first->string; + target.custom_entry_point_name = cfg_node_child_from_string(cfg, str8_lit("entry_point"))->first->string; + target.stdout_path = cfg_node_child_from_string(cfg, str8_lit("stdout_path"))->first->string; + target.stderr_path = cfg_node_child_from_string(cfg, str8_lit("stderr_path"))->first->string; + target.stdin_path = cfg_node_child_from_string(cfg, str8_lit("stdin_path"))->first->string; + target.debug_subprocesses = !!e_value_from_string(cfg_node_child_from_string(cfg, str8_lit("debug_subprocesses"))->first->string).u64; + for(CFG_Node *child = cfg->first; child != &cfg_nil_node; child = child->next) { if(str8_match(child->string, str8_lit("environment"), 0)) { @@ -1239,28 +515,14 @@ rd_target_from_cfg(Arena *arena, RD_Cfg *cfg) return target; } -internal MD_NodePtrList -rd_schemas_from_name(String8 name) -{ - MD_NodePtrList schemas = {0}; - for EachElement(idx, rd_name_schema_info_table) - { - if(str8_match(name, rd_name_schema_info_table[idx].name, 0)) - { - schemas = rd_state->schemas[idx]; - break; - } - } - return schemas; -} - internal String8 rd_default_setting_from_names(String8 schema_name, String8 setting_name) { String8 result = {0}; { + Temp scratch = scratch_begin(0, 0); MD_Node *setting_schema = &md_nil_node; - MD_NodePtrList schemas = rd_schemas_from_name(schema_name); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, schema_name); for(MD_NodePtrNode *n = schemas.first; n != 0 && setting_schema == &md_nil_node; n = n->next) { setting_schema = md_child_from_string(n->v, setting_name, 0); @@ -1273,6 +535,7 @@ rd_default_setting_from_names(String8 schema_name, String8 setting_name) result = default_tag->first->string; } } + scratch_end(scratch); } return result; } @@ -1290,33 +553,33 @@ rd_setting_from_name(String8 name) struct CfgSeedTask { CfgSeedTask *next; - RD_Cfg *cfg; + CFG_Node *cfg; B32 allow_bucket_chains; }; - RD_Cfg *view_cfg = rd_cfg_from_id(rd_regs()->view); - if(view_cfg == &rd_nil_cfg) + CFG_Node *view_cfg = cfg_node_from_id(rd_regs()->view); + if(view_cfg == &cfg_nil_node) { - view_cfg = rd_cfg_from_id(rd_regs()->tab); + view_cfg = cfg_node_from_id(rd_regs()->tab); } - CfgSeedTask panel_task = {0, &rd_nil_cfg, 1}; - if(panel_task.cfg == &rd_nil_cfg) { panel_task.cfg = rd_cfg_from_id(rd_regs()->panel); } - if(panel_task.cfg == &rd_nil_cfg) { panel_task.cfg = rd_cfg_from_id(rd_regs()->window); } + CfgSeedTask panel_task = {0, &cfg_nil_node, 1}; + if(panel_task.cfg == &cfg_nil_node) { panel_task.cfg = cfg_node_from_id(rd_regs()->panel); } + if(panel_task.cfg == &cfg_nil_node) { panel_task.cfg = cfg_node_from_id(rd_regs()->window); } CfgSeedTask view_task = {&panel_task, view_cfg, 1}; CfgSeedTask *first_task = &view_task; CfgSeedTask *last_task = &panel_task; // rjf: for each task, look for the setting, follow parent chain upwards - RD_Cfg *setting = &rd_nil_cfg; + CFG_Node *setting = &cfg_nil_node; for(CfgSeedTask *t = first_task; t != 0; t = t->next) { - for(RD_Cfg *cfg = t->cfg; cfg != &rd_nil_cfg; cfg = cfg->parent) + for(CFG_Node *cfg = t->cfg; cfg != &cfg_nil_node; cfg = cfg->parent) { - setting = rd_cfg_child_from_string(cfg, name); - if(setting != &rd_nil_cfg) + setting = cfg_node_child_from_string(cfg, name); + if(setting != &cfg_nil_node) { goto break_all; } - if(cfg->parent == rd_state->root_cfg && t->allow_bucket_chains) + if(cfg->parent == cfg_node_root() && t->allow_bucket_chains) { String8 next_bucket = {0}; B32 allow_bucket_chains = 0; @@ -1337,7 +600,7 @@ rd_setting_from_name(String8 name) { CfgSeedTask *task = push_array(scratch.arena, CfgSeedTask, 1); SLLQueuePush(first_task, last_task, task); - task->cfg = rd_cfg_child_from_string(rd_state->root_cfg, next_bucket); + task->cfg = cfg_node_child_from_string(cfg_node_root(), next_bucket); task->allow_bucket_chains = allow_bucket_chains; } } @@ -1353,7 +616,7 @@ rd_setting_from_name(String8 name) { for(CfgSeedTask *t = first_task; t != 0; t = t->next) { - for(RD_Cfg *cfg = t->cfg; cfg != &rd_nil_cfg; cfg = cfg->parent) + for(CFG_Node *cfg = t->cfg; cfg != &cfg_nil_node; cfg = cfg->parent) { result = rd_default_setting_from_names(cfg->string, name); if(result.size != 0) @@ -1418,41 +681,41 @@ rd_setting_f32_from_name(String8 name) return result; } -internal RD_Cfg * +internal CFG_Node * rd_immediate_cfg_from_key(String8 string) { - RD_Cfg *transient = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); - RD_Cfg *immediate = &rd_nil_cfg; - RD_Cfg *cfg = &rd_nil_cfg; - for(RD_Cfg *child = transient->first; child != &rd_nil_cfg; child = child->next) + CFG_Node *transient = cfg_node_child_from_string(cfg_node_root(), str8_lit("transient")); + CFG_Node *immediate = &cfg_nil_node; + CFG_Node *cfg = &cfg_nil_node; + for(CFG_Node *child = transient->first; child != &cfg_nil_node; child = child->next) { if(str8_match(child->string, str8_lit("immediate"), 0)) { - cfg = rd_cfg_child_from_string(child, string); - if(cfg != &rd_nil_cfg) + cfg = cfg_node_child_from_string(child, string); + if(cfg != &cfg_nil_node) { immediate = child; break; } } } - if(cfg == &rd_nil_cfg) + if(cfg == &cfg_nil_node) { - immediate = rd_cfg_new(transient, str8_lit("immediate")); - cfg = rd_cfg_new(immediate, string); + immediate = cfg_node_new(rd_state->cfg, transient, str8_lit("immediate")); + cfg = cfg_node_new(rd_state->cfg, immediate, string); } - rd_cfg_child_from_string_or_alloc(immediate, str8_lit("hot")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, immediate, str8_lit("hot")); return cfg; } -internal RD_Cfg * +internal CFG_Node * rd_immediate_cfg_from_keyf(char *fmt, ...) { Temp scratch = scratch_begin(0, 0); va_list args; va_start(args, fmt); String8 key = push_str8fv(scratch.arena, fmt, args); - RD_Cfg *result = rd_immediate_cfg_from_key(key); + CFG_Node *result = rd_immediate_cfg_from_key(key); va_end(args); scratch_end(scratch); return result; @@ -1465,13 +728,13 @@ rd_mapped_from_file_path(Arena *arena, String8 file_path) if(file_path.size != 0) { String8List file_path_parts = str8_split_path(scratch.arena, file_path); - RD_CfgList maps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); + CFG_NodePtrList maps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); String8 best_map_dst = {0}; U64 best_map_match_length = max_U64; String8Node *best_map_remaining_suffix_first = 0; - for(RD_CfgNode *n = maps.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = maps.first; n != 0; n = n->next) { - String8 map_src = rd_cfg_child_from_string(n->v, str8_lit("source"))->first->string; + String8 map_src = cfg_node_child_from_string(n->v, str8_lit("source"))->first->string; String8List map_src_parts = str8_split_path(scratch.arena, map_src); B32 matches = 1; U64 match_length = 0; @@ -1490,7 +753,7 @@ rd_mapped_from_file_path(Arena *arena, String8 file_path) if(matches && match_length < best_map_match_length) { best_map_match_length = match_length; - best_map_dst = rd_cfg_child_from_string(n->v, str8_lit("dest"))->first->string; + best_map_dst = cfg_node_child_from_string(n->v, str8_lit("dest"))->first->string; best_map_remaining_suffix_first = file_path_part_n; } } @@ -1531,13 +794,13 @@ rd_possible_overrides_from_file_path(Arena *arena, String8 file_path) PathStyle pth_style = PathStyle_Relative; String8List pth_parts = path_normalized_list_from_string(scratch.arena, file_path, &pth_style); { - RD_CfgList links = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); - for(RD_CfgNode *n = links.first; n != 0; n = n->next) + CFG_NodePtrList links = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); + for(CFG_NodePtrNode *n = links.first; n != 0; n = n->next) { //- rjf: unpack link - RD_Cfg *link = n->v; - RD_Cfg *src = rd_cfg_child_from_string(link, str8_lit("source")); - RD_Cfg *dst = rd_cfg_child_from_string(link, str8_lit("dest")); + CFG_Node *link = n->v; + CFG_Node *src = cfg_node_child_from_string(link, str8_lit("source")); + CFG_Node *dst = cfg_node_child_from_string(link, str8_lit("dest")); PathStyle src_style = PathStyle_Relative; PathStyle dst_style = PathStyle_Relative; String8List src_parts = path_normalized_list_from_string(scratch.arena, src->first->string, &src_style); @@ -1635,20 +898,20 @@ rd_name_from_ctrl_entity(Arena *arena, CTRL_Entity *entity) //- rjf: cfg <-> eval space -internal RD_Cfg * +internal CFG_Node * rd_cfg_from_eval_space(E_Space space) { - RD_Cfg *cfg = &rd_nil_cfg; + CFG_Node *cfg = &cfg_nil_node; if(space.kind == RD_EvalSpaceKind_MetaCfg) { CFG_ID id = space.u64s[0]; - cfg = rd_cfg_from_id(id); + cfg = cfg_node_from_id(id); } return cfg; } internal E_Space -rd_eval_space_from_cfg(RD_Cfg *cfg) +rd_eval_space_from_cfg(CFG_Node *cfg) { E_Space space = e_space_make(RD_EvalSpaceKind_MetaCfg); space.u64s[0] = cfg->id; @@ -1710,7 +973,7 @@ rd_eval_space_gen(E_Space space) case RD_EvalSpaceKind_MetaCfg: case RD_EvalSpaceKind_MetaQuery: { - result = rd_state->cfg_change_gen; + result = cfg_change_gen(); }break; } return result; @@ -1769,19 +1032,19 @@ rd_eval_space_read(E_Space space, void *out, Rng1U64 range) case RD_EvalSpaceKind_MetaCfg: { // rjf: unpack cfg - RD_Cfg *root_cfg = rd_cfg_from_eval_space(space); + CFG_Node *root_cfg = rd_cfg_from_eval_space(space); String8 child_key = e_string_from_id(space.u64s[1]); - RD_Cfg *cfg = root_cfg; + CFG_Node *cfg = root_cfg; if(child_key.size != 0) { - cfg = rd_cfg_child_from_string(root_cfg, child_key); + cfg = cfg_node_child_from_string(root_cfg, child_key); } // rjf: determine data to read from, depending on child type in schema String8 read_data = {0}; if(child_key.size != 0) { - MD_NodePtrList schemas = rd_schemas_from_name(root_cfg->string); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, root_cfg->string); MD_Node *expr_child_schema = &md_nil_node; MD_Node *child_schema = &md_nil_node; for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) @@ -1810,10 +1073,10 @@ rd_eval_space_read(E_Space space, void *out, Rng1U64 range) } if(value_string.size == 0 && !md_node_is_nil(md_tag_from_string(child_schema, str8_lit("override"), 0))) { - for(RD_Cfg *parent = root_cfg->parent; parent != &rd_nil_cfg; parent = parent->parent) + for(CFG_Node *parent = root_cfg->parent; parent != &cfg_nil_node; parent = parent->parent) { - RD_Cfg *parent_child_w_key = rd_cfg_child_from_string(parent, child_key); - if(parent_child_w_key != &rd_nil_cfg) + CFG_Node *parent_child_w_key = cfg_node_child_from_string(parent, child_key); + if(parent_child_w_key != &cfg_nil_node) { value_string = parent_child_w_key->first->string; break; @@ -1828,7 +1091,7 @@ rd_eval_space_read(E_Space space, void *out, Rng1U64 range) E_Key parent_key = {0}; if(expr_child_schema != &md_nil_node && child_schema != expr_child_schema) { - parent_key = e_key_from_string(rd_cfg_child_from_string(root_cfg, expr_child_schema->string)->first->string); + parent_key = e_key_from_string(cfg_node_child_from_string(root_cfg, expr_child_schema->string)->first->string); } E_ParentKey(parent_key) { @@ -1883,7 +1146,7 @@ rd_eval_space_read(E_Space space, void *out, Rng1U64 range) String8 read_data = {0}; if(child_key.size != 0) { - MD_NodePtrList schemas = rd_schemas_from_name(ctrl_entity_kind_code_name_table[entity->kind]); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, ctrl_entity_kind_code_name_table[entity->kind]); MD_Node *child_schema = &md_nil_node; for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) { @@ -1972,13 +1235,13 @@ rd_eval_space_write(E_Space space, void *in, Rng1U64 range) String8 write_string = str8_cstring_capped(in, (U8 *)in + dim_1u64(range)); // rjf: unpack cfg - RD_Cfg *root_cfg = rd_cfg_from_eval_space(space); + CFG_Node *root_cfg = rd_cfg_from_eval_space(space); String8 child_key = e_string_from_id(space.u64s[1]); // rjf: no child key? -> overwrite child string if(child_key.size == 0) { - rd_cfg_new_replace(root_cfg, write_string); + cfg_node_new_replace(rd_state->cfg, root_cfg, write_string); } // rjf: child key -> look up & edit child @@ -2002,14 +1265,14 @@ rd_eval_space_write(E_Space space, void *in, Rng1U64 range) // rjf: zero-range? delete child if(range.min == range.max) { - rd_cfg_release(rd_cfg_child_from_string(root_cfg, child_key)); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(root_cfg, child_key)); } // rjf: non-zero-range? create child if needed & write value else { - RD_Cfg *child_cfg = rd_cfg_child_from_string_or_alloc(root_cfg, child_key); - rd_cfg_new_replace(child_cfg, write_string); + CFG_Node *child_cfg = cfg_node_child_from_string_or_alloc(rd_state->cfg, root_cfg, child_key); + cfg_node_new_replace(rd_state->cfg, child_cfg, write_string); } } }break; @@ -2029,7 +1292,7 @@ rd_eval_space_write(E_Space space, void *in, Rng1U64 range) // rjf: perform write, based on child name in schema if(child_key.size != 0) { - MD_NodePtrList schemas = rd_schemas_from_name(ctrl_entity_kind_code_name_table[entity->kind]); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, ctrl_entity_kind_code_name_table[entity->kind]); MD_Node *child_schema = &md_nil_node; for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) { @@ -2346,8 +1609,8 @@ rd_query_from_eval_string(Arena *arena, String8 string) //////////////////////////////// //~ rjf: View Functions -internal RD_Cfg * -rd_view_from_eval(RD_Cfg *parent, E_Eval eval) +internal CFG_Node * +rd_view_from_eval(CFG_Node *parent, E_Eval eval) { Temp scratch = scratch_begin(0, 0); E_TypeKey type_key = eval.irtree.type_key; @@ -2363,8 +1626,8 @@ rd_view_from_eval(RD_Cfg *parent, E_Eval eval) type_is_visualizer = 1; } } - RD_Cfg *view = rd_cfg_child_from_string_or_alloc(parent, schema_name); - rd_cfg_child_from_string_or_alloc(view, str8_lit("selected")); + CFG_Node *view = cfg_node_child_from_string_or_alloc(rd_state->cfg, parent, schema_name); + cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("selected")); { // rjf: get expression evaluation // TODO(rjf): we need to account for UFCS style expressions here... @@ -2384,10 +1647,10 @@ rd_view_from_eval(RD_Cfg *parent, E_Eval eval) } // rjf: reflect expr & arguments in cfg tree - RD_Cfg *expr_root = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); - rd_cfg_new_replace(expr_root, e_full_expr_string_from_key(scratch.arena, expr_eval.key)); + CFG_Node *expr_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("expression")); + cfg_node_new_replace(rd_state->cfg, expr_root, e_full_expr_string_from_key(scratch.arena, expr_eval.key)); { - MD_NodePtrList schemas = rd_schemas_from_name(schema_name); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, schema_name); U64 unnamed_order_idx = 0; for EachIndex(arg_idx, args_count) { @@ -2418,8 +1681,8 @@ rd_view_from_eval(RD_Cfg *parent, E_Eval eval) } unnamed_order_idx += 1; } - RD_Cfg *arg_root = rd_cfg_child_from_string_or_alloc(view, param_name); - rd_cfg_new_replace(arg_root, e_string_from_expr(scratch.arena, arg_expr, str8_zero())); + CFG_Node *arg_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, param_name); + cfg_node_new_replace(rd_state->cfg, arg_root, e_string_from_expr(scratch.arena, arg_expr, str8_zero())); } } } @@ -2428,7 +1691,7 @@ rd_view_from_eval(RD_Cfg *parent, E_Eval eval) } internal RD_ViewState * -rd_view_state_from_cfg(RD_Cfg *cfg) +rd_view_state_from_cfg(CFG_Node *cfg) { RD_ViewState *view_state = &rd_nil_view_state; CFG_ID id = cfg->id; @@ -2503,12 +1766,12 @@ internal void rd_view_ui(Rng2F32 rect) { ProfBeginFunction(); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *vs = rd_view_state_from_cfg(view); String8 view_name = view->string; String8 expr_string = rd_expr_from_cfg(view); B32 view_is_floating = 0; - for(RD_Cfg *p = view->parent; p != &rd_nil_cfg; p = p->parent) + for(CFG_Node *p = view->parent; p != &cfg_nil_node; p = p->parent) { if(str8_match(p->string, str8_lit("immediate"), 0)) { @@ -2520,9 +1783,9 @@ rd_view_ui(Rng2F32 rect) ////////////////////////////// //- rjf: query extension // - RD_Cfg *query_root = rd_cfg_child_from_string(view, str8_lit("query")); - RD_Cfg *input_root = rd_cfg_child_from_string(query_root, str8_lit("input")); - RD_Cfg *cmd_root = rd_cfg_child_from_string(query_root, str8_lit("cmd")); + CFG_Node *query_root = cfg_node_child_from_string(view, str8_lit("query")); + CFG_Node *input_root = cfg_node_child_from_string(query_root, str8_lit("input")); + CFG_Node *cmd_root = cfg_node_child_from_string(query_root, str8_lit("cmd")); String8 current_input = input_root->first->string; B32 search_row_is_open = (vs->query_is_open); F32 search_row_open_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "search_row_open_%p", view), @@ -2614,11 +1877,11 @@ rd_view_ui(Rng2F32 rect) } //- rjf: commit string to view - if(input_root == &rd_nil_cfg) + if(input_root == &cfg_nil_node) { - input_root = rd_cfg_child_from_string_or_alloc(query_root, str8_lit("input")); + input_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, query_root, str8_lit("input")); } - rd_cfg_new_replace(input_root, str8(vs->query_buffer, vs->query_string_size)); + cfg_node_new_replace(rd_state->cfg, input_root, str8(vs->query_buffer, vs->query_string_size)); } ////////////////////////////// @@ -2648,7 +1911,7 @@ rd_view_ui(Rng2F32 rect) UI_Focus(UI_FocusKind_On) UI_WidthFill UI_HeightFill UI_NamedColumn(str8_lit("empty_view")) UI_Padding(ui_pct(1, 0)) UI_Focus(UI_FocusKind_Null) { - RD_CfgList targets = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("target")); + CFG_NodePtrList targets = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("target")); CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); //- rjf: icon & info @@ -2706,7 +1969,7 @@ rd_view_ui(Rng2F32 rect) //- rjf: user has 1 target. build helper for launching it case 1: { - RD_Cfg *target_cfg = rd_cfg_list_first(&targets); + CFG_Node *target_cfg = cfg_node_ptr_list_first(&targets); D_Target target = rd_target_from_cfg(scratch.arena, target_cfg); String8 target_full_path = target.exe; String8 target_name = str8_skip_last_slash(target_full_path); @@ -2864,8 +2127,8 @@ rd_view_ui(Rng2F32 rect) RD_Cmd *cmd = &cmd_node->cmd; rd_push_cmd(cmd->name, cmd->regs); } - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - rd_cfg_equip_string(view, new_view_name); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + cfg_node_equip_string(rd_state->cfg, view, new_view_name); RD_ViewState *vs = rd_view_state_from_cfg(view); for(RD_ArenaExt *ext = vs->first_arena_ext; ext != 0; ext = ext->next) { @@ -2944,7 +2207,7 @@ rd_view_ui(Rng2F32 rect) // the "collection of all watches", to build a watch window. but this behavior is not // as desirable if we are just using some other expression as the root. // - B32 implicit_root = (rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("explicit_root")) == &rd_nil_cfg); + B32 implicit_root = (cfg_node_child_from_string(cfg_node_from_id(rd_regs()->view), str8_lit("explicit_root")) == &cfg_nil_node); ////////////////////////////// //- rjf: determine autocompletion string @@ -3172,10 +2435,10 @@ rd_view_ui(Rng2F32 rect) if(evt->kind == UI_EventKind_Press && evt->slot == UI_EventActionSlot_Accept && selection_tbl.min.y == selection_tbl.max.y && - (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg)) + (cfg_node_child_from_string(view, str8_lit("lister")) != &cfg_nil_node)) { - RD_Cfg *query = rd_cfg_child_from_string(view, str8_lit("query")); - RD_Cfg *cmd = rd_cfg_child_from_string(query, str8_lit("cmd")); + CFG_Node *query = cfg_node_child_from_string(view, str8_lit("query")); + CFG_Node *cmd = cfg_node_child_from_string(query, str8_lit("cmd")); String8 cmd_name = cmd->first->string; // rjf: if we have no selection, just pick the first row @@ -3246,7 +2509,7 @@ rd_view_ui(Rng2F32 rect) }break; case RD_EvalSpaceKind_MetaCfg: { - RD_Cfg *cfg = rd_cfg_from_eval_space(eval.space); + CFG_Node *cfg = rd_cfg_from_eval_space(eval.space); rd_cmd(RD_CmdKind_CompleteQuery, .cfg = cfg->id); }break; case RD_EvalSpaceKind_MetaCtrlEntity: @@ -3328,7 +2591,7 @@ rd_view_ui(Rng2F32 rect) }break; case RD_EvalSpaceKind_MetaCfg: { - RD_Cfg *cfg = rd_cfg_from_eval_space(eval.space); + CFG_Node *cfg = rd_cfg_from_eval_space(eval.space); if(str8_match(cfg->string, str8_lit("recent_file"), 0)) { rd_cmd(RD_CmdKind_Switch, .cfg = cfg->id); @@ -3550,7 +2813,7 @@ rd_view_ui(Rng2F32 rect) if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0) { String8 autocomplete_string = ui_autocomplete(); - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; String8 new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(autocomp_cursor_info->replaced_range.min+1, autocomp_cursor_info->replaced_range.max+1), autocomplete_string); @@ -3588,32 +2851,32 @@ rd_view_ui(Rng2F32 rect) { if(cell->flags & RD_WatchCellFlag_Expr && cell->flags & RD_WatchCellFlag_NoEval) { - RD_Cfg *cfg = row_info.group_cfg_child; + CFG_Node *cfg = row_info.group_cfg_child; String8 child_key = {0}; // str8_lit("expression"); - if(cfg == &rd_nil_cfg && editing_complete && new_string.size != 0) + if(cfg == &cfg_nil_node && editing_complete && new_string.size != 0) { - RD_Cfg *new_cfg_parent = row_info.group_cfg_parent; - if(new_cfg_parent != &rd_nil_cfg) + CFG_Node *new_cfg_parent = row_info.group_cfg_parent; + if(new_cfg_parent != &cfg_nil_node) { child_key = str8_zero(); } - if(new_cfg_parent == &rd_nil_cfg) + if(new_cfg_parent == &cfg_nil_node) { - RD_CfgList all_cfgs = rd_cfg_top_level_list_from_string(scratch.arena, row_info.group_cfg_name); - new_cfg_parent = rd_cfg_list_last(&all_cfgs)->parent; + CFG_NodePtrList all_cfgs = cfg_node_top_level_list_from_string(scratch.arena, row_info.group_cfg_name); + new_cfg_parent = cfg_node_ptr_list_last(&all_cfgs)->parent; } - if(new_cfg_parent == &rd_nil_cfg) + if(new_cfg_parent == &cfg_nil_node) { - new_cfg_parent = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + new_cfg_parent = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); } - cfg = rd_cfg_new(new_cfg_parent, row_info.group_cfg_name); + cfg = cfg_node_new(rd_state->cfg, new_cfg_parent, row_info.group_cfg_name); state_dirty = 1; snap_to_cursor = 1; } - if(cfg != &rd_nil_cfg) + if(cfg != &cfg_nil_node) { - RD_Cfg *expr = child_key.size != 0 ? rd_cfg_child_from_string_or_alloc(cfg, child_key) : cfg; - rd_cfg_new_replace(expr, new_string); + CFG_Node *expr = child_key.size != 0 ? cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, child_key) : cfg; + cfg_node_new_replace(rd_state->cfg, expr, new_string); } } else @@ -3705,7 +2968,7 @@ rd_view_ui(Rng2F32 rect) taken = 1; state_dirty = 1; snap_to_cursor = 1; - RD_CfgList cfgs_to_remove = {0}; + CFG_NodePtrList cfgs_to_remove = {0}; RD_WatchPt next_cursor_pt = {0}; B32 next_cursor_set = 0; EV_WindowedRowList rows = ev_rows_from_num_range(scratch.arena, eval_view, &block_ranges, r1u64(selection_tbl.min.y, selection_tbl.max.y+1)); @@ -3724,10 +2987,10 @@ rd_view_ui(Rng2F32 rect) RD_WatchPt pt = {row->block->key, row->key, rd_id_from_watch_cell(cell)}; if(cell->flags & RD_WatchCellFlag_Expr && cell->flags & RD_WatchCellFlag_NoEval) { - RD_Cfg *cfg = row_info.group_cfg_child; - if(cfg != &rd_nil_cfg) + CFG_Node *cfg = row_info.group_cfg_child; + if(cfg != &cfg_nil_node) { - rd_cfg_list_push(scratch.arena, &cfgs_to_remove, cfg); + cfg_node_ptr_list_push(scratch.arena, &cfgs_to_remove, cfg); U64 deleted_num = ev_block_num_from_id(row->block, row->key.child_id); if(deleted_num != 0) { @@ -3758,9 +3021,9 @@ rd_view_ui(Rng2F32 rect) } } } - for(RD_CfgNode *n = cfgs_to_remove.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = cfgs_to_remove.first; n != 0; n = n->next) { - rd_cfg_release(n->v); + cfg_node_release(rd_state->cfg, n->v); } if(next_cursor_set) { @@ -3935,20 +3198,20 @@ rd_view_ui(Rng2F32 rect) } // rjf: map selection endpoints to cfgs - RD_Cfg *first_cfg = &rd_nil_cfg; - RD_Cfg *last_cfg = &rd_nil_cfg; + CFG_Node *first_cfg = &cfg_nil_node; + CFG_Node *last_cfg = &cfg_nil_node; if(group_cfg_name.size != 0) { - first_cfg = rd_cfg_from_id(selection_keys_in_block[0].child_id); - last_cfg = rd_cfg_from_id(selection_keys_in_block[1].child_id); + first_cfg = cfg_node_from_id(selection_keys_in_block[0].child_id); + last_cfg = cfg_node_from_id(selection_keys_in_block[1].child_id); } // rjf: reorder - if(first_cfg != &rd_nil_cfg && last_cfg != &rd_nil_cfg) + if(first_cfg != &cfg_nil_node && last_cfg != &cfg_nil_node) { - RD_Cfg *first_cfg_prev = &rd_nil_cfg; - RD_Cfg *last_cfg_next = &rd_nil_cfg; - for(RD_Cfg *prev = first_cfg->prev; prev != &rd_nil_cfg; prev = prev->prev) + CFG_Node *first_cfg_prev = &cfg_nil_node; + CFG_Node *last_cfg_next = &cfg_nil_node; + for(CFG_Node *prev = first_cfg->prev; prev != &cfg_nil_node; prev = prev->prev) { if(str8_match(prev->string, first_cfg->string, 0)) { @@ -3956,7 +3219,7 @@ rd_view_ui(Rng2F32 rect) break; } } - for(RD_Cfg *next = last_cfg->next; next != &rd_nil_cfg; next = next->next) + for(CFG_Node *next = last_cfg->next; next != &cfg_nil_node; next = next->next) { if(str8_match(next->string, last_cfg->string, 0)) { @@ -3964,21 +3227,21 @@ rd_view_ui(Rng2F32 rect) break; } } - if(evt->delta_2s32.y < 0 && first_cfg != &rd_nil_cfg && first_cfg_prev != &rd_nil_cfg) + if(evt->delta_2s32.y < 0 && first_cfg != &cfg_nil_node && first_cfg_prev != &cfg_nil_node) { state_dirty = 1; snap_to_cursor = 1; - RD_Cfg *parent = first_cfg_prev->parent; - rd_cfg_unhook(parent, first_cfg_prev); - rd_cfg_insert_child(parent, last_cfg, first_cfg_prev); + CFG_Node *parent = first_cfg_prev->parent; + cfg_node_unhook(rd_state->cfg, parent, first_cfg_prev); + cfg_node_insert_child(rd_state->cfg, parent, last_cfg, first_cfg_prev); } - if(evt->delta_2s32.y > 0 && last_cfg != &rd_nil_cfg && last_cfg_next != &rd_nil_cfg) + if(evt->delta_2s32.y > 0 && last_cfg != &cfg_nil_node && last_cfg_next != &cfg_nil_node) { state_dirty = 1; snap_to_cursor = 1; - RD_Cfg *parent = last_cfg_next->parent; - rd_cfg_unhook(parent, last_cfg_next); - rd_cfg_insert_child(parent, first_cfg_prev, last_cfg_next); + CFG_Node *parent = last_cfg_next->parent; + cfg_node_unhook(rd_state->cfg, parent, last_cfg_next); + cfg_node_insert_child(rd_state->cfg, parent, first_cfg_prev, last_cfg_next); } } } @@ -3998,7 +3261,7 @@ rd_view_ui(Rng2F32 rect) //- rjf: autocomplete watches -> feed autocompletion info forward // if(rd_watch_pt_match(ewv->cursor, ewv->mark) && - rd_cfg_child_from_string(view, str8_lit("autocomplete")) != &rd_nil_cfg) + cfg_node_child_from_string(view, str8_lit("autocomplete")) != &cfg_nil_node) { U64 row_num = ev_num_from_key(&block_ranges, ewv->cursor.key); EV_Row *row = ev_row_from_num(scratch.arena, rd_view_eval_view(), &block_ranges, row_num); @@ -4183,18 +3446,18 @@ rd_view_ui(Rng2F32 rect) max_pct__post = current_sum * (cell->next->default_pct / default_sum); ui_kill_action(); } - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string_or_alloc(view, row_info->cell_style_key); - RD_Cfg *min_cfg = &rd_nil_cfg; - RD_Cfg *max_cfg = &rd_nil_cfg; + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *style = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, row_info->cell_style_key); + CFG_Node *min_cfg = &cfg_nil_node; + CFG_Node *max_cfg = &cfg_nil_node; { - RD_Cfg *pct_child = style->first; + CFG_Node *pct_child = style->first; U64 c_idx = 0; for(RD_WatchCell *c = row_info->cells.first; c != 0; c = c->next, c_idx += 1) { - if(pct_child == &rd_nil_cfg) + if(pct_child == &cfg_nil_node) { - pct_child = rd_cfg_newf(style, "%f", c->pct); + pct_child = cfg_node_newf(rd_state->cfg, style, "%f", c->pct); } if(c_idx == cell_idx) { @@ -4206,8 +3469,8 @@ rd_view_ui(Rng2F32 rect) } pct_child = pct_child->next; } - rd_cfg_equip_stringf(min_cfg, "%f", min_pct__post); - rd_cfg_equip_stringf(max_cfg, "%f", max_pct__post); + cfg_node_equip_stringf(rd_state->cfg, min_cfg, "%f", min_pct__post); + cfg_node_equip_stringf(rd_state->cfg, max_cfg, "%f", max_pct__post); cell_pcts_are_dirty = 1; } } @@ -4306,8 +3569,8 @@ rd_view_ui(Rng2F32 rect) //- rjf: unpack block/previous row info B32 drag_target_is_good = 0; - RD_Cfg *drag_parent_cfg = &rd_nil_cfg; - RD_Cfg *drag_prev_cfg = &rd_nil_cfg; + CFG_Node *drag_parent_cfg = &cfg_nil_node; + CFG_Node *drag_prev_cfg = &cfg_nil_node; if(drag_block != &ev_nil_block) { EV_Key prev_row_key = ev_key_make(ev_hash_from_key(drag_block->key), ev_block_id_from_num(drag_block, best_prev_row_block_num)); @@ -4323,25 +3586,25 @@ rd_view_ui(Rng2F32 rect) } //- rjf: drop - if(drag_target_is_good && rd_drag_drop() && drag_parent_cfg != &rd_nil_cfg) + if(drag_target_is_good && rd_drag_drop() && drag_parent_cfg != &cfg_nil_node) { switch(drag_slot) { default:{}break; case RD_RegSlot_Expr: { - RD_Cfg *cfg = rd_cfg_from_id(drag_regs->cfg); - if(cfg != &rd_nil_cfg) + CFG_Node *cfg = cfg_node_from_id(drag_regs->cfg); + if(cfg != &cfg_nil_node) { - rd_cfg_unhook(cfg->parent, cfg); + cfg_node_unhook(rd_state->cfg, cfg->parent, cfg); } - if(cfg == &rd_nil_cfg) + if(cfg == &cfg_nil_node) { - cfg = rd_cfg_alloc(); - rd_cfg_equip_stringf(cfg, "watch"); - rd_cfg_new(cfg, drag_regs->expr); + cfg = cfg_node_alloc(rd_state->cfg); + cfg_node_equip_stringf(rd_state->cfg, cfg, "watch"); + cfg_node_new(rd_state->cfg, cfg, drag_regs->expr); } - rd_cfg_insert_child(drag_parent_cfg, drag_prev_cfg, cfg); + cfg_node_insert_child(rd_state->cfg, drag_parent_cfg, drag_prev_cfg, cfg); }break; } } @@ -4638,7 +3901,7 @@ rd_view_ui(Rng2F32 rect) if(cell_info.cfg->id == rd_get_hover_regs()->cfg && rd_state->hover_regs_slot == RD_RegSlot_Cfg) { - RD_Cfg *cfg = cell_info.cfg; + CFG_Node *cfg = cell_info.cfg; Vec4F32 rgba = rd_color_from_cfg(cfg); rgba.w *= 0.05f; if(rgba.w == 0) @@ -4700,7 +3963,7 @@ rd_view_ui(Rng2F32 rect) //////////// //- rjf: build cell contents // - RD_Cfg *cell_view = &rd_nil_cfg; + CFG_Node *cell_view = &cfg_nil_node; B32 revert_cell = 0; UI_Signal sig = {0}; ProfScope("build cell contents") @@ -4713,7 +3976,7 @@ rd_view_ui(Rng2F32 rect) //- rjf: cell has hook? -> build ui by calling hook if(cell->kind == RD_WatchCellKind_ViewUI && cell_info.view_ui_rule != &rd_nil_view_ui_rule) { - RD_Cfg *root = rd_immediate_cfg_from_keyf("view%I64x_%I64x", rd_regs()->view, row_hash); + CFG_Node *root = rd_immediate_cfg_from_keyf("view%I64x_%I64x", rd_regs()->view, row_hash); cell_view = rd_view_from_eval(root, cell->eval); Rng2F32 cell_rect = r2f32p(cell_x_px, row_y_px, next_cell_x_px, row_y_px + row_height_px*(row_node->visual_size_skipped + row->visual_size + row_node->visual_size_chopped)); ui_set_next_fixed_y(-1.f * (row_node->visual_size_skipped) * row_height_px); @@ -4868,12 +4131,12 @@ rd_view_ui(Rng2F32 rect) if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg && !(cell->flags & RD_WatchCellFlag_NoEval)) { - RD_Cfg *cfg = rd_cfg_from_eval_space(cell->eval.space); + CFG_Node *cfg = rd_cfg_from_eval_space(cell->eval.space); String8 child_key = e_string_from_id(cell->eval.space.u64s[1]); - RD_Cfg *child_cfg = rd_cfg_child_from_string(cfg, child_key); - if(child_cfg != &rd_nil_cfg) + CFG_Node *child_cfg = cfg_node_child_from_string(cfg, child_key); + if(child_cfg != &cfg_nil_node) { - MD_NodePtrList schemas = rd_schemas_from_name(cfg->string); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, cfg->string); if(schemas.count != 0) { MD_Node *child_schema = &md_nil_node; @@ -5055,7 +4318,7 @@ rd_view_ui(Rng2F32 rect) } // rjf: hover -> rich hover cfgs - if(ui_hovering(sig) && cell_info.cfg != &rd_nil_cfg) + if(ui_hovering(sig) && cell_info.cfg != &cfg_nil_node) { RD_RegsScope(.cfg = cell_info.cfg->id, .no_rich_tooltip = 1) rd_set_hover_regs(RD_RegSlot_Cfg); } @@ -5087,7 +4350,7 @@ rd_view_ui(Rng2F32 rect) String8 file_path = rd_file_path_from_eval(scratch.arena, cell->eval); RD_RegsScope(.file_path = file_path) rd_drag_begin(RD_RegSlot_FilePath); } - else if(cell_info.cfg != &rd_nil_cfg) + else if(cell_info.cfg != &cfg_nil_node) { RD_RegsScope(.cfg = cell_info.cfg->id) rd_drag_begin(RD_RegSlot_Cfg); } @@ -5128,9 +4391,9 @@ rd_view_ui(Rng2F32 rect) // rjf: reversion if(revert_cell && cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg) { - RD_Cfg *cfg = rd_cfg_from_eval_space(cell->eval.space); + CFG_Node *cfg = rd_cfg_from_eval_space(cell->eval.space); String8 child_key = e_string_from_id(cell->eval.space.u64s[1]); - rd_cfg_release(rd_cfg_child_from_string(cfg, child_key)); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(cfg, child_key)); } // rjf: activation (double-click normally, or single-clicks with special buttons) @@ -5149,12 +4412,12 @@ rd_view_ui(Rng2F32 rect) // if double-click: focus this visualizer (via edit) if(cell->kind == RD_WatchCellKind_ViewUI && cell_info.view_ui_rule != &rd_nil_view_ui_rule && - cell_view != &rd_nil_cfg) + cell_view != &cfg_nil_node) { if(!view_is_floating && sig.f & UI_SignalFlag_KeyboardPressed) { - rd_cfg_unhook(cell_view->parent, cell_view); - rd_cfg_insert_child(view->parent, view, cell_view); + cfg_node_unhook(rd_state->cfg, cell_view->parent, cell_view); + cfg_node_insert_child(rd_state->cfg, view->parent, view, cell_view); rd_cmd(RD_CmdKind_FocusTab, .tab = cell_view->id); } else if(sig.f & UI_SignalFlag_DoubleClicked) @@ -5169,8 +4432,8 @@ rd_view_ui(Rng2F32 rect) } // rjf: this watch window is a lister? -> move cursor & edit or accept - else if(rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg || - rd_cfg_child_from_string(view, str8_lit("autocomplete")) != &rd_nil_cfg) + else if(cfg_node_child_from_string(view, str8_lit("lister")) != &cfg_nil_node || + cfg_node_child_from_string(view, str8_lit("autocomplete")) != &cfg_nil_node) { ewv->next_cursor = ewv->next_mark = cell_pt; if(cell_info.flags & RD_WatchCellFlag_CanEdit) @@ -5195,8 +4458,8 @@ rd_view_ui(Rng2F32 rect) String8 cmd_name = cell_info.cmd_name; RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(row->eval.space); - RD_Cfg *cfg = rd_cfg_from_eval_space(row->eval.space); - if(cfg == &rd_nil_cfg) + CFG_Node *cfg = rd_cfg_from_eval_space(row->eval.space); + if(cfg == &cfg_nil_node) { cfg = rd_cfg_from_eval_space(row->block->eval.space); } @@ -5206,7 +4469,7 @@ rd_view_ui(Rng2F32 rect) } RD_RegsScope(.cfg = cfg->id, .ctrl_entity = entity->handle) { - if(cfg != &rd_nil_cfg) + if(cfg != &cfg_nil_node) { RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, cfg); RD_PanelNode *parent_panel_node = rd_panel_node_from_tree_cfg(panels.root, cfg->parent); @@ -5216,7 +4479,7 @@ rd_view_ui(Rng2F32 rect) } } if(!(cmd_kind_info->query.flags & RD_QueryFlag_Required) || - (cmd_kind_info->query.slot == RD_RegSlot_Cfg && cfg != &rd_nil_cfg) || + (cmd_kind_info->query.slot == RD_RegSlot_Cfg && cfg != &cfg_nil_node) || (cmd_kind_info->query.slot == RD_RegSlot_CtrlEntity && entity != &ctrl_entity_nil)) { rd_push_cmd(cell_info.cmd_name, rd_regs()); @@ -5283,9 +4546,9 @@ rd_view_ui(Rng2F32 rect) } // rjf: can't edit, but has cfg? -> find or select - else if(cell_info.cfg != &rd_nil_cfg) + else if(cell_info.cfg != &cfg_nil_node) { - RD_Cfg *cfg = cell_info.cfg; + CFG_Node *cfg = cell_info.cfg; RD_Location loc = rd_location_from_cfg(cfg); if(loc.file_path.size != 0) { @@ -5313,7 +4576,7 @@ rd_view_ui(Rng2F32 rect) } // rjf: other cases, but this watch window is floating, and this has a cfg/entity? -> push query - else if(view_is_floating && (cell_info.entity != &ctrl_entity_nil || cell_info.cfg != &rd_nil_cfg)) + else if(view_is_floating && (cell_info.entity != &ctrl_entity_nil || cell_info.cfg != &cfg_nil_node)) { rd_cmd(RD_CmdKind_PushQuery, .expr = e_full_expr_string_from_key(scratch.arena, cell->eval.key)); } @@ -5517,7 +4780,7 @@ rd_view_ui(Rng2F32 rect) internal Arena * rd_view_arena(void) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *view_state = rd_view_state_from_cfg(view); return view_state->arena; } @@ -5525,7 +4788,7 @@ rd_view_arena(void) internal UI_ScrollPt2 rd_view_scroll_pos(void) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *view_state = rd_view_state_from_cfg(view); return view_state->scroll_pos; } @@ -5533,7 +4796,7 @@ rd_view_scroll_pos(void) internal EV_View * rd_view_eval_view(void) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *view_state = rd_view_state_from_cfg(view); return view_state->ev_view; } @@ -5541,9 +4804,9 @@ rd_view_eval_view(void) internal String8 rd_view_query_cmd(void) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *query = rd_cfg_child_from_string(view, str8_lit("query")); - RD_Cfg *cmd = rd_cfg_child_from_string(query, str8_lit("cmd")); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *query = cfg_node_child_from_string(view, str8_lit("query")); + CFG_Node *cmd = cfg_node_child_from_string(query, str8_lit("cmd")); String8 string = cmd->first->string; return string; } @@ -5551,9 +4814,9 @@ rd_view_query_cmd(void) internal String8 rd_view_query_input(void) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *query = rd_cfg_child_from_string(view, str8_lit("query")); - RD_Cfg *input = rd_cfg_child_from_string(query, str8_lit("input")); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *query = cfg_node_child_from_string(view, str8_lit("query")); + CFG_Node *input = cfg_node_child_from_string(query, str8_lit("input")); String8 string = input->first->string; return string; } @@ -5561,8 +4824,8 @@ rd_view_query_input(void) internal String8 rd_view_setting_from_name(String8 name) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - String8 result = rd_cfg_child_from_string(view, name)->first->string; + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + String8 result = cfg_node_child_from_string(view, name)->first->string; if(result.size == 0) { result = rd_default_setting_from_names(view->string, name); @@ -5677,7 +4940,7 @@ rd_arch_from_eval(E_Eval eval) internal void * rd_view_state_by_size(U64 size) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *view_state = rd_view_state_from_cfg(view); if(view_state->user_data == 0) { @@ -5689,7 +4952,7 @@ rd_view_state_by_size(U64 size) internal Arena * rd_push_view_arena(void) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *view_state = rd_view_state_from_cfg(view); RD_ArenaExt *ext = push_array(view_state->arena, RD_ArenaExt, 1); ext->arena = arena_alloc(); @@ -5702,15 +4965,15 @@ rd_push_view_arena(void) internal void rd_store_view_expr_string(String8 string) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); - rd_cfg_new_replace(expr, string); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("expression")); + cfg_node_new_replace(rd_state->cfg, expr, string); } internal void rd_store_view_loading_info(B32 is_loading, U64 progress_u64, U64 progress_u64_target) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *view_state = rd_view_state_from_cfg(view); B32 loading_state_is_new = (is_loading && view_state->loading_t_target != (F32)!!is_loading); view_state->loading_t_target = (F32)!!is_loading; @@ -5725,7 +4988,7 @@ rd_store_view_loading_info(B32 is_loading, U64 progress_u64, U64 progress_u64_ta internal void rd_store_view_scroll_pos(UI_ScrollPt2 pos) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *view_state = rd_view_state_from_cfg(view); view_state->scroll_pos = pos; } @@ -5733,9 +4996,9 @@ rd_store_view_scroll_pos(UI_ScrollPt2 pos) internal void rd_store_view_param(String8 key, String8 value) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *child = rd_cfg_child_from_string_or_alloc(view, key); - rd_cfg_new_replace(child, value); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *child = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, key); + cfg_node_new_replace(rd_state->cfg, child, value); } internal void @@ -5760,13 +5023,13 @@ rd_push_window_title(Arena *arena) return result; } -internal RD_Cfg * -rd_window_from_cfg(RD_Cfg *cfg) +internal CFG_Node * +rd_window_from_cfg(CFG_Node *cfg) { - RD_Cfg *result = &rd_nil_cfg; - for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = c->parent) + CFG_Node *result = &cfg_nil_node; + for(CFG_Node *c = cfg; c != &cfg_nil_node; c = c->parent) { - if(c->parent->parent == rd_state->root_cfg && str8_match(c->string, str8_lit("window"), 0)) + if(c->parent->parent == cfg_node_root() && str8_match(c->string, str8_lit("window"), 0)) { result = c; break; @@ -5776,10 +5039,10 @@ rd_window_from_cfg(RD_Cfg *cfg) } internal RD_WindowState * -rd_window_state_from_cfg(RD_Cfg *cfg) +rd_window_state_from_cfg(CFG_Node *cfg) { //- rjf: unpack - RD_Cfg *window_cfg = rd_window_from_cfg(cfg); + CFG_Node *window_cfg = rd_window_from_cfg(cfg); CFG_ID id = window_cfg->id; //- rjf: scan for existing window @@ -5806,7 +5069,7 @@ rd_window_state_from_cfg(RD_Cfg *cfg) } //- rjf: allocate/open new window if one was not found - if(window_cfg != &rd_nil_cfg && ws == &rd_nil_window_state) + if(window_cfg != &cfg_nil_node && ws == &rd_nil_window_state) { Temp scratch = scratch_begin(0, 0); @@ -5816,10 +5079,10 @@ rd_window_state_from_cfg(RD_Cfg *cfg) Vec2F32 size = {0}; OS_Handle preferred_monitor = {0}; { - RD_Cfg *pos_cfg = rd_cfg_child_from_string(window_cfg, str8_lit("pos")); - has_pos = (pos_cfg != &rd_nil_cfg); - RD_Cfg *size_cfg = rd_cfg_child_from_string(window_cfg, str8_lit("size")); - RD_Cfg *monitor_cfg = rd_cfg_child_from_string(window_cfg, str8_lit("monitor")); + CFG_Node *pos_cfg = cfg_node_child_from_string(window_cfg, str8_lit("pos")); + has_pos = (pos_cfg != &cfg_nil_node); + CFG_Node *size_cfg = cfg_node_child_from_string(window_cfg, str8_lit("size")); + CFG_Node *monitor_cfg = cfg_node_child_from_string(window_cfg, str8_lit("monitor")); pos.x = (F32)f64_from_str8(pos_cfg->first->string); pos.y = (F32)f64_from_str8(pos_cfg->first->next->string); size.x = (F32)f64_from_str8(size_cfg->first->string); @@ -5867,11 +5130,11 @@ rd_window_state_from_cfg(RD_Cfg *cfg) { os_window_set_monitor(ws->os, preferred_monitor); } - if(rd_cfg_child_from_string(window_cfg, str8_lit("fullscreen")) != &rd_nil_cfg) + if(cfg_node_child_from_string(window_cfg, str8_lit("fullscreen")) != &cfg_nil_node) { os_window_set_fullscreen(ws->os, 1); } - if(rd_cfg_child_from_string(window_cfg, str8_lit("maximized")) != &rd_nil_cfg) + if(cfg_node_child_from_string(window_cfg, str8_lit("maximized")) != &cfg_nil_node) { os_window_set_maximized(ws->os, 1); } @@ -5929,8 +5192,8 @@ rd_window_frame(void) ////////////////////////////// //- rjf: @window_frame_part unpack context // - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); - RD_WindowState *ws = rd_window_state_from_cfg(rd_cfg_from_id(rd_regs()->window)); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(cfg_node_from_id(rd_regs()->window)); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); B32 window_is_focused = (os_window_is_focused(ws->os) || ws->window_temporarily_focused_ipc); B32 popup_is_open = (rd_state->popup_active); @@ -5962,43 +5225,43 @@ rd_window_frame(void) Access *access = access_open(); //- rjf: try to find theme settings from the project, then the user. - RD_CfgList colors_cfgs = {0}; - RD_Cfg *theme_parents[] = + CFG_NodePtrList colors_cfgs = {0}; + CFG_Node *theme_parents[] = { - rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")), - rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")) + cfg_node_child_from_string(cfg_node_root(), str8_lit("project")), + cfg_node_child_from_string(cfg_node_root(), str8_lit("user")) }; - RD_Cfg *theme_cfgs[] = + CFG_Node *theme_cfgs[] = { - &rd_nil_cfg, - &rd_nil_cfg, + &cfg_nil_node, + &cfg_nil_node, }; for EachIndex(idx, ArrayCount(theme_parents)) { - RD_Cfg *parent_cfg = theme_parents[idx]; - if(theme_cfgs[idx] == &rd_nil_cfg) + CFG_Node *parent_cfg = theme_parents[idx]; + if(theme_cfgs[idx] == &cfg_nil_node) { - RD_Cfg *possible_theme_cfg = rd_cfg_child_from_string(parent_cfg, str8_lit("theme")); - if(possible_theme_cfg != &rd_nil_cfg) + CFG_Node *possible_theme_cfg = cfg_node_child_from_string(parent_cfg, str8_lit("theme")); + if(possible_theme_cfg != &cfg_nil_node) { theme_cfgs[idx] = possible_theme_cfg; } } - for(RD_Cfg *child = parent_cfg->first; child != &rd_nil_cfg; child = child->next) + for(CFG_Node *child = parent_cfg->first; child != &cfg_nil_node; child = child->next) { if(str8_match(child->string, str8_lit("theme_color"), 0)) { - rd_cfg_list_push_front(scratch.arena, &colors_cfgs, child); + cfg_node_ptr_list_push_front(scratch.arena, &colors_cfgs, child); } } } //- rjf: choose which theme cfg to use - RD_Cfg *theme_cfg = theme_cfgs[1]; + CFG_Node *theme_cfg = theme_cfgs[1]; if(rd_setting_b32_from_name(str8_lit("use_project_theme"))) { theme_cfg = theme_cfgs[0]; - if(theme_cfg == &rd_nil_cfg) + if(theme_cfg == &cfg_nil_node) { theme_cfg = theme_cfgs[1]; } @@ -6023,11 +5286,11 @@ rd_window_frame(void) ThemeTask *first_task = &start_task; ThemeTask *last_task = first_task; { - for(RD_CfgNode *n = colors_cfgs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = colors_cfgs.first; n != 0; n = n->next) { ThemeTask *t = push_array(scratch.arena, ThemeTask, 1); SLLQueuePushFront(first_task, last_task, t); - t->tree = md_tree_from_string(scratch.arena, rd_string_from_cfg_tree(scratch.arena, str8_zero(), n->v)); + t->tree = md_tree_from_string(scratch.arena, cfg_string_from_tree(scratch.arena, rd_state->cfg_schema_table, str8_zero(), n->v)); } } @@ -6140,19 +5403,19 @@ rd_window_frame(void) B32 is_minimized = os_window_is_minimized(ws->os); if(is_fullscreen) { - rd_cfg_child_from_string_or_alloc(window, str8_lit("fullscreen")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("fullscreen")); } else { - rd_cfg_release(rd_cfg_child_from_string(window, str8_lit("fullscreen"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(window, str8_lit("fullscreen"))); } if(is_maximized) { - rd_cfg_child_from_string_or_alloc(window, str8_lit("maximized")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("maximized")); } else { - rd_cfg_release(rd_cfg_child_from_string(window, str8_lit("maximized"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(window, str8_lit("maximized"))); } //- rjf: commit position @@ -6160,24 +5423,24 @@ rd_window_frame(void) if(!is_fullscreen && !is_maximized && !is_minimized) { Vec2F32 pos = window_rect.p0; - RD_Cfg *pos_root = rd_cfg_child_from_string_or_alloc(window, str8_lit("pos")); + CFG_Node *pos_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("pos")); if((S32)pos.x != (S32)f64_from_str8(pos_root->first->string) || (S32)pos.y != (S32)f64_from_str8(pos_root->last->string)) { - RD_Cfg *x = pos_root->first; - if(x == &rd_nil_cfg) + CFG_Node *x = pos_root->first; + if(x == &cfg_nil_node) { - x= rd_cfg_alloc(); - rd_cfg_insert_child(pos_root, &rd_nil_cfg, x); + x= cfg_node_alloc(rd_state->cfg); + cfg_node_insert_child(rd_state->cfg, pos_root, &cfg_nil_node, x); } - RD_Cfg *y = x->next; - if(y == &rd_nil_cfg) + CFG_Node *y = x->next; + if(y == &cfg_nil_node) { - y = rd_cfg_alloc(); - rd_cfg_insert_child(pos_root, x, y); + y = cfg_node_alloc(rd_state->cfg); + cfg_node_insert_child(rd_state->cfg, pos_root, x, y); } - rd_cfg_equip_stringf(x, "%i", (S32)pos.x); - rd_cfg_equip_stringf(y, "%i", (S32)pos.y); + cfg_node_equip_stringf(rd_state->cfg, x, "%i", (S32)pos.x); + cfg_node_equip_stringf(rd_state->cfg, y, "%i", (S32)pos.y); } } @@ -6185,24 +5448,24 @@ rd_window_frame(void) if(!is_fullscreen && !is_maximized && !is_minimized) { Vec2F32 size = dim_2f32(window_rect); - RD_Cfg *size_root = rd_cfg_child_from_string_or_alloc(window, str8_lit("size")); + CFG_Node *size_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("size")); if((S32)size.x != (S32)f64_from_str8(size_root->first->string) || (S32)size.y != (S32)f64_from_str8(size_root->last->string)) { - RD_Cfg *width = size_root->first; - if(width == &rd_nil_cfg) + CFG_Node *width = size_root->first; + if(width == &cfg_nil_node) { - width = rd_cfg_alloc(); - rd_cfg_insert_child(size_root, &rd_nil_cfg, width); + width = cfg_node_alloc(rd_state->cfg); + cfg_node_insert_child(rd_state->cfg, size_root, &cfg_nil_node, width); } - RD_Cfg *height = width->next; - if(height == &rd_nil_cfg) + CFG_Node *height = width->next; + if(height == &cfg_nil_node) { - height = rd_cfg_alloc(); - rd_cfg_insert_child(size_root, width, height); + height = cfg_node_alloc(rd_state->cfg); + cfg_node_insert_child(rd_state->cfg, size_root, width, height); } - rd_cfg_equip_stringf(width, "%i", (S32)size.x); - rd_cfg_equip_stringf(height, "%i", (S32)size.y); + cfg_node_equip_stringf(rd_state->cfg, width, "%i", (S32)size.x); + cfg_node_equip_stringf(rd_state->cfg, height, "%i", (S32)size.y); } } @@ -6211,10 +5474,10 @@ rd_window_frame(void) { OS_Handle monitor = os_monitor_from_window(ws->os); String8 monitor_name = os_name_from_monitor(scratch.arena, monitor); - RD_Cfg *monitor_root = rd_cfg_child_from_string_or_alloc(window, str8_lit("monitor")); + CFG_Node *monitor_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("monitor")); if(!str8_match(monitor_root->first->string, monitor_name, 0)) { - rd_cfg_new_replace(monitor_root, monitor_name); + cfg_node_new_replace(rd_state->cfg, monitor_root, monitor_name); } } scratch_end(scratch); @@ -6360,7 +5623,7 @@ rd_window_frame(void) UI_Tooltip { // rjf: unpack - RD_Cfg *cfg = rd_cfg_from_id(regs->cfg); + CFG_Node *cfg = cfg_node_from_id(regs->cfg); DR_FStrList fstrs = rd_title_fstrs_from_cfg(scratch.arena, cfg, 0); // rjf: title @@ -6495,13 +5758,13 @@ rd_window_frame(void) .view = rd_state->drag_drop_regs->view) { Temp scratch = scratch_begin(0, 0); - RD_Cfg *view = rd_cfg_from_id(rd_state->drag_drop_regs->view); + CFG_Node *view = cfg_node_from_id(rd_state->drag_drop_regs->view); { //- rjf: tab dragging - if(rd_state->drag_drop_regs_slot == RD_RegSlot_View && view != &rd_nil_cfg) + if(rd_state->drag_drop_regs_slot == RD_RegSlot_View && view != &cfg_nil_node) { - RD_Cfg *immediate_parent = &rd_nil_cfg; - for(RD_Cfg *p = view->parent; p != &rd_nil_cfg; p = p->parent) + CFG_Node *immediate_parent = &cfg_nil_node; + for(CFG_Node *p = view->parent; p != &cfg_nil_node; p = p->parent) { if(str8_match(p->parent->string, str8_lit("immediate"), 0)) { @@ -6509,9 +5772,9 @@ rd_window_frame(void) break; } } - if(immediate_parent != &rd_nil_cfg) + if(immediate_parent != &cfg_nil_node) { - rd_cfg_child_from_string_or_alloc(immediate_parent, str8_lit("hot")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, immediate_parent, str8_lit("hot")); } UI_Size main_width = ui_top_pref_width(); UI_Size main_height = ui_top_pref_height(); @@ -6850,7 +6113,7 @@ rd_window_frame(void) Vec4F32 code_default = ui_color_from_name(str8_lit("code_default")); String8 opener = push_str8f(scratch.arena, "%S(", type->name); rd_code_label(1, 0, code_default, opener); - MD_NodePtrList schemas = rd_schemas_from_name(type->name); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, type->name); B32 first = 1; UI_TagF(".") for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) { @@ -6914,7 +6177,7 @@ rd_window_frame(void) struct FloatingViewTask { FloatingViewTask *next; - RD_Cfg *view; + CFG_Node *view; RD_Regs *regs; Rng2F32 rect; B32 is_focused; @@ -6938,14 +6201,14 @@ rd_window_frame(void) if(ws->autocomp_regs != 0 && ws->autocomp_last_frame_index+1 >= rd_state->frame_index) { // rjf: build view - RD_Cfg *root = rd_immediate_cfg_from_keyf("autocomp_view_%I64x", window->id); - RD_Cfg *view = rd_cfg_child_from_string_or_alloc(root, str8_lit("watch")); - rd_cfg_child_from_string_or_alloc(view, str8_lit("autocomplete")); - RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); - RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); - rd_cfg_new_replace(input, ws->autocomp_cursor_info.filter); - RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); - rd_cfg_new_replace(expr, ws->autocomp_cursor_info.list_expr); + CFG_Node *root = rd_immediate_cfg_from_keyf("autocomp_view_%I64x", window->id); + CFG_Node *view = cfg_node_child_from_string_or_alloc(rd_state->cfg, root, str8_lit("watch")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("autocomplete")); + CFG_Node *query = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("query")); + CFG_Node *input = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("input")); + cfg_node_new_replace(rd_state->cfg, input, ws->autocomp_cursor_info.filter); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("expression")); + cfg_node_new_replace(rd_state->cfg, expr, ws->autocomp_cursor_info.list_expr); // rjf: determine container size EV_BlockTree predicted_block_tree = {0}; @@ -6999,8 +6262,8 @@ rd_window_frame(void) panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { if(panel->first != &rd_nil_panel_node) { continue; } - RD_Cfg *tab = panel->selected_tab; - if(tab != &rd_nil_cfg) + CFG_Node *tab = panel->selected_tab; + if(tab != &cfg_nil_node) { RD_ViewState *vs = rd_view_state_from_cfg(tab); Rng2F32 panel_rect = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); @@ -7027,7 +6290,7 @@ rd_window_frame(void) build_hover_eval = 0; } else if(hover_eval.space.kind == RD_EvalSpaceKind_MetaCfg && - rd_cfg_from_eval_space(hover_eval.space) == &rd_nil_cfg) + rd_cfg_from_eval_space(hover_eval.space) == &cfg_nil_node) { build_hover_eval = 0; } @@ -7056,9 +6319,9 @@ rd_window_frame(void) RD_ViewUIRule *view_ui_rule = rd_view_ui_rule_from_string(expand_rule->string); // rjf: build view - RD_Cfg *root = rd_immediate_cfg_from_keyf("hover_eval_view_%I64x", ws->cfg_id); - RD_Cfg *view = rd_view_from_eval(root, hover_eval); - rd_cfg_child_from_string_or_alloc(view, str8_lit("explicit_root")); + CFG_Node *root = rd_immediate_cfg_from_keyf("hover_eval_view_%I64x", ws->cfg_id); + CFG_Node *view = rd_view_from_eval(root, hover_eval); + cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("explicit_root")); // rjf: determine size of hover evaluation container EV_BlockTree predicted_block_tree = {0}; @@ -7127,7 +6390,7 @@ rd_window_frame(void) rd_cmd(RD_CmdKind_CancelQuery); } else if(eval.space.kind == RD_EvalSpaceKind_MetaCfg && - rd_cfg_from_eval_space(eval.space) == &rd_nil_cfg) + rd_cfg_from_eval_space(eval.space) == &cfg_nil_node) { query_is_open = 0; rd_cmd(RD_CmdKind_CancelQuery); @@ -7145,11 +6408,11 @@ rd_window_frame(void) if(query_is_open) { // rjf: unpack view for query - RD_Cfg *root = rd_immediate_cfg_from_keyf("window_query_%p", window); - RD_Cfg *view = rd_cfg_child_from_string_or_alloc(root, str8_lit("watch")); - RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); - B32 is_lister = (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg); - B32 root_is_explicit = (rd_cfg_child_from_string(view, str8_lit("explicit_root")) != &rd_nil_cfg); + CFG_Node *root = rd_immediate_cfg_from_keyf("window_query_%p", window); + CFG_Node *view = cfg_node_child_from_string_or_alloc(rd_state->cfg, root, str8_lit("watch")); + CFG_Node *query = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("query")); + B32 is_lister = (cfg_node_child_from_string(view, str8_lit("lister")) != &cfg_nil_node); + B32 root_is_explicit = (cfg_node_child_from_string(view, str8_lit("explicit_root")) != &cfg_nil_node); RD_ViewState *vs = rd_view_state_from_cfg(view); // rjf: did this view ID change? -> reset open animation @@ -7193,8 +6456,8 @@ rd_window_frame(void) } // rjf: store expression - RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); - rd_cfg_new_replace(expr, query_expr); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("expression")); + cfg_node_new_replace(rd_state->cfg, expr, query_expr); // rjf: evaluate query expression E_Eval query_eval = e_eval_from_string(query_expr); @@ -7204,8 +6467,8 @@ rd_window_frame(void) { F32 row_height = 5.f; F32 row_height_px = row_height * ui_top_font_size(); - RD_Cfg *row_height_root = rd_cfg_child_from_string_or_alloc(view, str8_lit("row_height")); - rd_cfg_new_replacef(row_height_root, "%f", row_height); + CFG_Node *row_height_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("row_height")); + cfg_node_new_replacef(rd_state->cfg, row_height_root, "%f", row_height); } // rjf: compute query view's top-level rectangle @@ -7277,7 +6540,7 @@ rd_window_frame(void) for(FloatingViewTask *t = first_floating_view_task; t != 0; t = t->next) { // rjf: unpack - RD_Cfg *view = t->view; + CFG_Node *view = t->view; Rng2F32 rect = t->rect; B32 is_focused = t->is_focused; B32 is_anchored = t->is_anchored; @@ -7461,14 +6724,14 @@ rd_window_frame(void) //- rjf: query interactions if(t == query_floating_view_task) { - RD_Cfg *view = query_floating_view_task->view; + CFG_Node *view = query_floating_view_task->view; RD_ViewState *vs = rd_view_state_from_cfg(query_floating_view_task->view); String8 cmd_name = ws->query_regs->cmd_name; RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); // rjf: close queries if(query_floating_view_task->pressed_outside || - (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg && !vs->query_is_open) || + (cfg_node_child_from_string(view, str8_lit("lister")) != &cfg_nil_node && !vs->query_is_open) || (cmd_name.size != 0 && !vs->query_is_open) || ui_slot_press(UI_EventActionSlot_Cancel)) { @@ -7478,13 +6741,13 @@ rd_window_frame(void) // rjf: any queries which take a file path mutate the debugger's "current path" if(cmd_kind_info->query.slot == RD_RegSlot_FilePath) { - RD_Cfg *query = rd_cfg_child_from_string(view, str8_lit("query")); - RD_Cfg *input = rd_cfg_child_from_string(query, str8_lit("input")); - if(input != &rd_nil_cfg) + CFG_Node *query = cfg_node_child_from_string(view, str8_lit("query")); + CFG_Node *input = cfg_node_child_from_string(query, str8_lit("input")); + if(input != &cfg_nil_node) { String8 path_chopped = str8_chop_last_slash(input->first->string); - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_Cfg *current_path = rd_cfg_child_from_string_or_alloc(user, str8_lit("current_path")); + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + CFG_Node *current_path = cfg_node_child_from_string_or_alloc(rd_state->cfg, user, str8_lit("current_path")); if(!str8_match(current_path->first->string, path_chopped, 0)) { rd_cmd(RD_CmdKind_SetCurrentPath, .file_path = path_chopped); @@ -7873,7 +7136,7 @@ rd_window_frame(void) UI_FontSize(ui_top_font_size()*0.85f) { Temp scratch = scratch_begin(0, 0); - RD_CfgList targets = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("target")); + CFG_NodePtrList targets = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("target")); CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); B32 can_send_signal = !d_ctrl_targets_running(); typedef struct CenterButtonTask CenterButtonTask; @@ -8054,16 +7317,16 @@ rd_window_frame(void) B32 is_running = d_ctrl_targets_running() && d_ctrl_last_run_frame_idx() < d_frame_index(); CTRL_Event stop_event = d_ctrl_last_stop_event(); String8 tag = str8_lit("pop"); - RD_CfgList tasks = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("conversion_task")); - RD_CfgList long_running_tasks = {0}; + CFG_NodePtrList tasks = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("conversion_task")); + CFG_NodePtrList long_running_tasks = {0}; F32 alive_t_rate = 1 - pow_f32(2, (-5.f * rd_state->frame_dt)); - for(RD_CfgNode *n = tasks.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = tasks.first; n != 0; n = n->next) { - RD_Cfg *task = n->v; + CFG_Node *task = n->v; F32 task_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "task_anim_%I64u", task->id), 1.f, .rate = alive_t_rate); if(task_t > 0.5f) { - rd_cfg_list_push(scratch.arena, &long_running_tasks, task); + cfg_node_ptr_list_push(scratch.arena, &long_running_tasks, task); } } if(rd_state->bind_change_active) @@ -8210,8 +7473,8 @@ rd_window_frame(void) //- rjf: boundary tab-drag/drop sites // { - RD_Cfg *drag_view = rd_cfg_from_id(rd_state->drag_drop_regs->view); - if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && drag_view != &rd_nil_cfg) + CFG_Node *drag_view = cfg_node_from_id(rd_state->drag_drop_regs->view); + if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && drag_view != &cfg_nil_node) { //- rjf: params F32 drop_site_major_dim_px = ceil_f32(ui_top_font_size()*7.f); @@ -8441,8 +7704,8 @@ rd_window_frame(void) F32 sum_pct = min_child->pct_of_parent + max_child->pct_of_parent; min_child->pct_of_parent = 0.5f * sum_pct; max_child->pct_of_parent = 0.5f * sum_pct; - rd_cfg_equip_stringf(min_child->cfg, "%f", min_child->pct_of_parent); - rd_cfg_equip_stringf(max_child->cfg, "%f", max_child->pct_of_parent); + cfg_node_equip_stringf(rd_state->cfg, min_child->cfg, "%f", min_child->pct_of_parent); + cfg_node_equip_stringf(rd_state->cfg, max_child->cfg, "%f", max_child->pct_of_parent); } else if(ui_pressed(sig)) { @@ -8475,8 +7738,8 @@ rd_window_frame(void) } min_child->pct_of_parent = min_pct__after; max_child->pct_of_parent = max_pct__after; - rd_cfg_equip_stringf(min_child->cfg, "%f", min_pct__after); - rd_cfg_equip_stringf(max_child->cfg, "%f", max_pct__after); + cfg_node_equip_stringf(rd_state->cfg, min_child->cfg, "%f", min_pct__after); + cfg_node_equip_stringf(rd_state->cfg, max_child->cfg, "%f", max_pct__after); is_changing_panel_boundaries = 1; } } @@ -8528,7 +7791,7 @@ rd_window_frame(void) !ui_any_ctx_menu_is_open() && !ws->hover_eval_focused && panel_tree.focused == panel); - RD_Cfg *selected_tab = panel->selected_tab; + CFG_Node *selected_tab = panel->selected_tab; RD_ViewState *selected_tab_view_state = rd_view_state_from_cfg(selected_tab); ProfScope("leaf panel UI work - %.*s: %.*s", str8_varg(selected_tab->string), str8_varg(rd_expr_from_cfg(selected_tab))) UI_Focus(panel_is_focused ? UI_FocusKind_Null : UI_FocusKind_Off) @@ -8578,8 +7841,8 @@ rd_window_frame(void) // if(build_panel) { - RD_Cfg *view = rd_cfg_from_id(rd_state->drag_drop_regs->view); - if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && view != &rd_nil_cfg && contains_2f32(panel_rect, ui_mouse()) && ui_key_match(ui_drop_hot_key(), ui_key_zero())) + CFG_Node *view = cfg_node_from_id(rd_state->drag_drop_regs->view); + if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && view != &cfg_nil_node && contains_2f32(panel_rect, ui_mouse()) && ui_key_match(ui_drop_hot_key(), ui_key_zero())) { F32 drop_site_dim_px = ceil_f32(ui_top_font_size()*7.f); drop_site_dim_px = Min(drop_site_dim_px, dim_2f32(panel_rect).v[panel->split_axis]/4.f); @@ -8714,7 +7977,7 @@ rd_window_frame(void) .dst_panel = panel->cfg->id, .panel = rd_state->drag_drop_regs->panel, .view = rd_state->drag_drop_regs->view, - .prev_tab = rd_cfg_list_last(&panel->tabs)->id); + .prev_tab = cfg_node_ptr_list_last(&panel->tabs)->id); } } } @@ -8840,7 +8103,7 @@ rd_window_frame(void) } //- rjf: build empty view - UI_Parent(view_container_box) if(selected_tab == &rd_nil_cfg && panel->parent != &rd_nil_panel_node) + UI_Parent(view_container_box) if(selected_tab == &cfg_nil_node && panel->parent != &rd_nil_panel_node) { ui_set_next_flags(UI_BoxFlag_DefaultFocusNav); UI_Focus(UI_FocusKind_On) UI_WidthFill UI_HeightFill UI_NamedColumn(str8_lit("empty_view")) UI_TagF("weak") @@ -8863,7 +8126,7 @@ rd_window_frame(void) } //- rjf: build tab view - UI_Parent(view_container_box) if(selected_tab != &rd_nil_cfg) ProfScope("build tab view") + UI_Parent(view_container_box) if(selected_tab != &cfg_nil_node) ProfScope("build tab view") { rd_view_ui(content_rect); } @@ -8924,7 +8187,7 @@ rd_window_frame(void) struct TabTask { TabTask *next; - RD_Cfg *tab; + CFG_Node *tab; DR_FStrList fstrs; F32 tab_width; }; @@ -8936,9 +8199,9 @@ rd_window_frame(void) if(build_panel) UI_TagF("tab") { B32 reset = (ws->window_layout_reset || ws->frames_alive < 5 || is_changing_panel_boundaries); - for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = panel->tabs.first; n != 0; n = n->next) { - RD_Cfg *tab = n->v; + CFG_Node *tab = n->v; if(rd_cfg_is_project_filtered(tab)) { continue; @@ -8983,11 +8246,11 @@ rd_window_frame(void) //- rjf: determine tab drop site // B32 tab_drop_is_active = rd_drag_is_active() && ui_key_match(ui_drop_hot_key(), catchall_drop_site_key); - RD_Cfg *tab_drop_prev = &rd_nil_cfg; + CFG_Node *tab_drop_prev = &cfg_nil_node; if(build_panel) { F32 best_prev_distance_px = 1000000.f; - TabTask start_boundary_tab_task = {first_tab_task, &rd_nil_cfg}; + TabTask start_boundary_tab_task = {first_tab_task, &cfg_nil_node}; F32 off = 0; for(TabTask *task = &start_boundary_tab_task; task != 0; task = task->next) { @@ -9007,7 +8270,7 @@ rd_window_frame(void) // if(tab_drop_is_active && rd_state->drag_drop_regs->panel == panel->cfg->id) { - TabTask start_boundary_tab_task = {first_tab_task, &rd_nil_cfg}; + TabTask start_boundary_tab_task = {first_tab_task, &cfg_nil_node}; if(tab_drop_prev->id == rd_state->drag_drop_regs->view) { tab_drop_is_active = 0; @@ -9028,19 +8291,19 @@ rd_window_frame(void) if(build_panel) UI_Focus(UI_FocusKind_Off) UI_Parent(tab_bar_box) UI_Padding(ui_em(0.5f, 1.f)) UI_PrefHeight(ui_pct(1, 0)) UI_TagF("tab") { F32 corner_radius = ui_top_font_size()*0.6f; - TabTask start_boundary_tab_task = {first_tab_task, &rd_nil_cfg}; + TabTask start_boundary_tab_task = {first_tab_task, &cfg_nil_node}; UI_CornerRadius00(panel->tab_side == Side_Min ? corner_radius : 0) UI_CornerRadius01(panel->tab_side == Side_Min ? 0 : corner_radius) UI_CornerRadius10(panel->tab_side == Side_Min ? corner_radius : 0) UI_CornerRadius11(panel->tab_side == Side_Min ? 0 : corner_radius) for(TabTask *tab_task = &start_boundary_tab_task; tab_task != 0; tab_task = tab_task->next) { - RD_Cfg *tab = tab_task->tab; + CFG_Node *tab = tab_task->tab; //- rjf: build tab DR_FStrList tab_fstrs = tab_task->fstrs; F32 tab_width_px = tab_task->tab_width; - if(tab != &rd_nil_cfg) RD_RegsScope(.panel = panel->cfg->id, .view = tab->id, .tab = tab->id) + if(tab != &cfg_nil_node) RD_RegsScope(.panel = panel->cfg->id, .view = tab->id, .tab = tab->id) { // rjf: gather info for this tab B32 tab_is_selected = (tab == panel->selected_tab); @@ -9929,7 +9192,7 @@ rd_value_string_from_eval(Arena *arena, String8 filter, EV_StringParams *params, internal void rd_set_hover_eval(Vec2F32 pos, String8 string) { - RD_Cfg *window_cfg = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window_cfg = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window_cfg); if(ws->hover_eval_lastt_us < rd_state->time_in_us && ui_key_match(ui_active_key(UI_MouseButtonKind_Left), ui_key_zero()) && @@ -9955,7 +9218,7 @@ rd_set_hover_eval(Vec2F32 pos, String8 string) internal void rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs) { - RD_Cfg *window_cfg = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window_cfg = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window_cfg); if(ws->autocomp_last_frame_index < rd_state->frame_index) { @@ -9978,9 +9241,9 @@ rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs) E_TypeKey maybe_enum_type = e_type_key_unwrap(dst_eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative & ~E_TypeUnwrapFlag_Enums); if(dst_eval.space.kind == RD_EvalSpaceKind_MetaCfg) { - RD_Cfg *parent = rd_cfg_from_eval_space(dst_eval.space); + CFG_Node *parent = rd_cfg_from_eval_space(dst_eval.space); String8 child_key = e_string_from_id(dst_eval.space.u64s[1]); - MD_NodePtrList schemas = rd_schemas_from_name(parent->string); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, parent->string); MD_Node *child_schema = &md_nil_node; for(MD_NodePtrNode *n = schemas.first; n != 0 && md_node_is_nil(child_schema); n = n->next) { @@ -10118,7 +9381,7 @@ rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs) if(callee_type->kind == E_TypeKind_LensSpec) { U64 arg_idx = 0; - MD_NodePtrList schemas = rd_schemas_from_name(callee_type->name); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, callee_type->name); for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) { MD_Node *schema = n->v; @@ -10199,7 +9462,7 @@ rd_theme_tree_from_name(Arena *arena, Access *access, String8 theme_name) internal Vec4F32 rd_rgba_from_code_color_slot(RD_CodeColorSlot slot) { - RD_WindowState *ws = rd_window_state_from_cfg(rd_cfg_from_id(rd_regs()->window)); + RD_WindowState *ws = rd_window_state_from_cfg(cfg_node_from_id(rd_regs()->window)); Vec4F32 result = ws->theme_code_colors[slot]; return result; } @@ -10318,7 +9581,7 @@ rd_font_from_slot(RD_FontSlot slot) internal FNT_RasterFlags rd_raster_flags_from_slot(RD_FontSlot slot) { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); FNT_RasterFlags flags = ws->font_slot_raster_flags[slot]; return flags; @@ -10644,9 +9907,9 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 query_expr, String8 strin if(!good && query_expr.size != 0) { Temp scratch = scratch_begin(0, 0); - RD_Cfg *immediate = rd_immediate_cfg_from_keyf("###regs_fill_slot_view"); - RD_Cfg *view = rd_cfg_newf(immediate, "watch"); - rd_cfg_newf(view, "lister"); + CFG_Node *immediate = rd_immediate_cfg_from_keyf("###regs_fill_slot_view"); + CFG_Node *view = cfg_node_newf(rd_state->cfg, immediate, "watch"); + cfg_node_newf(rd_state->cfg, view, "lister"); RD_ViewState *vs = rd_view_state_from_cfg(view); EV_View *eval_view = vs->ev_view; { @@ -10861,42 +10124,13 @@ rd_init(CmdLine *cmdln) // rjf: set up schemas { - U64 schemas_count = ArrayCount(rd_name_schema_info_table); - rd_state->schemas = push_array(rd_state->arena, MD_NodePtrList, schemas_count); - for EachIndex(idx, schemas_count) + rd_state->cfg_schema_table = push_array(rd_state->arena, CFG_SchemaTable, 1); + rd_state->cfg_schema_table->slots_count = 4096; + rd_state->cfg_schema_table->slots = push_array(rd_state->arena, CFG_SchemaNode *, rd_state->cfg_schema_table->slots_count); + for EachElement(idx, rd_name_schema_info_table) { - Temp scratch = scratch_begin(0, 0); - typedef struct SchemaParseTask SchemaParseTask; - struct SchemaParseTask - { - SchemaParseTask *next; - String8 schema_text; - }; - SchemaParseTask start_task = {0, rd_name_schema_info_table[idx].schema}; - SchemaParseTask *first_task = &start_task; - SchemaParseTask *last_task = first_task; - for(SchemaParseTask *t = first_task; t != 0; t = t->next) - { - MD_Node *schema = md_tree_from_string(rd_state->arena, t->schema_text)->first; - md_node_ptr_list_push_front(rd_state->arena, &rd_state->schemas[idx], schema); - for MD_EachNode(tag, schema->first_tag) - { - if(str8_match(tag->string, str8_lit("inherit"), 0)) - { - for EachIndex(idx2, schemas_count) - { - if(str8_match(rd_name_schema_info_table[idx2].name, tag->first->string, 0)) - { - SchemaParseTask *new_task = push_array(scratch.arena, SchemaParseTask, 1); - SLLQueuePush(first_task, last_task, new_task); - new_task->schema_text = rd_name_schema_info_table[idx2].schema; - break; - } - } - } - } - } - scratch_end(scratch); + MD_Node *schema = md_tree_from_string(rd_state->arena, rd_name_schema_info_table[idx].schema)->first; + cfg_schema_table_insert(rd_state->arena, rd_state->cfg_schema_table, rd_name_schema_info_table[idx].name, schema); } } @@ -10935,13 +10169,12 @@ rd_init(CmdLine *cmdln) // rjf: set up top-level config entity trees & tables { - rd_state->cfg_id_slots_count = 1024; - rd_state->cfg_id_slots = push_array(arena, RD_CfgSlot, rd_state->cfg_id_slots_count); - rd_state->root_cfg = rd_cfg_alloc(); - RD_Cfg *user_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("user")); - RD_Cfg *project_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("project")); - RD_Cfg *command_line_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("command_line")); - RD_Cfg *transient = rd_cfg_new(rd_state->root_cfg, str8_lit("transient")); + rd_state->cfg = cfg_state_alloc(); + cfg_ctx_select(cfg_state_ctx(rd_state->cfg)); + cfg_node_new(rd_state->cfg, cfg_node_root(), str8_lit("user")); + cfg_node_new(rd_state->cfg, cfg_node_root(), str8_lit("project")); + cfg_node_new(rd_state->cfg, cfg_node_root(), str8_lit("command_line")); + cfg_node_new(rd_state->cfg, cfg_node_root(), str8_lit("transient")); } // rjf: set up window cache @@ -11044,14 +10277,14 @@ rd_init(CmdLine *cmdln) } //- rjf: build config tree - RD_Cfg *command_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); - RD_Cfg *target = rd_cfg_new(command_line_root, str8_lit("target")); - RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable")); - RD_Cfg *args = rd_cfg_new(target, str8_lit("arguments")); - RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory")); - rd_cfg_new(exe, executable_name_string); - rd_cfg_new(args, arguments_string); - rd_cfg_new(wdir, working_directory_string); + CFG_Node *command_line_root = cfg_node_child_from_string(cfg_node_root(), str8_lit("command_line")); + CFG_Node *target = cfg_node_new(rd_state->cfg, command_line_root, str8_lit("target")); + CFG_Node *exe = cfg_node_new(rd_state->cfg, target, str8_lit("executable")); + CFG_Node *args = cfg_node_new(rd_state->cfg, target, str8_lit("arguments")); + CFG_Node *wdir = cfg_node_new(rd_state->cfg, target, str8_lit("working_directory")); + cfg_node_new(rd_state->cfg, exe, executable_name_string); + cfg_node_new(rd_state->cfg, args, arguments_string); + cfg_node_new(rd_state->cfg, wdir, working_directory_string); rd_cmd(RD_CmdKind_SelectTarget, .cfg = target->id); } scratch_end(scratch); @@ -11238,9 +10471,10 @@ rd_frame(void) for EachElement(idx, table) { Arena *arena = arena_alloc(); - String8 data = rd_string_from_cfg_tree(arena, - str8_zero(), - rd_cfg_child_from_string(rd_state->root_cfg, table[idx].name)); + String8 data = cfg_string_from_tree(arena, + rd_state->cfg_schema_table, + str8_zero(), + cfg_node_child_from_string(cfg_node_root(), table[idx].name)); c_submit_data(table[idx].key, &arena, data); } } @@ -11277,16 +10511,16 @@ rd_frame(void) if(rd_state->frame_depth == 1) { Temp scratch = scratch_begin(0, 0); - RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); - for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + CFG_NodePtrList windows = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(CFG_NodePtrNode *n = windows.first; n != 0; n = n->next) { - RD_Cfg *window = n->v; + CFG_Node *window = n->v; RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { - for(RD_CfgNode *n = p->tabs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = p->tabs.first; n != 0; n = n->next) { - RD_Cfg *tab = n->v; + CFG_Node *tab = n->v; if(rd_cfg_is_project_filtered(tab)) { continue; @@ -11303,28 +10537,28 @@ rd_frame(void) // if(rd_state->frame_depth == 1) { - RD_Cfg *transient = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); - for(RD_Cfg *tln = transient->first, *next = &rd_nil_cfg; tln != &rd_nil_cfg; tln = next) + CFG_Node *transient = cfg_node_child_from_string(cfg_node_root(), str8_lit("transient")); + for(CFG_Node *tln = transient->first, *next = &cfg_nil_node; tln != &cfg_nil_node; tln = next) { next = tln->next; if(str8_match(tln->string, str8_lit("immediate"), 0)) { - if(rd_cfg_child_from_string(tln, str8_lit("hot")) == &rd_nil_cfg) + if(cfg_node_child_from_string(tln, str8_lit("hot")) == &cfg_nil_node) { - rd_cfg_release(tln); + cfg_node_release(rd_state->cfg, tln); } } } - for(RD_Cfg *tln = transient->first; tln != &rd_nil_cfg; tln = tln->next) + for(CFG_Node *tln = transient->first; tln != &cfg_nil_node; tln = tln->next) { if(str8_match(tln->string, str8_lit("immediate"), 0)) { - for(RD_Cfg *child = tln->first, *next = &rd_nil_cfg; child != &rd_nil_cfg; child = next) + for(CFG_Node *child = tln->first, *next = &cfg_nil_node; child != &cfg_nil_node; child = next) { next = child->next; if(str8_match(child->string, str8_lit("hot"), 0)) { - rd_cfg_release(child); + cfg_node_release(rd_state->cfg, child); } } } @@ -11370,18 +10604,18 @@ rd_frame(void) default:{}break; case DI_EventKind_ConversionStarted: { - RD_Cfg *root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); - RD_Cfg *task = rd_cfg_new(root, str8_lit("conversion_task")); - rd_cfg_new(task, event->string); + CFG_Node *root = cfg_node_child_from_string(cfg_node_root(), str8_lit("transient")); + CFG_Node *task = cfg_node_new(rd_state->cfg, root, str8_lit("conversion_task")); + cfg_node_new(rd_state->cfg, task, event->string); }break; case DI_EventKind_ConversionEnded: { - RD_Cfg *root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); - for(RD_Cfg *tln = root->first; tln != &rd_nil_cfg; tln = tln->next) + CFG_Node *root = cfg_node_child_from_string(cfg_node_root(), str8_lit("transient")); + for(CFG_Node *tln = root->first; tln != &cfg_nil_node; tln = tln->next) { if(str8_match(tln->string, str8_lit("conversion_task"), 0) && str8_match(tln->first->string, event->string, 0)) { - rd_cfg_release(tln); + cfg_node_release(rd_state->cfg, tln); break; } } @@ -11432,8 +10666,8 @@ rd_frame(void) { vs->scroll_pos.y.off = 0; } - RD_Cfg *vcfg = rd_cfg_from_id(vs->cfg_id); - if(rd_cfg_child_from_string(vcfg, str8_lit("selected")) != &rd_nil_cfg) + CFG_Node *vcfg = cfg_node_from_id(vs->cfg_id); + if(cfg_node_child_from_string(vcfg, str8_lit("selected")) != &cfg_nil_node) { if(vs->loading_t_target > 0.5f && any_window_is_focused) { @@ -11546,7 +10780,7 @@ rd_frame(void) if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Delete)) { rd_request_frame(); - rd_cfg_release(rd_cfg_from_id(rd_state->bind_change_binding_id)); + cfg_node_release(rd_state->cfg, cfg_node_from_id(rd_state->bind_change_binding_id)); rd_state->bind_change_active = 0; } for(OS_Event *event = events.first, *next = 0; event != 0; event = next) @@ -11564,19 +10798,19 @@ rd_frame(void) event->key != OS_Key_Shift) { rd_state->bind_change_active = 0; - RD_Cfg *binding = rd_cfg_from_id(rd_state->bind_change_binding_id); - if(binding == &rd_nil_cfg) + CFG_Node *binding = cfg_node_from_id(rd_state->bind_change_binding_id); + if(binding == &cfg_nil_node) { - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_Cfg *keybindings = rd_cfg_child_from_string_or_alloc(user, str8_lit("keybindings")); - binding = rd_cfg_new(keybindings, str8_lit("")); + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + CFG_Node *keybindings = cfg_node_child_from_string_or_alloc(rd_state->cfg, user, str8_lit("keybindings")); + binding = cfg_node_new(rd_state->cfg, keybindings, str8_lit("")); } - rd_cfg_release_all_children(binding); - rd_cfg_new(binding, rd_state->bind_change_cmd_name); - rd_cfg_new(binding, os_g_key_cfg_string_table[event->key]); - if(event->modifiers & OS_Modifier_Ctrl) { rd_cfg_new(binding, str8_lit("ctrl")); } - if(event->modifiers & OS_Modifier_Shift) { rd_cfg_new(binding, str8_lit("shift")); } - if(event->modifiers & OS_Modifier_Alt) { rd_cfg_new(binding, str8_lit("alt")); } + cfg_node_release_all_children(rd_state->cfg, binding); + cfg_node_new(rd_state->cfg, binding, rd_state->bind_change_cmd_name); + cfg_node_new(rd_state->cfg, binding, os_g_key_cfg_string_table[event->key]); + if(event->modifiers & OS_Modifier_Ctrl) { cfg_node_new(rd_state->cfg, binding, str8_lit("ctrl")); } + if(event->modifiers & OS_Modifier_Shift) { cfg_node_new(rd_state->cfg, binding, str8_lit("shift")); } + if(event->modifiers & OS_Modifier_Alt) { cfg_node_new(rd_state->cfg, binding, str8_lit("alt")); } U32 codepoint = os_codepoint_from_modifiers_and_key(event->modifiers, event->key); os_text(&events, event->window, codepoint); os_eat_event(&events, event); @@ -11600,15 +10834,15 @@ rd_frame(void) key_map->binding_slots = push_array(rd_frame_arena(), RD_KeyMapSlot, key_map->binding_slots_count); //- rjf: gather & parse all explicitly stored keybinding sets - RD_CfgList keybindings_cfg_list = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("keybindings")); - for(RD_CfgNode *n = keybindings_cfg_list.first; n != 0; n = n->next) + CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings")); + for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next) { - RD_Cfg *keybindings_root = n->v; - for(RD_Cfg *keybinding = keybindings_root->first; keybinding != &rd_nil_cfg; keybinding = keybinding->next) + CFG_Node *keybindings_root = n->v; + for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next) { String8 name = {0}; RD_Binding binding = {0}; - for(RD_Cfg *child = keybinding->first; child != &rd_nil_cfg; child = child->next) + for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next) { if(0){} else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; } @@ -11691,10 +10925,10 @@ rd_frame(void) { next = event->next; RD_WindowState *ws = rd_window_state_from_os_handle(event->window); - if(ws != 0 && ws != rd_window_state_from_cfg(rd_cfg_from_id(rd_regs()->window))) + if(ws != 0 && ws != rd_window_state_from_cfg(cfg_node_from_id(rd_regs()->window))) { Temp scratch = scratch_begin(0, 0); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, rd_cfg_from_id(ws->cfg_id)); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(ws->cfg_id)); rd_regs()->window = ws->cfg_id; rd_regs()->panel = panel_tree.focused->cfg->id; rd_regs()->tab = panel_tree.focused->selected_tab->id; @@ -12035,7 +11269,7 @@ rd_frame(void) for EachElement(idx, rd_name_schema_info_table) { String8 name = rd_name_schema_info_table[idx].name; - MD_NodePtrList schemas = rd_schemas_from_name(name); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, name); B32 is_individually_evallable = 0; for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) { @@ -12049,10 +11283,10 @@ rd_frame(void) if(is_individually_evallable) { E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, name); - RD_CfgList cfgs = rd_cfg_top_level_list_from_string(scratch.arena, name); - for(RD_CfgNode *n = cfgs.first; n != 0; n = n->next) + CFG_NodePtrList cfgs = cfg_node_top_level_list_from_string(scratch.arena, name); + for(CFG_NodePtrNode *n = cfgs.first; n != 0; n = n->next) { - RD_Cfg *cfg = n->v; + CFG_Node *cfg = n->v; String8 label = rd_label_from_cfg(cfg); if(label.size != 0) { @@ -12068,12 +11302,12 @@ rd_frame(void) } //- rjf: add macros for windows/tabs - RD_CfgList watch_tabs = {0}; + CFG_NodePtrList watch_tabs = {0}; { - RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); - for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + CFG_NodePtrList windows = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(CFG_NodePtrNode *n = windows.first; n != 0; n = n->next) { - RD_Cfg *window = n->v; + CFG_Node *window = n->v; { E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, window->string); E_Space space = rd_eval_space_from_cfg(window); @@ -12088,9 +11322,9 @@ rd_frame(void) p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { - for(RD_CfgNode *tab_n = p->tabs.first; tab_n != 0; tab_n = tab_n->next) + for(CFG_NodePtrNode *tab_n = p->tabs.first; tab_n != 0; tab_n = tab_n->next) { - RD_Cfg *tab = tab_n->v; + CFG_Node *tab = tab_n->v; E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, tab->string); E_Space space = rd_eval_space_from_cfg(tab); E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); @@ -12100,7 +11334,7 @@ rd_frame(void) e_string2expr_map_insert(scratch.arena, macro_map, push_str8f(scratch.arena, "query:config.$%I64x", tab->id), expr); if(str8_match(tab->string, str8_lit("watch"), 0)) { - rd_cfg_list_push(scratch.arena, &watch_tabs, tab); + cfg_node_ptr_list_push(scratch.arena, &watch_tabs, tab); } } } @@ -12108,14 +11342,14 @@ rd_frame(void) } //- rjf: add macros for all watches in all watch tabs which define identifiers - for(RD_CfgNode *n = watch_tabs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = watch_tabs.first; n != 0; n = n->next) { - RD_Cfg *watch_tab = n->v; - for(RD_Cfg *child = watch_tab->first; child != &rd_nil_cfg; child = child->next) + CFG_Node *watch_tab = n->v; + for(CFG_Node *child = watch_tab->first; child != &cfg_nil_node; child = child->next) { if(str8_match(child->string, str8_lit("watch"), 0)) { - RD_Cfg *watch = child; + CFG_Node *watch = child; String8 expr = watch->first->string; E_Parse parse = e_parse_from_string(expr); if(parse.msgs.max_kind == E_MsgKind_Null) @@ -12165,7 +11399,7 @@ rd_frame(void) //- rjf: add macros for user/project { E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, str8_lit("user")); - E_Space space = rd_eval_space_from_cfg(rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user"))); + E_Space space = rd_eval_space_from_cfg(cfg_node_child_from_string(cfg_node_root(), str8_lit("user"))); E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); expr->space = space; expr->mode = E_Mode_Offset; @@ -12174,7 +11408,7 @@ rd_frame(void) } { E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, str8_lit("project")); - E_Space space = rd_eval_space_from_cfg(rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project"))); + E_Space space = rd_eval_space_from_cfg(cfg_node_child_from_string(cfg_node_root(), str8_lit("project"))); E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); expr->space = space; expr->mode = E_Mode_Offset; @@ -12546,7 +11780,7 @@ rd_frame(void) //////////////////////////// //- rjf: gather config from loaded modules // - RD_CfgList immediate_type_views = {0}; + CFG_NodePtrList immediate_type_views = {0}; CTRL_EntityArray modules = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Module); ProfScope("gather config from loaded modules") { @@ -12560,14 +11794,14 @@ rd_frame(void) for(String8Node *text_n = raddbg_data_text_parts.first; text_n != 0; text_n = text_n->next) { String8 text = text_n->string; - RD_CfgList cfgs = rd_cfg_tree_list_from_string(scratch.arena, str8_zero(), text); + CFG_NodePtrList cfgs = cfg_node_ptr_list_from_string(scratch.arena, rd_state->cfg, rd_state->cfg_schema_table, str8_zero(), text); String8 module_name = ctrl_string_from_handle(scratch.arena, module->handle); - for(RD_CfgNode *n = cfgs.first; n != 0; n = n->next, cfg_idx += 1) + for(CFG_NodePtrNode *n = cfgs.first; n != 0; n = n->next, cfg_idx += 1) { - RD_Cfg *immediate_root = rd_immediate_cfg_from_keyf("module_%S_cfg_%I64x", module_name, cfg_idx); - rd_cfg_release_all_children(immediate_root); - rd_cfg_insert_child(immediate_root, immediate_root->last, n->v); - rd_cfg_list_push(scratch.arena, &immediate_type_views, n->v); + CFG_Node *immediate_root = rd_immediate_cfg_from_keyf("module_%S_cfg_%I64x", module_name, cfg_idx); + cfg_node_release_all_children(rd_state->cfg, immediate_root); + cfg_node_insert_child(rd_state->cfg, immediate_root, immediate_root->last, n->v); + cfg_node_ptr_list_push(scratch.arena, &immediate_type_views, n->v); } } } @@ -12610,13 +11844,13 @@ rd_frame(void) if((type_views[idx].stl && rd_state->use_default_stl_type_views) || (type_views[idx].ue && rd_state->use_default_ue_type_views)) { - RD_Cfg *immediate_root = rd_immediate_cfg_from_keyf("default_type_vis_%I64x", idx); - RD_Cfg *type_view = rd_cfg_child_from_string_or_alloc(immediate_root, str8_lit("type_view")); - RD_Cfg *type = rd_cfg_child_from_string_or_alloc(type_view, str8_lit("type")); - RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(type_view, str8_lit("expr")); - rd_cfg_new_replace(type, type_views[idx].pattern); - rd_cfg_new_replace(expr, type_views[idx].expr); - rd_cfg_list_push(scratch.arena, &immediate_type_views, type_view); + CFG_Node *immediate_root = rd_immediate_cfg_from_keyf("default_type_vis_%I64x", idx); + CFG_Node *type_view = cfg_node_child_from_string_or_alloc(rd_state->cfg, immediate_root, str8_lit("type_view")); + CFG_Node *type = cfg_node_child_from_string_or_alloc(rd_state->cfg, type_view, str8_lit("type")); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, type_view, str8_lit("expr")); + cfg_node_new_replace(rd_state->cfg, type, type_views[idx].pattern); + cfg_node_new_replace(rd_state->cfg, expr, type_views[idx].expr); + cfg_node_ptr_list_push(scratch.arena, &immediate_type_views, type_view); } } } @@ -12626,20 +11860,20 @@ rd_frame(void) //- rjf: add auto-hook rules for type views // { - RD_CfgList type_views = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("type_view")); - RD_CfgList rules_lists[] = + CFG_NodePtrList type_views = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("type_view")); + CFG_NodePtrList rules_lists[] = { type_views, immediate_type_views, }; for EachElement(list_idx, rules_lists) { - RD_CfgList list = rules_lists[list_idx]; - for(RD_CfgNode *n = list.first; n != 0; n = n->next) + CFG_NodePtrList list = rules_lists[list_idx]; + for(CFG_NodePtrNode *n = list.first; n != 0; n = n->next) { - RD_Cfg *rule = n->v; - String8 type_string = rd_cfg_child_from_string(rule, str8_lit("type"))->first->string; - String8 expr_string = rd_cfg_child_from_string(rule, str8_lit("expr"))->first->string; + CFG_Node *rule = n->v; + String8 type_string = cfg_node_child_from_string(rule, str8_lit("type"))->first->string; + String8 expr_string = cfg_node_child_from_string(rule, str8_lit("expr"))->first->string; e_auto_hook_map_insert_new(scratch.arena, auto_hook_map, .type_pattern = type_string, .tag_expr_string = expr_string); } } @@ -12714,11 +11948,11 @@ rd_frame(void) rd_request_frame(); // rjf: process command - RD_Cfg *cfg = &rd_nil_cfg; + CFG_Node *cfg = &cfg_nil_node; String8 dst_path = {0}; String8 bucket_name = {0}; Dir2 split_dir = Dir2_Invalid; - RD_Cfg *split_panel = &rd_nil_cfg; + CFG_Node *split_panel = &cfg_nil_node; U64 panel_sib_off = 0; U64 panel_child_off = 0; Vec2S32 panel_change_dir = {0}; @@ -12736,20 +11970,20 @@ rd_frame(void) CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(processes.count == 0 || kind == RD_CmdKind_Restart) { - RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); - for(RD_CfgNode *n = bps.first; n != 0; n = n->next) + CFG_NodePtrList bps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(CFG_NodePtrNode *n = bps.first; n != 0; n = n->next) { - RD_Cfg *hit_count = rd_cfg_child_from_string_or_alloc(n->v, str8_lit("hit_count")); - rd_cfg_new_replace(hit_count, str8_lit("0")); + CFG_Node *hit_count = cfg_node_child_from_string_or_alloc(rd_state->cfg, n->v, str8_lit("hit_count")); + cfg_node_new_replace(rd_state->cfg, hit_count, str8_lit("0")); } } // rjf: determine if we have active targets - RD_CfgList targets = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("target")); + CFG_NodePtrList targets = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("target")); B32 has_active_targets = 0; - for(RD_CfgNode *n = targets.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = targets.first; n != 0; n = n->next) { - RD_Cfg *target = n->v; + CFG_Node *target = n->v; if(!rd_disabled_from_cfg(target)) { has_active_targets = 1; @@ -12819,7 +12053,7 @@ rd_frame(void) params.pid = rd_regs()->pid; params.targets.count = 1; params.targets.v = push_array(scratch.arena, D_Target, params.targets.count); - params.targets.v[0] = rd_target_from_cfg(scratch.arena, rd_cfg_from_id(rd_regs()->cfg)); + params.targets.v[0] = rd_target_from_cfg(scratch.arena, cfg_node_from_id(rd_regs()->cfg)); d_push_cmd((D_CmdKind)kind, ¶ms); } @@ -12836,17 +12070,17 @@ rd_frame(void) //- rjf: open palette case RD_CmdKind_OpenPalette: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_Cfg *tab = panel_tree.focused->selected_tab; + CFG_Node *tab = panel_tree.focused->selected_tab; String8List exprs = {0}; { str8_list_pushf(scratch.arena, &exprs, "query:commands"); - if(tab != &rd_nil_cfg) + if(tab != &cfg_nil_node) { str8_list_pushf(scratch.arena, &exprs, "query:config.$%I64x", tab->id); } - if(window != &rd_nil_cfg) + if(window != &cfg_nil_node) { str8_list_pushf(scratch.arena, &exprs, "query:config.$%I64x", window->id); } @@ -12885,8 +12119,8 @@ rd_frame(void) // rjf: command has filesystem query, user wants native filesystem UI -> get the path then run the command else if(info->query.slot == RD_RegSlot_FilePath && rd_setting_b32_from_name(str8_lit("use_native_file_system_dialog"))) { - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_Cfg *current_path = rd_cfg_child_from_string(user, str8_lit("current_path")); + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + CFG_Node *current_path = cfg_node_child_from_string(user, str8_lit("current_path")); String8 current_path_string = current_path->first->string; if(current_path_string.size == 0) { @@ -12982,17 +12216,17 @@ rd_frame(void) //- rjf: windows case RD_CmdKind_OpenWindow: { - RD_Cfg *old_window = rd_cfg_from_id(rd_regs()->window); - RD_Cfg *bucket = old_window->parent; - if(bucket == &rd_nil_cfg) + CFG_Node *old_window = cfg_node_from_id(rd_regs()->window); + CFG_Node *bucket = old_window->parent; + if(bucket == &cfg_nil_node) { - bucket = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + bucket = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); } - RD_Cfg *new_window = rd_cfg_new(bucket, str8_lit("window")); - RD_Cfg *size = rd_cfg_new(new_window, str8_lit("size")); - rd_cfg_newf(size, "1280"); - rd_cfg_newf(size, "720"); - for(RD_Cfg *old_child = old_window->first; old_child != &rd_nil_cfg; old_child = old_child->next) + CFG_Node *new_window = cfg_node_new(rd_state->cfg, bucket, str8_lit("window")); + CFG_Node *size = cfg_node_new(rd_state->cfg, new_window, str8_lit("size")); + cfg_node_newf(rd_state->cfg, size, "1280"); + cfg_node_newf(rd_state->cfg, size, "720"); + for(CFG_Node *old_child = old_window->first; old_child != &cfg_nil_node; old_child = old_child->next) { if(!str8_match(old_child->string, str8_lit("panels"), 0) && !str8_match(old_child->string, str8_lit("size"), 0) && @@ -13001,12 +12235,12 @@ rd_frame(void) !str8_match(old_child->string, str8_lit("fullscreen"), 0) && !str8_match(old_child->string, str8_lit("maximized"), 0)) { - RD_Cfg *new_child = rd_cfg_deep_copy(old_child); - rd_cfg_insert_child(new_window, new_window->last, new_child); + CFG_Node *new_child = cfg_node_deep_copy(rd_state->cfg, old_child); + cfg_node_insert_child(rd_state->cfg, new_window, new_window->last, new_child); } } - RD_Cfg *panels = rd_cfg_new(new_window, str8_lit("panels")); - rd_cfg_child_from_string_or_alloc(panels, str8_lit("selected")); + CFG_Node *panels = cfg_node_new(rd_state->cfg, new_window, str8_lit("panels")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, panels, str8_lit("selected")); }break; case RD_CmdKind_WindowSettings: { @@ -13015,20 +12249,20 @@ rd_frame(void) }break; case RD_CmdKind_CloseWindow: { - RD_CfgList all_windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); - RD_Cfg *wcfg = rd_cfg_from_id(rd_regs()->window); + CFG_NodePtrList all_windows = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("window")); + CFG_Node *wcfg = cfg_node_from_id(rd_regs()->window); if(all_windows.count == 1 && all_windows.first->v == wcfg) { rd_cmd(RD_CmdKind_Exit); } else { - rd_cfg_release(wcfg); + cfg_node_release(rd_state->cfg, wcfg); } }break; case RD_CmdKind_ToggleFullscreen: { - RD_Cfg *wcfg = rd_cfg_from_id(rd_regs()->window); + CFG_Node *wcfg = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(wcfg); if(ws != &rd_nil_window_state) { @@ -13037,7 +12271,7 @@ rd_frame(void) }break; case RD_CmdKind_BringToFront: { - RD_Cfg *last_focused_wcfg = rd_cfg_from_id(rd_state->last_focused_window); + CFG_Node *last_focused_wcfg = cfg_node_from_id(rd_state->last_focused_window); RD_WindowState *last_focused_ws = rd_window_state_from_cfg(last_focused_wcfg); if(last_focused_ws == &rd_nil_window_state) { @@ -13069,31 +12303,31 @@ rd_frame(void) //- rjf: keybindings case RD_CmdKind_ResetToDefaultBindings: { - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_CfgList all_keybindings = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("keybindings")); - for(RD_CfgNode *n = all_keybindings.first; n != 0; n = n->next) + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + CFG_NodePtrList all_keybindings = cfg_node_child_list_from_string(scratch.arena, user, str8_lit("keybindings")); + for(CFG_NodePtrNode *n = all_keybindings.first; n != 0; n = n->next) { - rd_cfg_release(n->v); + cfg_node_release(rd_state->cfg, n->v); } - RD_Cfg *keybindings = rd_cfg_new(user, str8_lit("keybindings")); + CFG_Node *keybindings = cfg_node_new(rd_state->cfg, user, str8_lit("keybindings")); for EachElement(idx, rd_default_binding_table) { String8 name = rd_default_binding_table[idx].string; RD_Binding binding = rd_default_binding_table[idx].binding; - RD_Cfg *binding_root = rd_cfg_new(keybindings, str8_zero()); - rd_cfg_new(binding_root, name); - rd_cfg_new(binding_root, os_g_key_cfg_string_table[binding.key]); - if(binding.modifiers & OS_Modifier_Ctrl) {rd_cfg_newf(binding_root, "ctrl");} - if(binding.modifiers & OS_Modifier_Shift) {rd_cfg_newf(binding_root, "shift");} - if(binding.modifiers & OS_Modifier_Alt) {rd_cfg_newf(binding_root, "alt");} + CFG_Node *binding_root = cfg_node_new(rd_state->cfg, keybindings, str8_zero()); + cfg_node_new(rd_state->cfg, binding_root, name); + cfg_node_new(rd_state->cfg, binding_root, os_g_key_cfg_string_table[binding.key]); + if(binding.modifiers & OS_Modifier_Ctrl) {cfg_node_newf(rd_state->cfg, binding_root, "ctrl");} + if(binding.modifiers & OS_Modifier_Shift) {cfg_node_newf(rd_state->cfg, binding_root, "shift");} + if(binding.modifiers & OS_Modifier_Alt) {cfg_node_newf(rd_state->cfg, binding_root, "alt");} } }break; //- rjf: config path saving/loading/applying case RD_CmdKind_OpenRecentProject: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); - RD_Cfg *path = rd_cfg_child_from_string(cfg, str8_lit("path")); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); + CFG_Node *path = cfg_node_child_from_string(cfg, str8_lit("path")); if(str8_match(cfg->string, str8_lit("recent_project"), 0) && path->first->string.size != 0) { @@ -13106,7 +12340,7 @@ rd_frame(void) String8 file_root_key = (kind == RD_CmdKind_OpenUser ? str8_lit("user") : kind == RD_CmdKind_OpenProject ? str8_lit("project") : str8_lit("other")); - RD_Cfg *file_root = rd_cfg_child_from_string(rd_state->root_cfg, file_root_key); + CFG_Node *file_root = cfg_node_child_from_string(cfg_node_root(), file_root_key); //- rjf: load the new file's data String8 file_path = rd_regs()->file_path; @@ -13144,22 +12378,22 @@ rd_frame(void) //- rjf: eliminate all old state under this file tree if(file_is_okay) { - rd_cfg_release_all_children(file_root); + cfg_node_release_all_children(rd_state->cfg, file_root); } //- rjf: parse the new file, generate cfg entities for it - RD_CfgList file_cfg_list = {0}; + CFG_NodePtrList file_cfg_list = {0}; if(file_is_okay) { U64 file_version_code = version_from_str8(file_version); if(file_version_code < Version(0, 9, 16)) { - RD_CfgList (*legacy_parse_function)(Arena *arena, String8 file_path, String8 data) = rd_cfg_tree_list_from_string__pre_0_9_16; + CFG_NodePtrList (*legacy_parse_function)(Arena *arena, String8 file_path, String8 data) = rd_cfg_tree_list_from_string__pre_0_9_16; file_cfg_list = legacy_parse_function(scratch.arena, file_path, file_data); } else { - file_cfg_list = rd_cfg_tree_list_from_string(scratch.arena, str8_chop_last_slash(file_path), file_data); + file_cfg_list = cfg_node_ptr_list_from_string(scratch.arena, rd_state->cfg, rd_state->cfg_schema_table, str8_chop_last_slash(file_path), file_data); } } @@ -13185,16 +12419,16 @@ rd_frame(void) //- rjf: insert the new cfg entities into this file tree if(file_is_okay) { - for(RD_CfgNode *n = file_cfg_list.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = file_cfg_list.first; n != 0; n = n->next) { - rd_cfg_insert_child(file_root, file_root->last, n->v); + cfg_node_insert_child(rd_state->cfg, file_root, file_root->last, n->v); } } //- rjf: if config did not open any windows for the user, then we need to open a sensible default if(file_is_okay && kind == RD_CmdKind_OpenUser) { - RD_CfgList all_user_windows = rd_cfg_child_list_from_string(scratch.arena, file_root, str8_lit("window")); + CFG_NodePtrList all_user_windows = cfg_node_child_list_from_string(scratch.arena, file_root, str8_lit("window")); if(all_user_windows.count == 0) { OS_Handle monitor = os_primary_monitor(); @@ -13206,10 +12440,10 @@ rd_frame(void) { window_dim = v2f32(1280, 720); } - RD_Cfg *new_window = rd_cfg_new(file_root, str8_lit("window")); - RD_Cfg *size = rd_cfg_new(new_window, str8_lit("size")); - rd_cfg_newf(size, "%f", window_dim.x); - rd_cfg_newf(size, "%f", window_dim.y); + CFG_Node *new_window = cfg_node_new(rd_state->cfg, file_root, str8_lit("window")); + CFG_Node *size = cfg_node_new(rd_state->cfg, new_window, str8_lit("size")); + cfg_node_newf(rd_state->cfg, size, "%f", window_dim.x); + cfg_node_newf(rd_state->cfg, size, "%f", window_dim.y); F32 line_height_guess = 11.f * (monitor_dpi / 96.f); F32 num_lines_in_monitor_height = monitor_dim.y / line_height_guess; if(num_lines_in_monitor_height < 100) @@ -13226,7 +12460,7 @@ rd_frame(void) //- rjf: if config did not define any keybindings for the user, then we need to build a sensible default if(file_is_okay && kind == RD_CmdKind_OpenUser) { - RD_CfgList all_keybindings = rd_cfg_child_list_from_string(scratch.arena, file_root, str8_lit("keybindings")); + CFG_NodePtrList all_keybindings = cfg_node_child_list_from_string(scratch.arena, file_root, str8_lit("keybindings")); if(all_keybindings.count == 0) { rd_cmd(RD_CmdKind_ResetToDefaultBindings); @@ -13248,17 +12482,17 @@ rd_frame(void) //- rjf: eliminate all project-filtered tab focuses if(file_is_okay && kind == RD_CmdKind_OpenProject) { - RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); - for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + CFG_NodePtrList windows = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(CFG_NodePtrNode *n = windows.first; n != 0; n = n->next) { RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, n->v); for(RD_PanelNode *panel = panels.root; panel != &rd_nil_panel_node; panel = rd_panel_node_rec__depth_first_pre(panels.root, panel).next) { if(rd_cfg_is_project_filtered(panel->selected_tab)) { - for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - RD_Cfg *tab = tab_n->v; + CFG_Node *tab = tab_n->v; if(!rd_cfg_is_project_filtered(tab)) { rd_cmd(RD_CmdKind_FocusTab, .tab = tab->id); @@ -13275,8 +12509,8 @@ rd_frame(void) // load one of those, *or* just the default. if(file_is_okay && kind == RD_CmdKind_OpenUser && rd_state->project_path.size == 0) { - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_Cfg *recent_project = rd_cfg_child_from_string(user, str8_lit("recent_project")); + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + CFG_Node *recent_project = cfg_node_child_from_string(user, str8_lit("recent_project")); String8 project_path = rd_path_from_cfg(recent_project); if(project_path.size == 0) { @@ -13371,10 +12605,10 @@ rd_frame(void) case RD_CmdKind_RecordProjectInUser: { String8 file_path = rd_regs()->file_path; - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_CfgList recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); - RD_Cfg *recent_project = &rd_nil_cfg; - for(RD_CfgNode *n = recent_projects.first; n != 0; n = n->next) + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + CFG_NodePtrList recent_projects = cfg_node_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); + CFG_Node *recent_project = &cfg_nil_node; + for(CFG_NodePtrNode *n = recent_projects.first; n != 0; n = n->next) { if(path_match_normalized(rd_path_from_cfg(n->v), file_path)) { @@ -13382,18 +12616,18 @@ rd_frame(void) break; } } - if(recent_project == &rd_nil_cfg) + if(recent_project == &cfg_nil_node) { - recent_project = rd_cfg_new(user, str8_lit("recent_project")); - RD_Cfg *path_root = rd_cfg_new(recent_project, str8_lit("path")); - rd_cfg_new(path_root, file_path); + recent_project = cfg_node_new(rd_state->cfg, user, str8_lit("recent_project")); + CFG_Node *path_root = cfg_node_new(rd_state->cfg, recent_project, str8_lit("path")); + cfg_node_new(rd_state->cfg, path_root, file_path); } - rd_cfg_unhook(user, recent_project); - rd_cfg_insert_child(user, &rd_nil_cfg, recent_project); - recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); + cfg_node_unhook(rd_state->cfg, user, recent_project); + cfg_node_insert_child(rd_state->cfg, user, &cfg_nil_node, recent_project); + recent_projects = cfg_node_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); if(recent_projects.count > 32) { - rd_cfg_release(recent_projects.last->v); + cfg_node_release(rd_state->cfg, recent_projects.last->v); } }break; case RD_CmdKind_RecordUserAsLastOpened: @@ -13411,12 +12645,12 @@ rd_frame(void) B32 dst_exists = (os_properties_from_file_path(dst_path).created != 0); String8 temp_path = push_str8f(scratch.arena, "%S.temp", dst_path); String8 overwritten_path = push_str8f(scratch.arena, "%S.old", dst_path); - RD_Cfg *tree_root = rd_cfg_child_from_string(rd_state->root_cfg, bucket_name); + CFG_Node *tree_root = cfg_node_child_from_string(cfg_node_root(), bucket_name); String8List strings = {0}; str8_list_pushf(scratch.arena, &strings, "// raddbg %s %S file\n\n", BUILD_VERSION_STRING_LITERAL, bucket_name); - for(RD_Cfg *child = tree_root->first; child != &rd_nil_cfg; child = child->next) + for(CFG_Node *child = tree_root->first; child != &cfg_nil_node; child = child->next) { - str8_list_push(scratch.arena, &strings, rd_string_from_cfg_tree(scratch.arena, str8_chop_last_slash(dst_path), child)); + str8_list_push(scratch.arena, &strings, cfg_string_from_tree(scratch.arena, rd_state->cfg_schema_table, str8_chop_last_slash(dst_path), child)); } String8 data = str8_list_join(scratch.arena, &strings, 0); B32 temp_write_good = os_write_data_to_file_path(temp_path, data); @@ -13444,29 +12678,29 @@ rd_frame(void) }break; //- rjf: font sizes - case RD_CmdKind_IncWindowFontSize: cfg = rd_cfg_from_id(rd_regs()->window); rd_regs()->view = 0; rd_regs()->tab = 0; goto inc_font_size; - case RD_CmdKind_IncViewFontSize: cfg = rd_cfg_from_id(rd_regs()->view); goto inc_font_size; + case RD_CmdKind_IncWindowFontSize: cfg = cfg_node_from_id(rd_regs()->window); rd_regs()->view = 0; rd_regs()->tab = 0; goto inc_font_size; + case RD_CmdKind_IncViewFontSize: cfg = cfg_node_from_id(rd_regs()->view); goto inc_font_size; inc_font_size:; - if(cfg != &rd_nil_cfg) + if(cfg != &cfg_nil_node) { fnt_reset(); F32 current_font_size = rd_font_size(); F32 new_font_size = current_font_size+1; new_font_size = Clamp(6.f, new_font_size, 72.f); - RD_Cfg *font_size_cfg = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("font_size")); - rd_cfg_new_replacef(font_size_cfg, "%I64u", (U64)new_font_size); + CFG_Node *font_size_cfg = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, str8_lit("font_size")); + cfg_node_new_replacef(rd_state->cfg, font_size_cfg, "%I64u", (U64)new_font_size); }break; - case RD_CmdKind_DecWindowFontSize: cfg = rd_cfg_from_id(rd_regs()->window); rd_regs()->view = 0; rd_regs()->tab = 0; goto dec_font_size; - case RD_CmdKind_DecViewFontSize: cfg = rd_cfg_from_id(rd_regs()->view); goto dec_font_size; + case RD_CmdKind_DecWindowFontSize: cfg = cfg_node_from_id(rd_regs()->window); rd_regs()->view = 0; rd_regs()->tab = 0; goto dec_font_size; + case RD_CmdKind_DecViewFontSize: cfg = cfg_node_from_id(rd_regs()->view); goto dec_font_size; dec_font_size:; - if(cfg != &rd_nil_cfg) + if(cfg != &cfg_nil_node) { fnt_reset(); F32 current_font_size = rd_font_size(); F32 new_font_size = current_font_size-1; new_font_size = Clamp(6.f, new_font_size, 72.f); - RD_Cfg *font_size_cfg = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("font_size")); - rd_cfg_new_replacef(font_size_cfg, "%I64u", (U64)new_font_size); + CFG_Node *font_size_cfg = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, str8_lit("font_size")); + cfg_node_new_replacef(rd_state->cfg, font_size_cfg, "%I64u", (U64)new_font_size); }break; //- rjf: panel creation @@ -13477,7 +12711,7 @@ rd_frame(void) case RD_CmdKind_SplitPanel: { split_dir = rd_regs()->dir2; - split_panel = rd_cfg_from_id(rd_regs()->dst_panel); + split_panel = cfg_node_from_id(rd_regs()->dst_panel); }goto split; split:; if(split_dir != Dir2_Invalid) @@ -13485,11 +12719,11 @@ rd_frame(void) // rjf: unpack Axis2 split_axis = axis2_from_dir2(split_dir); Side split_side = side_from_dir2(split_dir); - if(split_panel == &rd_nil_cfg) + if(split_panel == &cfg_nil_node) { - split_panel = rd_cfg_from_id(rd_regs()->panel); + split_panel = cfg_node_from_id(rd_regs()->panel); } - RD_Cfg *new_panel_cfg = &rd_nil_cfg; + CFG_Node *new_panel_cfg = &cfg_nil_node; RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, split_panel); RD_PanelNode *panel_root = panel_tree.root; RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_root, split_panel); @@ -13498,16 +12732,16 @@ rd_frame(void) // rjf: splitting on same axis as parent -> insert new sibling on same axis, adjust sizes if(parent != &rd_nil_panel_node && parent->split_axis == split_axis) { - RD_Cfg *parent_cfg = parent->cfg; - RD_Cfg *panel_cfg = panel->cfg; - RD_Cfg *new_cfg = rd_cfg_alloc(); - rd_cfg_insert_child(parent_cfg, split_side == Side_Max ? panel_cfg : panel_cfg->prev, new_cfg); - rd_cfg_equip_stringf(new_cfg, "%f", 1.f/(parent->child_count+1)); + CFG_Node *parent_cfg = parent->cfg; + CFG_Node *panel_cfg = panel->cfg; + CFG_Node *new_cfg = cfg_node_alloc(rd_state->cfg); + cfg_node_insert_child(rd_state->cfg, parent_cfg, split_side == Side_Max ? panel_cfg : panel_cfg->prev, new_cfg); + cfg_node_equip_stringf(rd_state->cfg, new_cfg, "%f", 1.f/(parent->child_count+1)); for(RD_PanelNode *child = parent->first; child != &rd_nil_panel_node; child = child->next) { F32 old_pct = child->pct_of_parent; F32 new_pct = old_pct * ((F32)(parent->child_count) / (parent->child_count+1)); - rd_cfg_equip_stringf(child->cfg, "%f", new_pct); + cfg_node_equip_stringf(rd_state->cfg, child->cfg, "%f", new_pct); } new_panel_cfg = new_cfg; } @@ -13515,39 +12749,39 @@ rd_frame(void) // rjf: splitting on opposite axis as parent - need to create new replacement node, + new sibling else { - RD_Cfg *split_panel_prev = panel->prev->cfg; - RD_Cfg *new_parent = rd_cfg_alloc(); - RD_Cfg *new_sibling = rd_cfg_alloc(); - rd_cfg_equip_string(new_parent, split_panel->string); - rd_cfg_equip_string(split_panel, str8_lit("0.5")); - rd_cfg_equip_string(new_sibling, str8_lit("0.5")); - if(parent->cfg != &rd_nil_cfg) + CFG_Node *split_panel_prev = panel->prev->cfg; + CFG_Node *new_parent = cfg_node_alloc(rd_state->cfg); + CFG_Node *new_sibling = cfg_node_alloc(rd_state->cfg); + cfg_node_equip_string(rd_state->cfg, new_parent, split_panel->string); + cfg_node_equip_string(rd_state->cfg, split_panel, str8_lit("0.5")); + cfg_node_equip_string(rd_state->cfg, new_sibling, str8_lit("0.5")); + if(parent->cfg != &cfg_nil_node) { - rd_cfg_unhook(parent->cfg, split_panel); - rd_cfg_insert_child(parent->cfg, split_panel_prev, new_parent); + cfg_node_unhook(rd_state->cfg, parent->cfg, split_panel); + cfg_node_insert_child(rd_state->cfg, parent->cfg, split_panel_prev, new_parent); } else { - rd_cfg_equip_string(new_parent, str8_lit("panels")); - RD_Cfg *window_cfg = rd_window_from_cfg(split_panel); - rd_cfg_insert_child(window_cfg, window_cfg->last, new_parent); + cfg_node_equip_string(rd_state->cfg, new_parent, str8_lit("panels")); + CFG_Node *window_cfg = rd_window_from_cfg(split_panel); + cfg_node_insert_child(rd_state->cfg, window_cfg, window_cfg->last, new_parent); if(split_axis == Axis2_X) { - rd_cfg_child_from_string_or_alloc(window_cfg, str8_lit("split_x")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, window_cfg, str8_lit("split_x")); } else { - rd_cfg_release(rd_cfg_child_from_string(window_cfg, str8_lit("split_x"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(window_cfg, str8_lit("split_x"))); } } - RD_Cfg *min = split_panel; - RD_Cfg *max = new_sibling; + CFG_Node *min = split_panel; + CFG_Node *max = new_sibling; if(split_side == Side_Min) { - Swap(RD_Cfg *, min, max); + Swap(CFG_Node *, min, max); } - rd_cfg_insert_child(new_parent, new_parent->last, min); - rd_cfg_insert_child(new_parent, new_parent->last, max); + cfg_node_insert_child(rd_state->cfg, new_parent, new_parent->last, min); + cfg_node_insert_child(rd_state->cfg, new_parent, new_parent->last, max); new_panel_cfg = new_sibling; } @@ -13604,18 +12838,18 @@ rd_frame(void) // rjf: if this split was caused by drag/dropping a tab, and the originating panel // has no further tabs, then close the originating panel - RD_Cfg *dragdrop_origin_panel_cfg = rd_cfg_from_id(rd_regs()->panel); - RD_Cfg *dragdrop_tab = rd_cfg_from_id(rd_regs()->view); + CFG_Node *dragdrop_origin_panel_cfg = cfg_node_from_id(rd_regs()->panel); + CFG_Node *dragdrop_tab = cfg_node_from_id(rd_regs()->view); if(kind == RD_CmdKind_SplitPanel && - new_panel_cfg != &rd_nil_cfg && dragdrop_tab != &rd_nil_cfg && dragdrop_origin_panel_cfg != &rd_nil_cfg) + new_panel_cfg != &cfg_nil_node && dragdrop_tab != &cfg_nil_node && dragdrop_origin_panel_cfg != &cfg_nil_node) { - rd_cfg_unhook(dragdrop_origin_panel_cfg, dragdrop_tab); - rd_cfg_insert_child(new_panel_cfg, new_panel_cfg->last, dragdrop_tab); + cfg_node_unhook(rd_state->cfg, dragdrop_origin_panel_cfg, dragdrop_tab); + cfg_node_insert_child(rd_state->cfg, new_panel_cfg, new_panel_cfg->last, dragdrop_tab); RD_PanelTree origin_panel_tree = rd_panel_tree_from_cfg(scratch.arena, dragdrop_origin_panel_cfg); RD_PanelNode *origin_panel = rd_panel_node_from_tree_cfg(origin_panel_tree.root, dragdrop_origin_panel_cfg); - if(origin_panel->selected_tab == &rd_nil_cfg) + if(origin_panel->selected_tab == &cfg_nil_node) { - for(RD_CfgNode *n = origin_panel->tabs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = origin_panel->tabs.first; n != 0; n = n->next) { if(!rd_cfg_is_project_filtered(n->v)) { @@ -13632,7 +12866,7 @@ rd_frame(void) } // rjf: focus new panel - if(new_panel_cfg != &rd_nil_cfg) + if(new_panel_cfg != &cfg_nil_node) { rd_cmd(RD_CmdKind_FocusPanel, .panel = new_panel_cfg->id); } @@ -13647,7 +12881,7 @@ rd_frame(void) //- rjf: panel rotation case RD_CmdKind_RotatePanelColumns: { - RD_Cfg *panel_cfg = rd_cfg_from_id(rd_regs()->panel); + CFG_Node *panel_cfg = cfg_node_from_id(rd_regs()->panel); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel_cfg); RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, panel_cfg); RD_PanelNode *parent = &rd_nil_panel_node; @@ -13661,9 +12895,9 @@ rd_frame(void) } if(parent != &rd_nil_panel_node && parent->child_count > 1) { - RD_Cfg *rotated = parent->first->cfg; - rd_cfg_unhook(parent->cfg, parent->first->cfg); - rd_cfg_insert_child(parent->cfg, parent->last->cfg, rotated); + CFG_Node *rotated = parent->first->cfg; + cfg_node_unhook(rd_state->cfg, parent->cfg, parent->first->cfg); + cfg_node_insert_child(rd_state->cfg, parent->cfg, parent->last->cfg, rotated); } }break; @@ -13672,7 +12906,7 @@ rd_frame(void) case RD_CmdKind_PrevPanel: panel_sib_off = OffsetOf(RD_PanelNode, prev); panel_child_off = OffsetOf(RD_PanelNode, last); goto cycle; cycle:; { - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, rd_cfg_from_id(rd_regs()->window)); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(rd_regs()->window)); RD_PanelNode *next_focused = &rd_nil_panel_node; for(RD_PanelNode *p = panel_tree.focused; p != &rd_nil_panel_node; @@ -13701,33 +12935,33 @@ rd_frame(void) }break; case RD_CmdKind_FocusPanel: { - RD_Cfg *panel = rd_cfg_from_id(rd_regs()->panel); + CFG_Node *panel = cfg_node_from_id(rd_regs()->panel); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel); - RD_Cfg *selection_cfg = &rd_nil_cfg; + CFG_Node *selection_cfg = &cfg_nil_node; for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { - RD_Cfg *p_cfg = p->cfg; - RD_Cfg *p_selection = rd_cfg_child_from_string(p_cfg, str8_lit("selected")); - if(selection_cfg == &rd_nil_cfg) + CFG_Node *p_cfg = p->cfg; + CFG_Node *p_selection = cfg_node_child_from_string(p_cfg, str8_lit("selected")); + if(selection_cfg == &cfg_nil_node) { selection_cfg = p_selection; } - else for(RD_Cfg *s = p_selection; s != &rd_nil_cfg; s = rd_cfg_child_from_string(p_cfg, str8_lit("selected"))) + else for(CFG_Node *s = p_selection; s != &cfg_nil_node; s = cfg_node_child_from_string(p_cfg, str8_lit("selected"))) { - rd_cfg_release(s); + cfg_node_release(rd_state->cfg, s); } } - if(selection_cfg == &rd_nil_cfg) + if(selection_cfg == &cfg_nil_node) { - selection_cfg = rd_cfg_alloc(); - rd_cfg_equip_string(selection_cfg, str8_lit("selected")); + selection_cfg = cfg_node_alloc(rd_state->cfg); + cfg_node_equip_string(rd_state->cfg, selection_cfg, str8_lit("selected")); } - if(panel != &rd_nil_cfg) + if(panel != &cfg_nil_node) { - rd_cfg_insert_child(panel, &rd_nil_cfg, selection_cfg); - RD_Cfg *window = rd_window_from_cfg(panel); + cfg_node_insert_child(rd_state->cfg, panel, &cfg_nil_node, selection_cfg); + CFG_Node *window = rd_window_from_cfg(panel); RD_WindowState *ws = rd_window_state_from_cfg(window); ws->menu_bar_focused = 0; } @@ -13740,7 +12974,7 @@ rd_frame(void) case RD_CmdKind_FocusPanelDown: panel_change_dir = v2s32(+0, +1); goto focus_panel_dir; focus_panel_dir:; { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); RD_PanelNode *src_panel = panel_tree.focused; Rng2F32 src_panel_rect = rd_target_rect_from_panel_node(r2f32(v2f32(0, 0), v2f32(1000, 1000)), panel_tree.root, src_panel); @@ -13788,9 +13022,9 @@ rd_frame(void) //- rjf: files case RD_CmdKind_SetCurrentPath: { - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_Cfg *current_path = rd_cfg_child_from_string_or_alloc(user, str8_lit("current_path")); - rd_cfg_new_replace(current_path, rd_regs()->file_path); + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + CFG_Node *current_path = cfg_node_child_from_string_or_alloc(rd_state->cfg, user, str8_lit("current_path")); + cfg_node_new_replace(rd_state->cfg, current_path, rd_regs()->file_path); }break; case RD_CmdKind_SetFileReplacementPath: { @@ -13862,36 +13096,36 @@ rd_frame(void) String8 map_dst = str8_list_join(scratch.arena, &map_dst_parts, &map_join); //- rjf: store as file path map cfg - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); { - RD_CfgList cfgs = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("file_path_map")); - RD_Cfg *map = &rd_nil_cfg; - for(RD_CfgNode *n = cfgs.first; n != 0; n = n->next) + CFG_NodePtrList cfgs = cfg_node_child_list_from_string(scratch.arena, user, str8_lit("file_path_map")); + CFG_Node *map = &cfg_nil_node; + for(CFG_NodePtrNode *n = cfgs.first; n != 0; n = n->next) { - RD_Cfg *src = rd_cfg_child_from_string(n->v, str8_lit("source")); + CFG_Node *src = cfg_node_child_from_string(n->v, str8_lit("source")); if(path_match_normalized(src->first->string, map_src)) { map = n->v; break; } } - if(map == &rd_nil_cfg) + if(map == &cfg_nil_node) { - map = rd_cfg_new(user, str8_lit("file_path_map")); + map = cfg_node_new(rd_state->cfg, user, str8_lit("file_path_map")); } - RD_Cfg *src = rd_cfg_child_from_string_or_alloc(map, str8_lit("source")); - RD_Cfg *dst = rd_cfg_child_from_string_or_alloc(map, str8_lit("dest")); - rd_cfg_new_replace(src, map_src); - rd_cfg_new_replace(dst, map_dst); + CFG_Node *src = cfg_node_child_from_string_or_alloc(rd_state->cfg, map, str8_lit("source")); + CFG_Node *dst = cfg_node_child_from_string_or_alloc(rd_state->cfg, map, str8_lit("dest")); + cfg_node_new_replace(rd_state->cfg, src, map_src); + cfg_node_new_replace(rd_state->cfg, dst, map_dst); } }break; //- rjf: panel removal case RD_CmdKind_ClosePanel: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, rd_cfg_from_id(rd_regs()->panel)); + RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, cfg_node_from_id(rd_regs()->panel)); RD_PanelNode *parent = panel->parent; if(parent != &rd_nil_panel_node) { @@ -13908,17 +13142,17 @@ rd_frame(void) F32 pct_of_parent = parent->pct_of_parent; // rjf: unhook kept child - rd_cfg_unhook(parent->cfg, keep_child->cfg); + cfg_node_unhook(rd_state->cfg, parent->cfg, keep_child->cfg); // rjf: unhook this subtree if(grandparent != &rd_nil_panel_node) { - rd_cfg_unhook(grandparent->cfg, parent->cfg); + cfg_node_unhook(rd_state->cfg, grandparent->cfg, parent->cfg); } // rjf: release the containing tree { - rd_cfg_release(parent->cfg); + cfg_node_release(rd_state->cfg, parent->cfg); } // rjf: re-hook our kept child into the overall tree @@ -13926,37 +13160,37 @@ rd_frame(void) { if(keep_child->split_axis == Axis2_X) { - rd_cfg_child_from_string_or_alloc(window, str8_lit("split_x")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("split_x")); } else { - rd_cfg_release(rd_cfg_child_from_string(window, str8_lit("split_x"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(window, str8_lit("split_x"))); } - rd_cfg_equip_string(keep_child->cfg, str8_lit("panels")); - rd_cfg_insert_child(window, window->last, keep_child->cfg); + cfg_node_equip_string(rd_state->cfg, keep_child->cfg, str8_lit("panels")); + cfg_node_insert_child(rd_state->cfg, window, window->last, keep_child->cfg); } else { - rd_cfg_insert_child(grandparent->cfg, parent_prev->cfg, keep_child->cfg); - rd_cfg_equip_stringf(keep_child->cfg, "%f", pct_of_parent); + cfg_node_insert_child(rd_state->cfg, grandparent->cfg, parent_prev->cfg, keep_child->cfg); + cfg_node_equip_stringf(rd_state->cfg, keep_child->cfg, "%f", pct_of_parent); } // rjf: keep-child split-axis == grandparent split-axis? bubble keep-child up into grandparent's children if(grandparent != &rd_nil_panel_node && grandparent->split_axis == keep_child->split_axis && keep_child->first != &rd_nil_panel_node) { - rd_cfg_unhook(grandparent->cfg, keep_child->cfg); - RD_Cfg *prev = parent_prev->cfg; + cfg_node_unhook(rd_state->cfg, grandparent->cfg, keep_child->cfg); + CFG_Node *prev = parent_prev->cfg; for(RD_PanelNode *child = keep_child->first, *next = &rd_nil_panel_node; child != &rd_nil_panel_node; child = next) { next = child->next; - rd_cfg_unhook(keep_child->cfg, child->cfg); - rd_cfg_insert_child(grandparent->cfg, prev, child->cfg); + cfg_node_unhook(rd_state->cfg, keep_child->cfg, child->cfg); + cfg_node_insert_child(rd_state->cfg, grandparent->cfg, prev, child->cfg); prev = child->cfg; F32 old_pct = child->pct_of_parent; F32 new_pct = old_pct * pct_of_parent; - rd_cfg_equip_stringf(child->cfg, "%f", new_pct); + cfg_node_equip_stringf(rd_state->cfg, child->cfg, "%f", new_pct); } - rd_cfg_release(keep_child->cfg); + cfg_node_release(rd_state->cfg, keep_child->cfg); } // rjf: reset focus, if needed @@ -13979,8 +13213,8 @@ rd_frame(void) F32 removed_size_pct = panel->pct_of_parent; if(next == &rd_nil_panel_node) { next = panel->prev; } if(next == &rd_nil_panel_node) { next = panel->next; } - rd_cfg_unhook(parent->cfg, panel->cfg); - rd_cfg_release(panel->cfg); + cfg_node_unhook(rd_state->cfg, parent->cfg, panel->cfg); + cfg_node_release(rd_state->cfg, panel->cfg); // rjf: resize siblings to this node { @@ -13988,10 +13222,10 @@ rd_frame(void) RD_PanelNode *new_parent = rd_panel_node_from_tree_cfg(new_panel_tree.root, parent->cfg); for(RD_PanelNode *child = new_parent->first; child != &rd_nil_panel_node; child = child->next) { - RD_Cfg *cfg = child->cfg; + CFG_Node *cfg = child->cfg; F32 old_pct = child->pct_of_parent; F32 new_pct = old_pct / (1.f-removed_size_pct); - rd_cfg_equip_stringf(cfg, "%f", new_pct); + cfg_node_equip_stringf(rd_state->cfg, cfg, "%f", new_pct); } } @@ -14013,37 +13247,37 @@ rd_frame(void) //- rjf: panel tab controls case RD_CmdKind_FocusTab: { - RD_Cfg *tab = rd_cfg_from_id(rd_regs()->tab); - RD_Cfg *panel = tab->parent; + CFG_Node *tab = cfg_node_from_id(rd_regs()->tab); + CFG_Node *panel = tab->parent; RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel); RD_PanelNode *panel_node = rd_panel_node_from_tree_cfg(panel_tree.root, panel); - RD_Cfg *selection_cfg = &rd_nil_cfg; - for(RD_CfgNode *n = panel_node->tabs.first; n != 0; n = n->next) + CFG_Node *selection_cfg = &cfg_nil_node; + for(CFG_NodePtrNode *n = panel_node->tabs.first; n != 0; n = n->next) { - RD_Cfg *tab_selection_cfg = rd_cfg_child_from_string(n->v, str8_lit("selected")); - if(selection_cfg == &rd_nil_cfg) + CFG_Node *tab_selection_cfg = cfg_node_child_from_string(n->v, str8_lit("selected")); + if(selection_cfg == &cfg_nil_node) { selection_cfg = tab_selection_cfg; } - else for(RD_Cfg *s = tab_selection_cfg; s != &rd_nil_cfg; s = rd_cfg_child_from_string(n->v, str8_lit("selected"))) + else for(CFG_Node *s = tab_selection_cfg; s != &cfg_nil_node; s = cfg_node_child_from_string(n->v, str8_lit("selected"))) { - rd_cfg_release(s); + cfg_node_release(rd_state->cfg, s); } } - if(selection_cfg == &rd_nil_cfg) + if(selection_cfg == &cfg_nil_node) { - selection_cfg = rd_cfg_alloc(); - rd_cfg_equip_string(selection_cfg, str8_lit("selected")); + selection_cfg = cfg_node_alloc(rd_state->cfg); + cfg_node_equip_string(rd_state->cfg, selection_cfg, str8_lit("selected")); } - rd_cfg_insert_child(tab, &rd_nil_cfg, selection_cfg); + cfg_node_insert_child(rd_state->cfg, tab, &cfg_nil_node, selection_cfg); }break; case RD_CmdKind_NextTab: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); RD_PanelNode *focused = panel_tree.focused; - RD_CfgNode *selected_tab_n = 0; - for(RD_CfgNode *n = focused->tabs.first; n != 0; n = n->next) + CFG_NodePtrNode *selected_tab_n = 0; + for(CFG_NodePtrNode *n = focused->tabs.first; n != 0; n = n->next) { if(n->v == focused->selected_tab) { @@ -14051,9 +13285,9 @@ rd_frame(void) break; } } - RD_Cfg *next_selected_tab = &rd_nil_cfg; + CFG_Node *next_selected_tab = &cfg_nil_node; U64 idx = 0; - for(RD_CfgNode *tab_n = selected_tab_n; + for(CFG_NodePtrNode *tab_n = selected_tab_n; tab_n != 0 && (tab_n != selected_tab_n || idx == 0); ((tab_n->next == 0) ? (tab_n = focused->tabs.first) : (tab_n = tab_n->next)), idx += 1) { @@ -14063,18 +13297,18 @@ rd_frame(void) break; } } - if(next_selected_tab != &rd_nil_cfg) + if(next_selected_tab != &cfg_nil_node) { rd_cmd(RD_CmdKind_FocusTab, .tab = next_selected_tab->id); } }break; case RD_CmdKind_PrevTab: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); RD_PanelNode *focused = panel_tree.focused; - RD_CfgNode *selected_tab_n = 0; - for(RD_CfgNode *n = focused->tabs.last; n != 0; n = n->prev) + CFG_NodePtrNode *selected_tab_n = 0; + for(CFG_NodePtrNode *n = focused->tabs.last; n != 0; n = n->prev) { if(n->v == focused->selected_tab) { @@ -14082,9 +13316,9 @@ rd_frame(void) break; } } - RD_Cfg *next_selected_tab = &rd_nil_cfg; + CFG_Node *next_selected_tab = &cfg_nil_node; U64 idx = 0; - for(RD_CfgNode *tab_n = selected_tab_n; + for(CFG_NodePtrNode *tab_n = selected_tab_n; tab_n != 0 && (tab_n != selected_tab_n || idx == 0); ((tab_n->prev == 0) ? (tab_n = focused->tabs.last) : (tab_n = tab_n->prev)), idx += 1) { @@ -14094,7 +13328,7 @@ rd_frame(void) break; } } - if(next_selected_tab != &rd_nil_cfg) + if(next_selected_tab != &cfg_nil_node) { rd_cmd(RD_CmdKind_FocusTab, .tab = next_selected_tab->id); } @@ -14102,29 +13336,29 @@ rd_frame(void) case RD_CmdKind_MoveTabRight: case RD_CmdKind_MoveTabLeft: { - RD_Cfg *tab = rd_cfg_from_id(rd_regs()->tab); - RD_Cfg *window = rd_window_from_cfg(tab); + CFG_Node *tab = cfg_node_from_id(rd_regs()->tab); + CFG_Node *window = rd_window_from_cfg(tab); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, tab->parent); - RD_CfgList filtered_tabs = {0}; - for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) + CFG_NodePtrList filtered_tabs = {0}; + for(CFG_NodePtrNode *n = panel->tabs.first; n != 0; n = n->next) { if(rd_cfg_is_project_filtered(n->v)) { continue; } - rd_cfg_list_push(scratch.arena, &filtered_tabs, n->v); + cfg_node_ptr_list_push(scratch.arena, &filtered_tabs, n->v); } - RD_Cfg *tab_prev2 = &rd_nil_cfg; - RD_Cfg *tab_prev = &rd_nil_cfg; - RD_Cfg *tab_next = &rd_nil_cfg; + CFG_Node *tab_prev2 = &cfg_nil_node; + CFG_Node *tab_prev = &cfg_nil_node; + CFG_Node *tab_next = &cfg_nil_node; { - RD_Cfg *prev2 = &rd_nil_cfg; - RD_Cfg *prev = &rd_nil_cfg; - RD_Cfg *next = &rd_nil_cfg; - for(RD_CfgNode *n = filtered_tabs.first; n != 0; (prev2 = prev, prev = n->v, n = n->next)) + CFG_Node *prev2 = &cfg_nil_node; + CFG_Node *prev = &cfg_nil_node; + CFG_Node *next = &cfg_nil_node; + for(CFG_NodePtrNode *n = filtered_tabs.first; n != 0; (prev2 = prev, prev = n->v, n = n->next)) { - next = n->next ? n->next->v : &rd_nil_cfg; + next = n->next ? n->next->v : &cfg_nil_node; if(n->v == tab) { tab_prev2 = prev2; @@ -14134,7 +13368,7 @@ rd_frame(void) } } } - RD_Cfg *new_prev = (kind == RD_CmdKind_MoveTabRight ? tab_next : tab_prev2); + CFG_Node *new_prev = (kind == RD_CmdKind_MoveTabRight ? tab_next : tab_prev2); if(new_prev == tab_prev && filtered_tabs.last) { new_prev = filtered_tabs.last->v; @@ -14147,41 +13381,41 @@ rd_frame(void) case RD_CmdKind_BuildTab: { String8 expr_file_path = rd_file_path_from_eval_string(scratch.arena, rd_regs()->expr); - RD_Cfg *panel = rd_cfg_from_id(rd_regs()->panel); - RD_Cfg *tab = rd_cfg_new(panel, rd_regs()->string); - RD_Cfg *expr = rd_cfg_new(tab, str8_lit("expression")); - rd_cfg_new(expr, rd_regs()->expr); + CFG_Node *panel = cfg_node_from_id(rd_regs()->panel); + CFG_Node *tab = cfg_node_new(rd_state->cfg, panel, rd_regs()->string); + CFG_Node *expr = cfg_node_new(rd_state->cfg, tab, str8_lit("expression")); + cfg_node_new(rd_state->cfg, expr, rd_regs()->expr); if(expr_file_path.size != 0) { - RD_Cfg *project = rd_cfg_new(tab, str8_lit("project")); - rd_cfg_new(project, rd_state->project_path); + CFG_Node *project = cfg_node_new(rd_state->cfg, tab, str8_lit("project")); + cfg_node_new(rd_state->cfg, project, rd_state->project_path); } rd_cmd(RD_CmdKind_FocusTab, .tab = tab->id); }break; case RD_CmdKind_DuplicateTab: { - RD_Cfg *src = rd_cfg_from_id(rd_regs()->tab); - RD_Cfg *dst = rd_cfg_deep_copy(src); - rd_cfg_insert_child(src->parent, src, dst); + CFG_Node *src = cfg_node_from_id(rd_regs()->tab); + CFG_Node *dst = cfg_node_deep_copy(rd_state->cfg, src); + cfg_node_insert_child(rd_state->cfg, src->parent, src, dst); rd_cmd(RD_CmdKind_FocusTab, .tab = dst->id); }break; case RD_CmdKind_CopyTabFullPath: { - RD_Cfg *tab = rd_cfg_from_id(rd_regs()->tab); + CFG_Node *tab = cfg_node_from_id(rd_regs()->tab); String8 expr = rd_expr_from_cfg(tab); String8 full_path = rd_file_path_from_eval_string(scratch.arena, expr); os_set_clipboard_text(full_path); }break; case RD_CmdKind_CloseTab: { - RD_Cfg *tab = rd_cfg_from_id(rd_regs()->tab); + CFG_Node *tab = cfg_node_from_id(rd_regs()->tab); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, tab); RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, tab->parent); if(panel->selected_tab == tab) { B32 found_selected = 0; - RD_Cfg *next_selected_tab = &rd_nil_cfg; - for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) + CFG_Node *next_selected_tab = &cfg_nil_node; + for(CFG_NodePtrNode *n = panel->tabs.first; n != 0; n = n->next) { if(n->v == panel->selected_tab) { @@ -14198,18 +13432,18 @@ rd_frame(void) } rd_cmd(RD_CmdKind_FocusTab, .tab = next_selected_tab->id); } - rd_cfg_release(tab); + cfg_node_release(rd_state->cfg, tab); }break; case RD_CmdKind_MoveView: { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *prev_tab = rd_cfg_from_id(rd_regs()->prev_tab); - RD_Cfg *src_panel = view->parent; - RD_Cfg *dst_panel = rd_cfg_from_id(rd_regs()->dst_panel); - if(dst_panel != &rd_nil_cfg && prev_tab != view) + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *prev_tab = cfg_node_from_id(rd_regs()->prev_tab); + CFG_Node *src_panel = view->parent; + CFG_Node *dst_panel = cfg_node_from_id(rd_regs()->dst_panel); + if(dst_panel != &cfg_nil_node && prev_tab != view) { - rd_cfg_unhook(src_panel, view); - rd_cfg_insert_child(dst_panel, prev_tab, view); + cfg_node_unhook(rd_state->cfg, src_panel, view); + cfg_node_insert_child(rd_state->cfg, dst_panel, prev_tab, view); rd_cmd(RD_CmdKind_FocusTab, .panel = dst_panel->id, .tab = view->id); rd_cmd(RD_CmdKind_FocusPanel, .panel = dst_panel->id); RD_PanelTree src_panel_tree = rd_panel_tree_from_cfg(scratch.arena, src_panel); @@ -14218,7 +13452,7 @@ rd_frame(void) if(src_panel != dst_panel) { src_panel_is_empty = 1; - for(RD_CfgNode *n = src_panel_node->tabs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = src_panel_node->tabs.first; n != 0; n = n->next) { if(!rd_cfg_is_project_filtered(n->v)) { @@ -14236,13 +13470,13 @@ rd_frame(void) }break; case RD_CmdKind_TabBarTop: { - RD_Cfg *panel = rd_cfg_from_id(rd_regs()->panel); - rd_cfg_release(rd_cfg_child_from_string(panel, str8_lit("tabs_on_bottom"))); + CFG_Node *panel = cfg_node_from_id(rd_regs()->panel); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(panel, str8_lit("tabs_on_bottom"))); }break; case RD_CmdKind_TabBarBottom: { - RD_Cfg *panel = rd_cfg_from_id(rd_regs()->panel); - rd_cfg_child_from_string_or_alloc(panel, str8_lit("tabs_on_bottom")); + CFG_Node *panel = cfg_node_from_id(rd_regs()->panel); + cfg_node_child_from_string_or_alloc(rd_state->cfg, panel, str8_lit("tabs_on_bottom")); }break; case RD_CmdKind_TabSettings: { @@ -14270,8 +13504,8 @@ rd_frame(void) String8 path = {0}; if(path.size == 0) { - RD_Cfg *recent_file = rd_cfg_from_id(rd_regs()->cfg); - RD_Cfg *path_root = rd_cfg_child_from_string(recent_file, str8_lit("path")); + CFG_Node *recent_file = cfg_node_from_id(rd_regs()->cfg); + CFG_Node *path_root = cfg_node_child_from_string(recent_file, str8_lit("path")); path = path_root->first->string; } if(path.size == 0) @@ -14315,10 +13549,10 @@ rd_frame(void) if(rd_regs()->file_path.size != 0) { String8 path = rd_regs()->file_path; - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - RD_CfgList recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_file")); - RD_Cfg *recent_file = &rd_nil_cfg; - for(RD_CfgNode *n = recent_files.first; n != 0; n = n->next) + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); + CFG_NodePtrList recent_files = cfg_node_child_list_from_string(scratch.arena, project, str8_lit("recent_file")); + CFG_Node *recent_file = &cfg_nil_node; + for(CFG_NodePtrNode *n = recent_files.first; n != 0; n = n->next) { if(path_match_normalized(rd_path_from_cfg(n->v), path)) { @@ -14326,18 +13560,18 @@ rd_frame(void) break; } } - if(recent_file == &rd_nil_cfg) + if(recent_file == &cfg_nil_node) { - recent_file = rd_cfg_new(project, str8_lit("recent_file")); - RD_Cfg *path_root = rd_cfg_new(recent_file, str8_lit("path")); - rd_cfg_new(path_root, path); + recent_file = cfg_node_new(rd_state->cfg, project, str8_lit("recent_file")); + CFG_Node *path_root = cfg_node_new(rd_state->cfg, recent_file, str8_lit("path")); + cfg_node_new(rd_state->cfg, path_root, path); } - rd_cfg_unhook(project, recent_file); - rd_cfg_insert_child(project, &rd_nil_cfg, recent_file); - recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_file")); + cfg_node_unhook(rd_state->cfg, project, recent_file); + cfg_node_insert_child(rd_state->cfg, project, &cfg_nil_node, recent_file); + recent_files = cfg_node_child_list_from_string(scratch.arena, project, str8_lit("recent_file")); if(recent_files.count > 256) { - rd_cfg_release(recent_files.last->v); + cfg_node_release(rd_state->cfg, recent_files.last->v); } }break; case RD_CmdKind_ShowFileInExplorer: @@ -14382,14 +13616,14 @@ rd_frame(void) case RD_CmdKind_ResetToCompactPanels: case RD_CmdKind_ResetToSimplePanels: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); - RD_Cfg *panels = rd_cfg_child_from_string(window, str8_lit("panels")); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); + CFG_Node *panels = cfg_node_child_from_string(window, str8_lit("panels")); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); //- rjf: define all of the "fixed" tabs we care about -#define X(name) RD_Cfg *name = &rd_nil_cfg; -#define Y(name, rule, expr) RD_Cfg *name = &rd_nil_cfg; -#define Z(name) RD_Cfg *name = &rd_nil_cfg; +#define X(name) CFG_Node *name = &cfg_nil_node; +#define Y(name, rule, expr) CFG_Node *name = &cfg_nil_node; +#define Z(name) CFG_Node *name = &cfg_nil_node; RD_FixedTabXList #undef X #undef Y @@ -14397,14 +13631,14 @@ rd_frame(void) //- rjf: find all the fixed tabs, and all text viewers B32 any_fixed_tabs_found = 0; - RD_CfgList texts = {0}; + CFG_NodePtrList texts = {0}; for(RD_PanelNode *panel = panel_tree.root; panel != &rd_nil_panel_node; panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = panel->tabs.first; n != 0; n = n->next) { - RD_Cfg *tab = n->v; + CFG_Node *tab = n->v; B32 need_unhook = 1; if(0){} #define X(name) else if(str8_match(tab->string, str8_lit("watch"), 0) && str8_match(rd_expr_from_cfg(tab), str8_lit("query:" #name), 0)) {name = tab;} @@ -14414,46 +13648,46 @@ rd_frame(void) #undef X #undef Y #undef Z - else if(str8_match(tab->string, str8_lit("text"), 0)) {rd_cfg_list_push(scratch.arena, &texts, tab);} + else if(str8_match(tab->string, str8_lit("text"), 0)) {cfg_node_ptr_list_push(scratch.arena, &texts, tab);} else { need_unhook = 0; } if(need_unhook) { - rd_cfg_unhook(panel->cfg, tab); + cfg_node_unhook(rd_state->cfg, panel->cfg, tab); any_fixed_tabs_found = 1; } } } //- rjf: release the old panel tree - rd_cfg_release(panels); + cfg_node_release(rd_state->cfg, panels); //- rjf: allocate any missing tabs -#define X(name) if(name == &rd_nil_cfg) {name = rd_cfg_alloc(); rd_cfg_equip_string(name, str8_lit("watch")); RD_Cfg *expr_cfg = rd_cfg_new(name, str8_lit("expression")); rd_cfg_new(expr_cfg, str8_lit("query:" #name));} -#define Y(name, rule, expr) if(name == &rd_nil_cfg) {name = rd_cfg_alloc(); rd_cfg_equip_string(name, str8_lit(#rule)); RD_Cfg *expr_cfg = rd_cfg_new(name, str8_lit("expression")); rd_cfg_new(expr_cfg, str8_lit(expr));} -#define Z(name) if(name == &rd_nil_cfg && !any_fixed_tabs_found) {name = rd_cfg_alloc(); rd_cfg_equip_string(name, str8_lit(#name));} +#define X(name) if(name == &cfg_nil_node) {name = cfg_node_alloc(rd_state->cfg); cfg_node_equip_string(rd_state->cfg, name, str8_lit("watch")); CFG_Node *expr_cfg = cfg_node_new(rd_state->cfg, name, str8_lit("expression")); cfg_node_new(rd_state->cfg, expr_cfg, str8_lit("query:" #name));} +#define Y(name, rule, expr) if(name == &cfg_nil_node) {name = cfg_node_alloc(rd_state->cfg); cfg_node_equip_string(rd_state->cfg, name, str8_lit(#rule)); CFG_Node *expr_cfg = cfg_node_new(rd_state->cfg, name, str8_lit("expression")); cfg_node_new(rd_state->cfg, expr_cfg, str8_lit(expr));} +#define Z(name) if(name == &cfg_nil_node && !any_fixed_tabs_found) {name = cfg_node_alloc(rd_state->cfg); cfg_node_equip_string(rd_state->cfg, name, str8_lit(#name));} RD_FixedTabXList #undef X #undef Y #undef Z //- rjf: eliminate all tab selections -#define X(name) if(name != &rd_nil_cfg) {rd_cfg_release(rd_cfg_child_from_string(name, str8_lit("selected")));} -#define Y(name, rule, expr) if(name != &rd_nil_cfg) {rd_cfg_release(rd_cfg_child_from_string(name, str8_lit("selected")));} -#define Z(name) if(name != &rd_nil_cfg) {rd_cfg_release(rd_cfg_child_from_string(name, str8_lit("selected")));} +#define X(name) if(name != &cfg_nil_node) {cfg_node_release(rd_state->cfg, cfg_node_child_from_string(name, str8_lit("selected")));} +#define Y(name, rule, expr) if(name != &cfg_nil_node) {cfg_node_release(rd_state->cfg, cfg_node_child_from_string(name, str8_lit("selected")));} +#define Z(name) if(name != &cfg_nil_node) {cfg_node_release(rd_state->cfg, cfg_node_child_from_string(name, str8_lit("selected")));} RD_FixedTabXList #undef X #undef Y #undef Z - for(RD_CfgNode *n = texts.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = texts.first; n != 0; n = n->next) { - rd_cfg_release(rd_cfg_child_from_string(n->v, str8_lit("selected"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(n->v, str8_lit("selected"))); } //- rjf: create the panel root - panels = rd_cfg_new(window, str8_lit("panels")); + panels = cfg_node_new(rd_state->cfg, window, str8_lit("panels")); //- rjf: rebuild the new panel tree switch(kind) @@ -14464,161 +13698,161 @@ rd_frame(void) case RD_CmdKind_ResetToDefaultPanels: { // rjf: root split - rd_cfg_child_from_string_or_alloc(window, str8_lit("split_x")); - RD_Cfg *root_0 = rd_cfg_new(panels, str8_lit("0.85")); - RD_Cfg *root_1 = rd_cfg_new(panels, str8_lit("0.15")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("split_x")); + CFG_Node *root_0 = cfg_node_new(rd_state->cfg, panels, str8_lit("0.85")); + CFG_Node *root_1 = cfg_node_new(rd_state->cfg, panels, str8_lit("0.15")); // rjf: root_0 split - RD_Cfg *root_0_0 = rd_cfg_new(root_0, str8_lit("0.80")); - RD_Cfg *root_0_1 = rd_cfg_new(root_0, str8_lit("0.20")); + CFG_Node *root_0_0 = cfg_node_new(rd_state->cfg, root_0, str8_lit("0.80")); + CFG_Node *root_0_1 = cfg_node_new(rd_state->cfg, root_0, str8_lit("0.20")); // rjf: root_1 split - RD_Cfg *root_1_0 = rd_cfg_new(root_1, str8_lit("0.50")); - RD_Cfg *root_1_1 = rd_cfg_new(root_1, str8_lit("0.50")); - rd_cfg_insert_child(root_1_0, root_1_0->last, targets); - rd_cfg_insert_child(root_1_1, root_1_1->last, threads); - rd_cfg_insert_child(root_1_1, root_1_1->last, processes); - rd_cfg_insert_child(root_1_1, root_1_1->last, machines); - rd_cfg_new(targets, str8_lit("selected")); - rd_cfg_new(threads, str8_lit("selected")); + CFG_Node *root_1_0 = cfg_node_new(rd_state->cfg, root_1, str8_lit("0.50")); + CFG_Node *root_1_1 = cfg_node_new(rd_state->cfg, root_1, str8_lit("0.50")); + cfg_node_insert_child(rd_state->cfg, root_1_0, root_1_0->last, targets); + cfg_node_insert_child(rd_state->cfg, root_1_1, root_1_1->last, threads); + cfg_node_insert_child(rd_state->cfg, root_1_1, root_1_1->last, processes); + cfg_node_insert_child(rd_state->cfg, root_1_1, root_1_1->last, machines); + cfg_node_new(rd_state->cfg, targets, str8_lit("selected")); + cfg_node_new(rd_state->cfg, threads, str8_lit("selected")); // rjf: root 0_0 split - RD_Cfg *root_0_0_0 = rd_cfg_new(root_0_0, str8_lit("0.25")); - RD_Cfg *root_0_0_1 = rd_cfg_new(root_0_0, str8_lit("0.75")); + CFG_Node *root_0_0_0 = cfg_node_new(rd_state->cfg, root_0_0, str8_lit("0.25")); + CFG_Node *root_0_0_1 = cfg_node_new(rd_state->cfg, root_0_0, str8_lit("0.75")); // rjf: root_0_0_0 split - RD_Cfg *root_0_0_0_0 = rd_cfg_new(root_0_0_0, str8_lit("0.50")); - RD_Cfg *root_0_0_0_1 = rd_cfg_new(root_0_0_0, str8_lit("0.50")); - rd_cfg_insert_child(root_0_0_0_0, root_0_0_0_0->last, disasm); - rd_cfg_new(disasm, str8_lit("selected")); - rd_cfg_insert_child(root_0_0_0_1, root_0_0_0_1->last, breakpoints); - rd_cfg_insert_child(root_0_0_0_1, root_0_0_0_1->last, watch_pins); - rd_cfg_insert_child(root_0_0_0_1, root_0_0_0_1->last, output); - rd_cfg_insert_child(root_0_0_0_1, root_0_0_0_1->last, memory); - rd_cfg_new(output, str8_lit("selected")); + CFG_Node *root_0_0_0_0 = cfg_node_new(rd_state->cfg, root_0_0_0, str8_lit("0.50")); + CFG_Node *root_0_0_0_1 = cfg_node_new(rd_state->cfg, root_0_0_0, str8_lit("0.50")); + cfg_node_insert_child(rd_state->cfg, root_0_0_0_0, root_0_0_0_0->last, disasm); + cfg_node_new(rd_state->cfg, disasm, str8_lit("selected")); + cfg_node_insert_child(rd_state->cfg, root_0_0_0_1, root_0_0_0_1->last, breakpoints); + cfg_node_insert_child(rd_state->cfg, root_0_0_0_1, root_0_0_0_1->last, watch_pins); + cfg_node_insert_child(rd_state->cfg, root_0_0_0_1, root_0_0_0_1->last, output); + cfg_node_insert_child(rd_state->cfg, root_0_0_0_1, root_0_0_0_1->last, memory); + cfg_node_new(rd_state->cfg, output, str8_lit("selected")); // rjf: root_0_1 split - RD_Cfg *root_0_1_0 = rd_cfg_new(root_0_1, str8_lit("0.60")); - RD_Cfg *root_0_1_1 = rd_cfg_new(root_0_1, str8_lit("0.40")); - rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, watches); - rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, locals); - rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, registers); - rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, globals); - rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, thread_locals); - rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, types); - rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, procedures); - rd_cfg_new(watches, str8_lit("selected")); - rd_cfg_new(root_0_1_0, str8_lit("tabs_on_bottom")); - rd_cfg_insert_child(root_0_1_1, root_0_1_1->last, call_stack); - rd_cfg_insert_child(root_0_1_1, root_0_1_1->last, modules); - rd_cfg_new(call_stack, str8_lit("selected")); - rd_cfg_new(root_0_1_1, str8_lit("tabs_on_bottom")); + CFG_Node *root_0_1_0 = cfg_node_new(rd_state->cfg, root_0_1, str8_lit("0.60")); + CFG_Node *root_0_1_1 = cfg_node_new(rd_state->cfg, root_0_1, str8_lit("0.40")); + cfg_node_insert_child(rd_state->cfg, root_0_1_0, root_0_1_0->last, watches); + cfg_node_insert_child(rd_state->cfg, root_0_1_0, root_0_1_0->last, locals); + cfg_node_insert_child(rd_state->cfg, root_0_1_0, root_0_1_0->last, registers); + cfg_node_insert_child(rd_state->cfg, root_0_1_0, root_0_1_0->last, globals); + cfg_node_insert_child(rd_state->cfg, root_0_1_0, root_0_1_0->last, thread_locals); + cfg_node_insert_child(rd_state->cfg, root_0_1_0, root_0_1_0->last, types); + cfg_node_insert_child(rd_state->cfg, root_0_1_0, root_0_1_0->last, procedures); + cfg_node_new(rd_state->cfg, watches, str8_lit("selected")); + cfg_node_new(rd_state->cfg, root_0_1_0, str8_lit("tabs_on_bottom")); + cfg_node_insert_child(rd_state->cfg, root_0_1_1, root_0_1_1->last, call_stack); + cfg_node_insert_child(rd_state->cfg, root_0_1_1, root_0_1_1->last, modules); + cfg_node_new(rd_state->cfg, call_stack, str8_lit("selected")); + cfg_node_new(rd_state->cfg, root_0_1_1, str8_lit("tabs_on_bottom")); // rjf: fill main panel with getting started, OR all collected code views - RD_Cfg *main_panel = root_0_0_1; - if(getting_started != &rd_nil_cfg) + CFG_Node *main_panel = root_0_0_1; + if(getting_started != &cfg_nil_node) { - rd_cfg_insert_child(main_panel, main_panel->last, getting_started); - rd_cfg_new(getting_started, str8_lit("selected")); + cfg_node_insert_child(rd_state->cfg, main_panel, main_panel->last, getting_started); + cfg_node_new(rd_state->cfg, getting_started, str8_lit("selected")); } else if(texts.first) { - rd_cfg_new(texts.first->v, str8_lit("selected")); + cfg_node_new(rd_state->cfg, texts.first->v, str8_lit("selected")); } - for(RD_CfgNode *n = texts.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = texts.first; n != 0; n = n->next) { - rd_cfg_insert_child(main_panel, main_panel->last, n->v); + cfg_node_insert_child(rd_state->cfg, main_panel, main_panel->last, n->v); } // rjf: set main panel as selected - rd_cfg_new(main_panel, str8_lit("selected")); + cfg_node_new(rd_state->cfg, main_panel, str8_lit("selected")); }break; //- rjf: (compact layout) case RD_CmdKind_ResetToCompactPanels: { // rjf: root split - rd_cfg_child_from_string_or_alloc(window, str8_lit("split_x")); - RD_Cfg *root_0 = rd_cfg_new(panels, str8_lit("0.25")); - RD_Cfg *root_1 = rd_cfg_new(panels, str8_lit("0.75")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("split_x")); + CFG_Node *root_0 = cfg_node_new(rd_state->cfg, panels, str8_lit("0.25")); + CFG_Node *root_1 = cfg_node_new(rd_state->cfg, panels, str8_lit("0.75")); // rjf: root_0 split - RD_Cfg *root_0_0 = rd_cfg_new(root_0, str8_lit("0.25")); - RD_Cfg *root_0_1 = rd_cfg_new(root_0, str8_lit("0.25")); - RD_Cfg *root_0_2 = rd_cfg_new(root_0, str8_lit("0.25")); - RD_Cfg *root_0_3 = rd_cfg_new(root_0, str8_lit("0.25")); - rd_cfg_insert_child(root_0_0, root_0_0->last, watches); - rd_cfg_insert_child(root_0_0, root_0_0->last, types); - rd_cfg_new(watches, str8_lit("selected")); - rd_cfg_insert_child(root_0_1, root_0_1->last, threads); - rd_cfg_insert_child(root_0_1, root_0_1->last, targets); - rd_cfg_insert_child(root_0_1, root_0_1->last, breakpoints); - rd_cfg_insert_child(root_0_1, root_0_1->last, watch_pins); - rd_cfg_new(threads, str8_lit("selected")); - rd_cfg_insert_child(root_0_2, root_0_2->last, disasm); - rd_cfg_insert_child(root_0_2, root_0_2->last, output); - rd_cfg_new(disasm, str8_lit("selected")); - rd_cfg_insert_child(root_0_3, root_0_3->last, call_stack); - rd_cfg_insert_child(root_0_3, root_0_3->last, modules); - rd_cfg_new(call_stack, str8_lit("selected")); + CFG_Node *root_0_0 = cfg_node_new(rd_state->cfg, root_0, str8_lit("0.25")); + CFG_Node *root_0_1 = cfg_node_new(rd_state->cfg, root_0, str8_lit("0.25")); + CFG_Node *root_0_2 = cfg_node_new(rd_state->cfg, root_0, str8_lit("0.25")); + CFG_Node *root_0_3 = cfg_node_new(rd_state->cfg, root_0, str8_lit("0.25")); + cfg_node_insert_child(rd_state->cfg, root_0_0, root_0_0->last, watches); + cfg_node_insert_child(rd_state->cfg, root_0_0, root_0_0->last, types); + cfg_node_new(rd_state->cfg, watches, str8_lit("selected")); + cfg_node_insert_child(rd_state->cfg, root_0_1, root_0_1->last, threads); + cfg_node_insert_child(rd_state->cfg, root_0_1, root_0_1->last, targets); + cfg_node_insert_child(rd_state->cfg, root_0_1, root_0_1->last, breakpoints); + cfg_node_insert_child(rd_state->cfg, root_0_1, root_0_1->last, watch_pins); + cfg_node_new(rd_state->cfg, threads, str8_lit("selected")); + cfg_node_insert_child(rd_state->cfg, root_0_2, root_0_2->last, disasm); + cfg_node_insert_child(rd_state->cfg, root_0_2, root_0_2->last, output); + cfg_node_new(rd_state->cfg, disasm, str8_lit("selected")); + cfg_node_insert_child(rd_state->cfg, root_0_3, root_0_3->last, call_stack); + cfg_node_insert_child(rd_state->cfg, root_0_3, root_0_3->last, modules); + cfg_node_new(rd_state->cfg, call_stack, str8_lit("selected")); // rjf: fill main panel with getting started, OR all collected code views - RD_Cfg *main_panel = root_1; - if(getting_started != &rd_nil_cfg) + CFG_Node *main_panel = root_1; + if(getting_started != &cfg_nil_node) { - rd_cfg_insert_child(main_panel, main_panel->last, getting_started); - rd_cfg_new(getting_started, str8_lit("selected")); + cfg_node_insert_child(rd_state->cfg, main_panel, main_panel->last, getting_started); + cfg_node_new(rd_state->cfg, getting_started, str8_lit("selected")); } else if(texts.first) { - rd_cfg_new(texts.first->v, str8_lit("selected")); + cfg_node_new(rd_state->cfg, texts.first->v, str8_lit("selected")); } - for(RD_CfgNode *n = texts.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = texts.first; n != 0; n = n->next) { - rd_cfg_insert_child(main_panel, main_panel->last, n->v); + cfg_node_insert_child(rd_state->cfg, main_panel, main_panel->last, n->v); } // rjf: set main panel as selected - rd_cfg_new(main_panel, str8_lit("selected")); + cfg_node_new(rd_state->cfg, main_panel, str8_lit("selected")); }break; //- rjf: simple layout case RD_CmdKind_ResetToSimplePanels: { // rjf: root split - rd_cfg_child_from_string_or_alloc(window, str8_lit("split_x")); - RD_Cfg *root_0 = rd_cfg_new(panels, str8_lit("0.25")); - RD_Cfg *root_1 = rd_cfg_new(panels, str8_lit("0.75")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("split_x")); + CFG_Node *root_0 = cfg_node_new(rd_state->cfg, panels, str8_lit("0.25")); + CFG_Node *root_1 = cfg_node_new(rd_state->cfg, panels, str8_lit("0.75")); // rjf: fill smaller panel with watch - rd_cfg_insert_child(root_0, root_0->last, watches); - rd_cfg_new(watches, str8_lit("selected")); + cfg_node_insert_child(rd_state->cfg, root_0, root_0->last, watches); + cfg_node_new(rd_state->cfg, watches, str8_lit("selected")); // rjf: fill main panel with getting started, OR all collected code views - RD_Cfg *main_panel = root_1; - if(getting_started != &rd_nil_cfg) + CFG_Node *main_panel = root_1; + if(getting_started != &cfg_nil_node) { - rd_cfg_insert_child(main_panel, main_panel->last, getting_started); - rd_cfg_new(getting_started, str8_lit("selected")); + cfg_node_insert_child(rd_state->cfg, main_panel, main_panel->last, getting_started); + cfg_node_new(rd_state->cfg, getting_started, str8_lit("selected")); } else if(texts.first) { - rd_cfg_new(texts.first->v, str8_lit("selected")); + cfg_node_new(rd_state->cfg, texts.first->v, str8_lit("selected")); } - for(RD_CfgNode *n = texts.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = texts.first; n != 0; n = n->next) { - rd_cfg_insert_child(main_panel, main_panel->last, n->v); + cfg_node_insert_child(rd_state->cfg, main_panel, main_panel->last, n->v); } // rjf: set main panel as selected - rd_cfg_new(main_panel, str8_lit("selected")); + cfg_node_new(rd_state->cfg, main_panel, str8_lit("selected")); }break; } //- rjf: release any unused views from the previous layout -#define X(name) if(name->parent == &rd_nil_cfg) {rd_cfg_release(name);} -#define Y(name, rule, expr) if(name->parent == &rd_nil_cfg) {rd_cfg_release(name);} -#define Z(name) if(name->parent == &rd_nil_cfg) {rd_cfg_release(name);} +#define X(name) if(name->parent == &cfg_nil_node) {cfg_node_release(rd_state->cfg, name);} +#define Y(name, rule, expr) if(name->parent == &cfg_nil_node) {cfg_node_release(rd_state->cfg, name);} +#define Z(name) if(name->parent == &cfg_nil_node) {cfg_node_release(rd_state->cfg, name);} RD_FixedTabXList #undef X #undef Y @@ -14759,7 +13993,7 @@ rd_frame(void) String8List search_parts = str8_split_path(scratch.arena, file_part_of_name); // rjf: get source path - RD_Cfg *src_view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *src_view = cfg_node_from_id(rd_regs()->view); String8 src_view_expr = rd_expr_from_cfg(src_view); String8 src_file_path = rd_file_path_from_eval_string(scratch.arena, src_view_expr); String8List src_file_parts = str8_split_path(scratch.arena, src_file_path); @@ -14910,9 +14144,9 @@ rd_frame(void) struct WindowTask { WindowTask *next; - RD_Cfg *window; + CFG_Node *window; }; - WindowTask start_window_task = {0, rd_cfg_from_id(rd_regs()->window)}; + WindowTask start_window_task = {0, cfg_node_from_id(rd_regs()->window)}; WindowTask *first_window_task = &start_window_task; WindowTask *last_window_task = first_window_task; if(rd_regs()->all_windows) @@ -14925,7 +14159,7 @@ rd_frame(void) } WindowTask *t = push_array(scratch.arena, WindowTask, 1); SLLQueuePush(first_window_task, last_window_task, t); - t->window = rd_cfg_from_id(ws->cfg_id); + t->window = cfg_node_from_id(ws->cfg_id); } } @@ -14935,15 +14169,15 @@ rd_frame(void) struct WindowInfo { WindowInfo *next; - RD_Cfg *window; + CFG_Node *window; RD_PanelTree panel_tree; RD_PanelNode *panel_w_this_src_code; - RD_Cfg *view_w_this_src_code; + CFG_Node *view_w_this_src_code; RD_PanelNode *panel_w_auto; - RD_Cfg *view_w_auto; + CFG_Node *view_w_auto; RD_PanelNode *panel_w_any_src_code; RD_PanelNode *panel_w_disasm; - RD_Cfg *view_w_disasm; + CFG_Node *view_w_disasm; RD_PanelNode *biggest_panel; RD_PanelNode *biggest_empty_panel; }; @@ -14951,7 +14185,7 @@ rd_frame(void) WindowInfo *last_window_info = 0; for(WindowTask *t = first_window_task; t != 0; t = t->next) { - RD_Cfg *window = t->window; + CFG_Node *window = t->window; RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); WindowInfo *info = push_array(scratch.arena, WindowInfo, 1); SLLQueuePush(first_window_info, last_window_info, info); @@ -14960,7 +14194,7 @@ rd_frame(void) // rjf: first, try to find panel/view pair that already has the src file open info->panel_w_this_src_code = &rd_nil_panel_node; - info->view_w_this_src_code = &rd_nil_cfg; + info->view_w_this_src_code = &cfg_nil_node; for(RD_PanelNode *panel = panel_tree.root; panel != &rd_nil_panel_node; panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) @@ -14969,9 +14203,9 @@ rd_frame(void) { continue; } - for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - RD_Cfg *tab = tab_n->v; + CFG_Node *tab = tab_n->v; if(rd_cfg_is_project_filtered(tab)) { continue; } String8 tab_expr = rd_expr_from_cfg(tab); String8 tab_file_path = rd_file_path_from_eval_string(scratch.arena, tab_expr); @@ -14990,7 +14224,7 @@ rd_frame(void) // rjf: try to find panel/view pair that has any *auto* source code tab open info->panel_w_auto = &rd_nil_panel_node; - info->view_w_auto = &rd_nil_cfg; + info->view_w_auto = &cfg_nil_node; for(RD_PanelNode *panel = panel_tree.root; panel != &rd_nil_panel_node; panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) @@ -14999,9 +14233,9 @@ rd_frame(void) { continue; } - for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - RD_Cfg *tab = tab_n->v; + CFG_Node *tab = tab_n->v; if(rd_cfg_is_project_filtered(tab)) { continue; } RD_RegsScope(.tab = tab->id, .view = tab->id) { @@ -15031,9 +14265,9 @@ rd_frame(void) Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; - for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - RD_Cfg *tab = tab_n->v; + CFG_Node *tab = tab_n->v; if(rd_cfg_is_project_filtered(tab)) { continue; } String8 view_expr = rd_expr_from_cfg(tab); String8 file_path = rd_file_path_from_eval_string(scratch.arena, view_expr); @@ -15049,7 +14283,7 @@ rd_frame(void) // rjf: try to find panel/view pair that has disassembly open (prioritize largest) info->panel_w_disasm = &rd_nil_panel_node; - info->view_w_disasm = &rd_nil_cfg; + info->view_w_disasm = &cfg_nil_node; { Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); F32 best_panel_area = 0; @@ -15064,9 +14298,9 @@ rd_frame(void) Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; - for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - RD_Cfg *tab = tab_n->v; + CFG_Node *tab = tab_n->v; if(rd_cfg_is_project_filtered(tab)) { continue; } RD_RegsScope(.view = tab->id, .tab = tab->id) { @@ -15128,9 +14362,9 @@ rd_frame(void) Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; B32 panel_is_empty = 1; - for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = panel->tabs.first; n != 0; n = n->next) { - RD_Cfg *tab = n->v; + CFG_Node *tab = n->v; if(!rd_cfg_is_project_filtered(tab)) { panel_is_empty = 0; @@ -15152,15 +14386,15 @@ rd_frame(void) struct FindCodeLocTask { FindCodeLocTask *next; - RD_Cfg *window; + CFG_Node *window; RD_PanelNode *src_code_dst_panel; RD_PanelNode *disasm_dst_panel; RD_PanelNode *panel_w_this_src_code; - RD_Cfg *view_w_this_src_code; + CFG_Node *view_w_this_src_code; RD_PanelNode *panel_w_auto; - RD_Cfg *view_w_auto; + CFG_Node *view_w_auto; RD_PanelNode *panel_w_disasm; - RD_Cfg *view_w_disasm; + CFG_Node *view_w_disasm; }; FindCodeLocTask *first_task = 0; FindCodeLocTask *last_task = 0; @@ -15341,7 +14575,7 @@ rd_frame(void) // rjf: if disasm is not preferred, and we have no disassembly view // *selected* at all, cancel disasm, so that it doesn't open if the user // doesn't want it. - if(!rd_regs()->prefer_disasm && t->view_w_disasm != &rd_nil_cfg && rd_cfg_child_from_string(t->view_w_disasm, str8_lit("selected")) == &rd_nil_cfg && + if(!rd_regs()->prefer_disasm && t->view_w_disasm != &cfg_nil_node && cfg_node_child_from_string(t->view_w_disasm, str8_lit("selected")) == &cfg_nil_node && file_path.size != 0) { disasm_dst_panel = &rd_nil_panel_node; @@ -15353,26 +14587,26 @@ rd_frame(void) RD_PanelNode *dst_panel = src_code_dst_panel; // rjf: construct new view if needed - RD_Cfg *dst_tab = t->view_w_this_src_code; - if(dst_tab == &rd_nil_cfg && dst_panel == t->panel_w_auto && t->view_w_auto != &rd_nil_cfg) + CFG_Node *dst_tab = t->view_w_this_src_code; + if(dst_tab == &cfg_nil_node && dst_panel == t->panel_w_auto && t->view_w_auto != &cfg_nil_node) { dst_tab = t->view_w_auto; RD_ViewState *vs = rd_view_state_from_cfg(dst_tab); vs->last_frame_index_built = 0; - RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(dst_tab, str8_lit("expression")); - rd_cfg_new_replace(expr, rd_eval_string_from_file_path(scratch.arena, file_path)); - rd_cfg_new_replace(rd_cfg_child_from_string_or_alloc(dst_tab, str8_lit("cursor_line")), str8_lit("1")); - rd_cfg_new_replace(rd_cfg_child_from_string_or_alloc(dst_tab, str8_lit("cursor_column")), str8_lit("1")); - rd_cfg_new_replace(rd_cfg_child_from_string_or_alloc(dst_tab, str8_lit("mark_line")), str8_lit("1")); - rd_cfg_new_replace(rd_cfg_child_from_string_or_alloc(dst_tab, str8_lit("mark_column")), str8_lit("1")); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, dst_tab, str8_lit("expression")); + cfg_node_new_replace(rd_state->cfg, expr, rd_eval_string_from_file_path(scratch.arena, file_path)); + cfg_node_new_replace(rd_state->cfg, cfg_node_child_from_string_or_alloc(rd_state->cfg, dst_tab, str8_lit("cursor_line")), str8_lit("1")); + cfg_node_new_replace(rd_state->cfg, cfg_node_child_from_string_or_alloc(rd_state->cfg, dst_tab, str8_lit("cursor_column")), str8_lit("1")); + cfg_node_new_replace(rd_state->cfg, cfg_node_child_from_string_or_alloc(rd_state->cfg, dst_tab, str8_lit("mark_line")), str8_lit("1")); + cfg_node_new_replace(rd_state->cfg, cfg_node_child_from_string_or_alloc(rd_state->cfg, dst_tab, str8_lit("mark_column")), str8_lit("1")); } - else if(dst_panel != &rd_nil_panel_node && dst_tab == &rd_nil_cfg) + else if(dst_panel != &rd_nil_panel_node && dst_tab == &cfg_nil_node) { - dst_tab = rd_cfg_new(dst_panel->cfg, str8_lit("text")); - RD_Cfg *expr = rd_cfg_new(dst_tab, str8_lit("expression")); - rd_cfg_new(expr, rd_eval_string_from_file_path(scratch.arena, file_path)); - RD_Cfg *auto_root = rd_cfg_new(dst_tab, str8_lit("auto")); - rd_cfg_new(auto_root, str8_lit("1")); + dst_tab = cfg_node_new(rd_state->cfg, dst_panel->cfg, str8_lit("text")); + CFG_Node *expr = cfg_node_new(rd_state->cfg, dst_tab, str8_lit("expression")); + cfg_node_new(rd_state->cfg, expr, rd_eval_string_from_file_path(scratch.arena, file_path)); + CFG_Node *auto_root = cfg_node_new(rd_state->cfg, dst_tab, str8_lit("auto")); + cfg_node_new(rd_state->cfg, auto_root, str8_lit("1")); } // rjf: determine if we need a contain or center @@ -15410,10 +14644,10 @@ rd_frame(void) RD_PanelNode *dst_panel = disasm_dst_panel; // rjf: construct new tab if needed - RD_Cfg *dst_tab = t->view_w_disasm; - if(dst_panel != &rd_nil_panel_node && t->view_w_disasm == &rd_nil_cfg) + CFG_Node *dst_tab = t->view_w_disasm; + if(dst_panel != &rd_nil_panel_node && t->view_w_disasm == &cfg_nil_node) { - dst_tab = rd_cfg_new(dst_panel->cfg, str8_lit("disasm")); + dst_tab = cfg_node_new(rd_state->cfg, dst_panel->cfg, str8_lit("disasm")); } // rjf: determine if we need a contain or center @@ -15444,11 +14678,11 @@ rd_frame(void) RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); // rjf: floating queries -> set up window to build immediate-mode top-level query - RD_Cfg *view = &rd_nil_cfg; + CFG_Node *view = &cfg_nil_node; B32 is_floating = (cmd_name.size == 0 || cmd_kind_info->query.flags & RD_QueryFlag_Floating); if(is_floating) { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); if(ws != &rd_nil_window_state) { @@ -15456,46 +14690,46 @@ rd_frame(void) arena_clear(ws->query_arena); ws->query_regs = rd_regs_copy(ws->query_arena, rd_regs()); } - RD_Cfg *window_query = rd_immediate_cfg_from_keyf("window_query_%p", window); - rd_cfg_release_all_children(window_query); - view = rd_cfg_child_from_string_or_alloc(window_query, str8_lit("watch")); - RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); - rd_cfg_new_replace(expr, rd_regs()->expr); + CFG_Node *window_query = rd_immediate_cfg_from_keyf("window_query_%p", window); + cfg_node_release_all_children(rd_state->cfg, window_query); + view = cfg_node_child_from_string_or_alloc(rd_state->cfg, window_query, str8_lit("watch")); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("expression")); + cfg_node_new_replace(rd_state->cfg, expr, rd_regs()->expr); } // rjf: non-floating -> embed in view else { - view = rd_cfg_from_id(rd_regs()->view); + view = cfg_node_from_id(rd_regs()->view); } // rjf: determine if the target view is a lister (and thus already has a command) - B32 view_is_lister = (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg); + B32 view_is_lister = (cfg_node_child_from_string(view, str8_lit("lister")) != &cfg_nil_node); // rjf: target view is a lister -> do not do anything - cannot replace the command if(!view_is_lister) { // rjf: unpack view's query info - RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); - RD_Cfg *cmd = rd_cfg_child_from_string_or_alloc(query, str8_lit("cmd")); - RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); + CFG_Node *query = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("query")); + CFG_Node *cmd = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("cmd")); + CFG_Node *input = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("input")); if(is_floating) { if(rd_regs()->do_implicit_root) { - rd_cfg_release(rd_cfg_child_from_string(view, str8_lit("explicit_root"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(view, str8_lit("explicit_root"))); } else { - rd_cfg_child_from_string_or_alloc(view, str8_lit("explicit_root")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("explicit_root")); } if(!rd_regs()->do_lister) { - rd_cfg_release(rd_cfg_child_from_string(view, str8_lit("lister"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(view, str8_lit("lister"))); } else { - rd_cfg_child_from_string_or_alloc(view, str8_lit("lister")); + cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("lister")); } } @@ -15505,8 +14739,8 @@ rd_frame(void) { if(cmd_kind_info->query.slot == RD_RegSlot_FilePath) { - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_Cfg *current_path = rd_cfg_child_from_string(user, str8_lit("current_path")); + CFG_Node *user = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + CFG_Node *current_path = cfg_node_child_from_string(user, str8_lit("current_path")); String8 current_path_string = current_path->first->string; if(current_path_string.size == 0) { @@ -15523,8 +14757,8 @@ rd_frame(void) // rjf: build query state String8 current_query_cmd_name = cmd->first->string; - rd_cfg_new_replace(input, initial_input); - rd_cfg_new_replace(cmd, cmd_name); + cfg_node_new_replace(rd_state->cfg, input, initial_input); + cfg_node_new_replace(rd_state->cfg, cmd, cmd_name); RD_ViewState *vs = rd_view_state_from_cfg(view); if(cmd_name.size != 0) { @@ -15557,13 +14791,13 @@ rd_frame(void) case RD_CmdKind_CompleteQuery: { // rjf: unpack params - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); String8 cmd_name = rd_view_query_cmd(); // rjf: find out if this view is a lister - B32 is_lister = (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg); + B32 is_lister = (cfg_node_child_from_string(view, str8_lit("lister")) != &cfg_nil_node); // rjf: push command if(cmd_name.size != 0) RD_RegsScope() @@ -15591,7 +14825,7 @@ rd_frame(void) }break; case RD_CmdKind_CancelQuery: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); if(ws != &rd_nil_window_state) { @@ -15602,10 +14836,10 @@ rd_frame(void) }break; case RD_CmdKind_UpdateQuery: { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); - RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); - rd_cfg_new_replace(input, rd_regs()->string); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *query = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("query")); + CFG_Node *input = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("input")); + cfg_node_new_replace(rd_state->cfg, input, rd_regs()->string); RD_ViewState *vs = rd_view_state_from_cfg(view); vs->query_cursor = vs->query_mark = txt_pt(1, rd_regs()->string.size+1); vs->query_string_size = Min(sizeof(vs->query_buffer), rd_regs()->string.size); @@ -15615,15 +14849,15 @@ rd_frame(void) //- rjf: event buffers case RD_CmdKind_OpenEventBuffer: { - RD_Cfg *transient = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); - RD_Cfg *buffer = rd_cfg_new(transient, str8_lit("event_buffer")); + CFG_Node *transient = cfg_node_child_from_string(cfg_node_root(), str8_lit("transient")); + CFG_Node *buffer = cfg_node_new(rd_state->cfg, transient, str8_lit("event_buffer")); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, "$%I64x", buffer->id); }break; //- rjf: developer commands case RD_CmdKind_ToggleDevMenu: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); ws->dev_menu_is_open ^= 1; }break; @@ -15632,84 +14866,84 @@ rd_frame(void) case RD_CmdKind_SelectCfg: case RD_CmdKind_SelectTarget: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); - RD_CfgList all_of_the_same_kind = rd_cfg_top_level_list_from_string(scratch.arena, cfg->string); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); + CFG_NodePtrList all_of_the_same_kind = cfg_node_top_level_list_from_string(scratch.arena, cfg->string); B32 is_selected = !rd_disabled_from_cfg(cfg); - for(RD_CfgNode *n = all_of_the_same_kind.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = all_of_the_same_kind.first; n != 0; n = n->next) { - RD_Cfg *c = n->v; - rd_cfg_release(rd_cfg_child_from_string(c, str8_lit("enabled"))); + CFG_Node *c = n->v; + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(c, str8_lit("enabled"))); } - RD_Cfg *enabled_root = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("enabled")); - rd_cfg_new_replace(enabled_root, str8_lit("1")); + CFG_Node *enabled_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, str8_lit("enabled")); + cfg_node_new_replace(rd_state->cfg, enabled_root, str8_lit("1")); }break; case RD_CmdKind_EnableCfg: case RD_CmdKind_EnableBreakpoint: case RD_CmdKind_EnableTarget: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); - RD_Cfg *enabled_root = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("enabled")); - rd_cfg_new_replacef(enabled_root, "1"); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); + CFG_Node *enabled_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, str8_lit("enabled")); + cfg_node_new_replacef(rd_state->cfg, enabled_root, "1"); }break; case RD_CmdKind_DisableCfg: case RD_CmdKind_DisableBreakpoint: case RD_CmdKind_DisableTarget: case RD_CmdKind_DeselectCfg: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); - RD_Cfg *enabled_root = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("enabled")); - rd_cfg_new_replacef(enabled_root, "0"); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); + CFG_Node *enabled_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, str8_lit("enabled")); + cfg_node_new_replacef(rd_state->cfg, enabled_root, "0"); }break; case RD_CmdKind_RemoveCfg: case RD_CmdKind_RemoveBreakpoint: case RD_CmdKind_RemoveTarget: case RD_CmdKind_CloseEventBuffer: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); - rd_cfg_release(cfg); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); + cfg_node_release(rd_state->cfg, cfg); }break; case RD_CmdKind_NameCfg: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); if(rd_regs()->string.size != 0) { - RD_Cfg *label = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("label")); - rd_cfg_new(label, rd_regs()->string); + CFG_Node *label = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, str8_lit("label")); + cfg_node_new(rd_state->cfg, label, rd_regs()->string); } else { - rd_cfg_release(rd_cfg_child_from_string(cfg, str8_lit("label"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(cfg, str8_lit("label"))); } }break; case RD_CmdKind_ConditionCfg: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); if(rd_regs()->string.size != 0) { - RD_Cfg *cnd = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("condition")); - rd_cfg_new(cnd, rd_regs()->string); + CFG_Node *cnd = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, str8_lit("condition")); + cfg_node_new(rd_state->cfg, cnd, rd_regs()->string); } else { - rd_cfg_release(rd_cfg_child_from_string(cfg, str8_lit("condition"))); + cfg_node_release(rd_state->cfg, cfg_node_child_from_string(cfg, str8_lit("condition"))); } }break; case RD_CmdKind_DuplicateCfg: { - RD_Cfg *src = rd_cfg_from_id(rd_regs()->cfg); - RD_Cfg *dst = rd_cfg_deep_copy(src); - rd_cfg_insert_child(src->parent, src, dst); + CFG_Node *src = cfg_node_from_id(rd_regs()->cfg); + CFG_Node *dst = cfg_node_deep_copy(rd_state->cfg, src); + cfg_node_insert_child(rd_state->cfg, src->parent, src, dst); }break; case RD_CmdKind_RelocateCfg: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); // rjf: release old location info { - RD_Cfg *src_loc = rd_cfg_child_from_string(cfg, str8_lit("source_location")); - RD_Cfg *addr_loc = rd_cfg_child_from_string(cfg, str8_lit("address_location")); - rd_cfg_release(src_loc); - rd_cfg_release(addr_loc); + CFG_Node *src_loc = cfg_node_child_from_string(cfg, str8_lit("source_location")); + CFG_Node *addr_loc = cfg_node_child_from_string(cfg, str8_lit("address_location")); + cfg_node_release(rd_state->cfg, src_loc); + cfg_node_release(rd_state->cfg, addr_loc); } // rjf: attach new location info @@ -15724,22 +14958,22 @@ rd_frame(void) } if(file_path.size != 0 && pt.line != 0) { - RD_Cfg *src_loc = rd_cfg_new(cfg, str8_lit("source_location")); - rd_cfg_newf(src_loc, "%S:%I64d:%I64d", file_path, pt.line, pt.column); + CFG_Node *src_loc = cfg_node_new(rd_state->cfg, cfg, str8_lit("source_location")); + cfg_node_newf(rd_state->cfg, src_loc, "%S:%I64d:%I64d", file_path, pt.line, pt.column); } else if(expr_string.size != 0) { - RD_Cfg *vaddr_loc = rd_cfg_new(cfg, str8_lit("address_location")); - rd_cfg_new(vaddr_loc, expr_string); + CFG_Node *vaddr_loc = cfg_node_new(rd_state->cfg, cfg, str8_lit("address_location")); + cfg_node_new(rd_state->cfg, vaddr_loc, expr_string); } } }break; case RD_CmdKind_SaveToProject: { - RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); - rd_cfg_unhook(cfg->parent, cfg); - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - rd_cfg_insert_child(project, project->last, cfg); + CFG_Node *cfg = cfg_node_from_id(rd_regs()->cfg); + cfg_node_unhook(rd_state->cfg, cfg->parent, cfg); + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); + cfg_node_insert_child(rd_state->cfg, project, project->last, cfg); }break; //- rjf: breakpoints @@ -15757,11 +14991,11 @@ rd_frame(void) if(file_path.size != 0 || expr.size != 0) { B32 already_exists = 0; - RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); - for(RD_CfgNode *n = bps.first; n != 0; n = n->next) + CFG_NodePtrList bps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(CFG_NodePtrNode *n = bps.first; n != 0; n = n->next) { - RD_Cfg *bp = n->v; - RD_Cfg *cnd = rd_cfg_child_from_string(bp, str8_lit("condition")); + CFG_Node *bp = n->v; + CFG_Node *cnd = cfg_node_child_from_string(bp, str8_lit("condition")); RD_Location loc = rd_location_from_cfg(bp); B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == pt.line); B32 loc_matches_expr = (expr.size != 0 && str8_match(expr, loc.expr, 0)); @@ -15769,7 +15003,7 @@ rd_frame(void) { if(kind == RD_CmdKind_ToggleBreakpoint) { - rd_cfg_release(bp); + cfg_node_release(rd_state->cfg, bp); } already_exists = 1; break; @@ -15777,8 +15011,8 @@ rd_frame(void) } if(!already_exists) { - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - RD_Cfg *bp = rd_cfg_new(project, str8_lit("breakpoint")); + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); + CFG_Node *bp = cfg_node_new(rd_state->cfg, project, str8_lit("breakpoint")); rd_cmd(RD_CmdKind_RelocateCfg, .cfg = bp->id); if(rd_regs()->do_lister && !rd_regs()->non_graphical) { @@ -15798,18 +15032,18 @@ rd_frame(void) }break; case RD_CmdKind_ClearBreakpoints: { - RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); - for(RD_CfgNode *n = bps.first; n != 0; n = n->next) + CFG_NodePtrList bps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(CFG_NodePtrNode *n = bps.first; n != 0; n = n->next) { - rd_cfg_release(n->v); + cfg_node_release(rd_state->cfg, n->v); } }break; case RD_CmdKind_ListBreakpoints: { - RD_CfgList list = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); - for(RD_CfgNode *n = list.first; n != 0; n = n->next) + CFG_NodePtrList list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(CFG_NodePtrNode *n = list.first; n != 0; n = n->next) { - String8 string = rd_string_from_cfg_tree(rd_state->cmd_output_arena, str8_zero(), n->v); + String8 string = cfg_string_from_tree(rd_state->cmd_output_arena, rd_state->cfg_schema_table, str8_zero(), n->v); str8_list_push(rd_state->cmd_output_arena, &rd_state->cmd_outputs, string); } }break; @@ -15832,27 +15066,27 @@ rd_frame(void) B32 removed_already_existing = 0; if(kind == RD_CmdKind_ToggleWatchPin) { - RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); - for(RD_CfgNode *n = wps.first; n != 0; n = n->next) + CFG_NodePtrList wps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); + for(CFG_NodePtrNode *n = wps.first; n != 0; n = n->next) { - RD_Cfg *wp = n->v; - RD_Cfg *expr = rd_cfg_child_from_string(wp, str8_lit("expression")); + CFG_Node *wp = n->v; + CFG_Node *expr = cfg_node_child_from_string(wp, str8_lit("expression")); RD_Location loc = rd_location_from_cfg(wp); B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == pt.line); B32 loc_matches_expr = (expr_string.size != 0 && str8_match(expr_string, loc.expr, 0)); if((loc_matches_file_pt || loc_matches_expr) && str8_match(expr->first->string, expr_string, 0)) { - rd_cfg_release(wp); + cfg_node_release(rd_state->cfg, wp); removed_already_existing = 1; } } } if(!removed_already_existing) { - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - RD_Cfg *wp = rd_cfg_new(project, str8_lit("watch_pin")); - RD_Cfg *expr = rd_cfg_new(wp, str8_lit("expression")); - rd_cfg_new(expr, expr_string); + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); + CFG_Node *wp = cfg_node_new(rd_state->cfg, project, str8_lit("watch_pin")); + CFG_Node *expr = cfg_node_new(rd_state->cfg, wp, str8_lit("expression")); + cfg_node_new(rd_state->cfg, expr, expr_string); rd_cmd(RD_CmdKind_RelocateCfg, .cfg = wp->id, .expr = str8_zero()); } }break; @@ -15860,54 +15094,54 @@ rd_frame(void) //- rjf: type views case RD_CmdKind_AddTypeView: { - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - rd_cfg_new(project, str8_lit("type_view")); + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); + cfg_node_new(rd_state->cfg, project, str8_lit("type_view")); }break; //- rjf: file path maps case RD_CmdKind_AddFilePathMap: { - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - rd_cfg_new(project, str8_lit("file_path_map")); + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); + cfg_node_new(rd_state->cfg, project, str8_lit("file_path_map")); }break; //- rjf: themes case RD_CmdKind_EditUserTheme: { - RD_Cfg *parent = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + CFG_Node *parent = cfg_node_child_from_string(cfg_node_root(), str8_lit("user")); rd_cmd(RD_CmdKind_PushQuery, .expr = push_str8f(scratch.arena, "query:config.$%I64x.theme_colors", parent->id)); }break; case RD_CmdKind_EditProjectTheme: { - RD_Cfg *parent = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + CFG_Node *parent = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); rd_cmd(RD_CmdKind_PushQuery, .expr = push_str8f(scratch.arena, "query:config.$%I64x.theme_colors", parent->id)); }break; case RD_CmdKind_AddThemeColor: { Access *access = access_open(); - RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); - RD_Cfg *theme = rd_cfg_child_from_string_or_alloc(parent, str8_lit("theme")); + CFG_Node *parent = cfg_node_from_id(rd_regs()->cfg); + CFG_Node *theme = cfg_node_child_from_string_or_alloc(rd_state->cfg, parent, str8_lit("theme")); MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, access, theme->first->string); if(theme_tree == &md_nil_node) { - rd_cfg_new_replace(theme, rd_theme_preset_display_string_table[RD_ThemePreset_DefaultDark]); + cfg_node_new_replace(rd_state->cfg, theme, rd_theme_preset_display_string_table[RD_ThemePreset_DefaultDark]); } - RD_Cfg *color = rd_cfg_new(parent, str8_lit("theme_color")); - rd_cfg_new(color, str8_lit("tags")); - RD_Cfg *value = rd_cfg_new(color, str8_lit("value")); - rd_cfg_new(value, str8_lit("0xffffffff")); + CFG_Node *color = cfg_node_new(rd_state->cfg, parent, str8_lit("theme_color")); + cfg_node_new(rd_state->cfg, color, str8_lit("tags")); + CFG_Node *value = cfg_node_new(rd_state->cfg, color, str8_lit("value")); + cfg_node_new(rd_state->cfg, value, str8_lit("0xffffffff")); access_close(access); }break; case RD_CmdKind_ForkTheme: { Access *access = access_open(); - RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); - RD_CfgList colors = rd_cfg_child_list_from_string(scratch.arena, parent, str8_lit("theme_color")); - for(RD_CfgNode *n = colors.first; n != 0; n = n->next) + CFG_Node *parent = cfg_node_from_id(rd_regs()->cfg); + CFG_NodePtrList colors = cfg_node_child_list_from_string(scratch.arena, parent, str8_lit("theme_color")); + for(CFG_NodePtrNode *n = colors.first; n != 0; n = n->next) { - rd_cfg_release(n->v); + cfg_node_release(rd_state->cfg, n->v); } - RD_Cfg *theme_cfg = rd_cfg_child_from_string(parent, str8_lit("theme")); + CFG_Node *theme_cfg = cfg_node_child_from_string(parent, str8_lit("theme")); String8 theme_name = theme_cfg->first->string; MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, access, theme_name); if(theme_tree == &md_nil_node) @@ -15918,14 +15152,14 @@ rd_frame(void) { if(str8_match(n->string, str8_lit("theme_color"), 0)) { - RD_Cfg *color = rd_cfg_new(parent, str8_lit("theme_color")); - RD_Cfg *tags = rd_cfg_new(color, str8_lit("tags")); - RD_Cfg *value = rd_cfg_new(color, str8_lit("value")); - rd_cfg_new(tags, md_child_from_string(n, str8_lit("tags"), 0)->first->string); - rd_cfg_new(value, md_child_from_string(n, str8_lit("value"), 0)->first->string); + CFG_Node *color = cfg_node_new(rd_state->cfg, parent, str8_lit("theme_color")); + CFG_Node *tags = cfg_node_new(rd_state->cfg, color, str8_lit("tags")); + CFG_Node *value = cfg_node_new(rd_state->cfg, color, str8_lit("value")); + cfg_node_new(rd_state->cfg, tags, md_child_from_string(n, str8_lit("tags"), 0)->first->string); + cfg_node_new(rd_state->cfg, value, md_child_from_string(n, str8_lit("value"), 0)->first->string); } } - rd_cfg_release(theme_cfg); + cfg_node_release(rd_state->cfg, theme_cfg); access_close(access); }break; case RD_CmdKind_SaveTheme: @@ -15938,24 +15172,24 @@ rd_frame(void) if(os_make_directory(themes_folder)) { String8 dst_path = push_str8f(scratch.arena, "%S/%S", themes_folder, name); - RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); - RD_CfgList colors = rd_cfg_child_list_from_string(scratch.arena, parent, str8_lit("theme_color")); + CFG_Node *parent = cfg_node_from_id(rd_regs()->cfg); + CFG_NodePtrList colors = cfg_node_child_list_from_string(scratch.arena, parent, str8_lit("theme_color")); String8List strings = {0}; - for(RD_CfgNode *n = colors.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = colors.first; n != 0; n = n->next) { - str8_list_push(scratch.arena, &strings, rd_string_from_cfg_tree(scratch.arena, str8_chop_last_slash(dst_path), n->v)); + str8_list_push(scratch.arena, &strings, cfg_string_from_tree(scratch.arena, rd_state->cfg_schema_table, str8_chop_last_slash(dst_path), n->v)); } String8 data = str8_list_join(scratch.arena, &strings, 0); if(os_write_data_to_file_path(dst_path, data)) { if(kind == RD_CmdKind_SaveAndSetTheme) { - for(RD_CfgNode *n = colors.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = colors.first; n != 0; n = n->next) { - rd_cfg_release(n->v); + cfg_node_release(rd_state->cfg, n->v); } - RD_Cfg *theme = rd_cfg_child_from_string_or_alloc(parent, str8_lit("theme")); - rd_cfg_new_replace(theme, name); + CFG_Node *theme = cfg_node_child_from_string_or_alloc(rd_state->cfg, parent, str8_lit("theme")); + cfg_node_new_replace(rd_state->cfg, theme, name); } } else @@ -15971,23 +15205,23 @@ rd_frame(void) if(rd_regs()->string.size != 0) { // rjf: pick a watch tab from all the windows to toggle this expression within - RD_Cfg *watch_tab = &rd_nil_cfg; + CFG_Node *watch_tab = &cfg_nil_node; { B32 watch_tab_has_no_label = 0; B32 watch_tab_matches_src_window = 0; - RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); - for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + CFG_NodePtrList windows = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(CFG_NodePtrNode *n = windows.first; n != 0; n = n->next) { - RD_Cfg *window = n->v; + CFG_Node *window = n->v; RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, window); for(RD_PanelNode *panel = panels.root; panel != &rd_nil_panel_node; panel = rd_panel_node_rec__depth_first_pre(panels.root, panel).next) { - for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - RD_Cfg *tab = tab_n->v; - RD_Cfg *label = rd_cfg_child_from_string(tab, str8_lit("label")); + CFG_Node *tab = tab_n->v; + CFG_Node *label = cfg_node_child_from_string(tab, str8_lit("label")); if(str8_match(tab->string, str8_lit("watch"), 0) && rd_expr_from_cfg(tab).size == 0) { @@ -15995,7 +15229,7 @@ rd_frame(void) B32 tab_matches_src_window = (window->id == rd_regs()->window); if(tab_has_no_label > watch_tab_has_no_label || tab_matches_src_window > watch_tab_matches_src_window || - watch_tab == &rd_nil_cfg) + watch_tab == &cfg_nil_node) { watch_tab = tab; if(tab_has_no_label && tab_matches_src_window) @@ -16011,8 +15245,8 @@ rd_frame(void) } // rjf: find the existing watch in the selected tab, if it exists - RD_Cfg *existing_watch = &rd_nil_cfg; - for(RD_Cfg *child = watch_tab->first; child != &rd_nil_cfg; child = child->next) + CFG_Node *existing_watch = &cfg_nil_node; + for(CFG_Node *child = watch_tab->first; child != &cfg_nil_node; child = child->next) { if(str8_match(child->string, str8_lit("watch"), 0) && str8_match(child->first->string, rd_regs()->string, 0)) { @@ -16022,16 +15256,16 @@ rd_frame(void) } // rjf: if this watch exists -> delete it - if(existing_watch != &rd_nil_cfg) + if(existing_watch != &cfg_nil_node) { - rd_cfg_release(existing_watch); + cfg_node_release(rd_state->cfg, existing_watch); } // rjf: otherwise, create it - else if(watch_tab != &rd_nil_cfg) + else if(watch_tab != &cfg_nil_node) { - RD_Cfg *watch = rd_cfg_new(watch_tab, str8_lit("watch")); - rd_cfg_new(watch, rd_regs()->string); + CFG_Node *watch = cfg_node_new(rd_state->cfg, watch_tab, str8_lit("watch")); + cfg_node_new(rd_state->cfg, watch, rd_regs()->string); } }break; @@ -16089,15 +15323,15 @@ rd_frame(void) case RD_CmdKind_AddTarget: { String8 file_path = rd_regs()->file_path; - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - RD_Cfg *target = rd_cfg_new(project, str8_lit("target")); - RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable")); - rd_cfg_new(exe, file_path); + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); + CFG_Node *target = cfg_node_new(rd_state->cfg, project, str8_lit("target")); + CFG_Node *exe = cfg_node_new(rd_state->cfg, target, str8_lit("executable")); + cfg_node_new(rd_state->cfg, exe, file_path); String8 working_directory = str8_chop_last_slash(file_path); if(working_directory.size != 0) { - RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory")); - rd_cfg_newf(wdir, "%S/", working_directory); + CFG_Node *wdir = cfg_node_new(rd_state->cfg, target, str8_lit("working_directory")); + cfg_node_newf(rd_state->cfg, wdir, "%S/", working_directory); } rd_cmd(RD_CmdKind_SelectTarget, .cfg = target->id); if(!rd_regs()->non_graphical) @@ -16255,7 +15489,7 @@ rd_frame(void) //- rjf: meta controls case RD_CmdKind_Edit: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Press; @@ -16264,7 +15498,7 @@ rd_frame(void) }break; case RD_CmdKind_Accept: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Press; @@ -16273,7 +15507,7 @@ rd_frame(void) }break; case RD_CmdKind_Cancel: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Press; @@ -16289,7 +15523,7 @@ rd_frame(void) // case RD_CmdKind_MoveLeft: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16300,7 +15534,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveRight: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16311,7 +15545,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUp: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16322,7 +15556,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDown: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16333,7 +15567,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveLeftSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16344,7 +15578,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveRightSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16355,7 +15589,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16366,7 +15600,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16377,7 +15611,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveLeftChunk: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16388,7 +15622,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveRightChunk: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16399,7 +15633,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpChunk: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16410,7 +15644,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownChunk: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16421,7 +15655,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpPage: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16432,7 +15666,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownPage: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16443,7 +15677,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpWhole: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16454,7 +15688,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownWhole: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16465,7 +15699,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveLeftChunkSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16476,7 +15710,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveRightChunkSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16487,7 +15721,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpChunkSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16498,7 +15732,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownChunkSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16509,7 +15743,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpPageSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16520,7 +15754,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownPageSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16531,7 +15765,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpWholeSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16542,7 +15776,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownWholeSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16553,7 +15787,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpReorder: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16564,7 +15798,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownReorder: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16575,7 +15809,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveHome: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16585,7 +15819,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveEnd: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16595,7 +15829,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveHomeSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16606,7 +15840,7 @@ rd_frame(void) }break; case RD_CmdKind_MoveEndSelect: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16617,7 +15851,7 @@ rd_frame(void) }break; case RD_CmdKind_SelectAll: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt1 = zero_struct; evt1.kind = UI_EventKind_Navigate; @@ -16633,7 +15867,7 @@ rd_frame(void) }break; case RD_CmdKind_DeleteSingle: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; @@ -16644,7 +15878,7 @@ rd_frame(void) }break; case RD_CmdKind_DeleteChunk: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; @@ -16655,7 +15889,7 @@ rd_frame(void) }break; case RD_CmdKind_BackspaceSingle: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; @@ -16666,7 +15900,7 @@ rd_frame(void) }break; case RD_CmdKind_BackspaceChunk: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; @@ -16677,7 +15911,7 @@ rd_frame(void) }break; case RD_CmdKind_Copy: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; @@ -16686,7 +15920,7 @@ rd_frame(void) }break; case RD_CmdKind_Cut: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; @@ -16695,7 +15929,7 @@ rd_frame(void) }break; case RD_CmdKind_Paste: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Text; @@ -16704,7 +15938,7 @@ rd_frame(void) }break; case RD_CmdKind_InsertText: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Text; @@ -16715,7 +15949,7 @@ rd_frame(void) //- rjf: directionless navigation case RD_CmdKind_MoveNext: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16726,7 +15960,7 @@ rd_frame(void) }break; case RD_CmdKind_MovePrev: { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; @@ -16745,13 +15979,13 @@ rd_frame(void) D_TargetArray targets = {0}; ProfScope("gather targets") { - RD_CfgList target_cfgs = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("target")); + CFG_NodePtrList target_cfgs = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("target")); targets.count = target_cfgs.count; targets.v = push_array(scratch.arena, D_Target, targets.count); U64 idx = 0; - for(RD_CfgNode *n = target_cfgs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = target_cfgs.first; n != 0; n = n->next) { - RD_Cfg *src = n->v; + CFG_Node *src = n->v; B32 src_is_disabled = rd_disabled_from_cfg(src); if(src_is_disabled) { @@ -16769,13 +16003,13 @@ rd_frame(void) D_BreakpointArray breakpoints = {0}; ProfScope("gather breakpoints & meta-evals") { - RD_CfgList bp_cfgs = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + CFG_NodePtrList bp_cfgs = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); breakpoints.count = bp_cfgs.count; breakpoints.v = push_array(scratch.arena, D_Breakpoint, breakpoints.count); U64 idx = 0; - for(RD_CfgNode *n = bp_cfgs.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = bp_cfgs.first; n != 0; n = n->next) { - RD_Cfg *src_bp = n->v; + CFG_Node *src_bp = n->v; B32 src_bp_is_disabled = rd_disabled_from_cfg(src_bp); if(src_bp_is_disabled) { @@ -16783,7 +16017,7 @@ rd_frame(void) continue; } RD_Location src_bp_loc = rd_location_from_cfg(src_bp); - String8 src_bp_cnd = rd_cfg_child_from_string(src_bp, str8_lit("condition"))->first->string; + String8 src_bp_cnd = cfg_node_child_from_string(src_bp, str8_lit("condition"))->first->string; //- rjf: walk conditional breakpoint expression tree - for each leaf identifier, // determine if it resolves to a meta-evaluation. if it does, compute the meta @@ -16861,15 +16095,15 @@ rd_frame(void) //- rjf: compute breakpoint flags D_BreakpointFlags flags = 0; - if(str8_match(rd_cfg_child_from_string(src_bp, str8_lit("break_on_write"))->first->string, str8_lit("1"), 0)) + if(str8_match(cfg_node_child_from_string(src_bp, str8_lit("break_on_write"))->first->string, str8_lit("1"), 0)) { flags |= D_BreakpointFlag_BreakOnWrite; } - if(str8_match(rd_cfg_child_from_string(src_bp, str8_lit("break_on_read"))->first->string, str8_lit("1"), 0)) + if(str8_match(cfg_node_child_from_string(src_bp, str8_lit("break_on_read"))->first->string, str8_lit("1"), 0)) { flags |= D_BreakpointFlag_BreakOnRead; } - if(str8_match(rd_cfg_child_from_string(src_bp, str8_lit("break_on_execute"))->first->string, str8_lit("1"), 0)) + if(str8_match(cfg_node_child_from_string(src_bp, str8_lit("break_on_execute"))->first->string, str8_lit("1"), 0)) { flags |= D_BreakpointFlag_BreakOnExecute; } @@ -16877,7 +16111,7 @@ rd_frame(void) //- rjf: compute address range size U64 addr_range_size = 0; { - RD_Cfg *address_range_size_cfg = rd_cfg_child_from_string(src_bp, str8_lit("address_range_size")); + CFG_Node *address_range_size_cfg = cfg_node_child_from_string(src_bp, str8_lit("address_range_size")); try_u64_from_str8_c_rules(address_range_size_cfg->first->string, &addr_range_size); } @@ -16899,15 +16133,15 @@ rd_frame(void) // D_PathMapArray path_maps = {0}; { - RD_CfgList maps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); + CFG_NodePtrList maps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); path_maps.count = maps.count; path_maps.v = push_array(scratch.arena, D_PathMap, path_maps.count); U64 idx = 0; - for(RD_CfgNode *n = maps.first; n != 0; n = n->next, idx += 1) + for(CFG_NodePtrNode *n = maps.first; n != 0; n = n->next, idx += 1) { - RD_Cfg *map = n->v; - path_maps.v[idx].src = rd_cfg_child_from_string(map, str8_lit("source"))->first->string; - path_maps.v[idx].dst = rd_cfg_child_from_string(map, str8_lit("dest"))->first->string; + CFG_Node *map = n->v; + path_maps.v[idx].src = cfg_node_child_from_string(map, str8_lit("source"))->first->string; + path_maps.v[idx].dst = cfg_node_child_from_string(map, str8_lit("dest"))->first->string; } } @@ -16989,14 +16223,14 @@ rd_frame(void) // rjf: increment breakpoint hit counts if(evt->cause == D_EventCause_UserBreakpoint) { - RD_Cfg *bp = rd_cfg_from_id(evt->id); - if(bp != &rd_nil_cfg) + CFG_Node *bp = cfg_node_from_id(evt->id); + if(bp != &cfg_nil_node) { - RD_Cfg *hit_count_root = rd_cfg_child_from_string_or_alloc(bp, str8_lit("hit_count")); + CFG_Node *hit_count_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, bp, str8_lit("hit_count")); U64 hit_count = 0; try_u64_from_str8_c_rules(hit_count_root->first->string, &hit_count); hit_count += 1; - rd_cfg_new_replacef(hit_count_root, "%I64u", hit_count); + cfg_node_new_replacef(rd_state->cfg, hit_count_root, "%I64u", hit_count); } } @@ -17014,7 +16248,7 @@ rd_frame(void) } if(!any_window_is_focused) { - RD_Cfg *last_focused_window = rd_cfg_from_id(rd_state->last_focused_window); + CFG_Node *last_focused_window = cfg_node_from_id(rd_state->last_focused_window); RD_WindowState *ws = rd_window_state_from_cfg(last_focused_window); if(ws == &rd_nil_window_state) { @@ -17108,13 +16342,13 @@ rd_frame(void) rd_state->ambiguous_path_slots = push_array(rd_frame_arena(), RD_AmbiguousPathNode *, rd_state->ambiguous_path_slots_count); for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) { - RD_Cfg *window = rd_cfg_from_id(ws->cfg_id); + CFG_Node *window = cfg_node_from_id(ws->cfg_id); RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { - for(RD_CfgNode *tab_n = p->tabs.first; tab_n != 0; tab_n = tab_n->next) + for(CFG_NodePtrNode *tab_n = p->tabs.first; tab_n != 0; tab_n = tab_n->next) { - RD_Cfg *tab = tab_n->v; + CFG_Node *tab = tab_n->v; if(rd_cfg_is_project_filtered(tab)) { continue; @@ -17189,10 +16423,10 @@ rd_frame(void) // { dr_begin_frame(rd_font_from_slot(RD_FontSlot_Icons)); - RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); - for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + CFG_NodePtrList windows = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(CFG_NodePtrNode *n = windows.first; n != 0; n = n->next) { - RD_Cfg *window = n->v; + CFG_Node *window = n->v; RD_WindowState *w = rd_window_state_from_cfg(window); B32 window_is_focused = os_window_is_focused(w->os); if(window_is_focused) @@ -17220,8 +16454,8 @@ rd_frame(void) for(RD_WindowState *ws = rd_state->window_state_slots[slot_idx].first, *next; ws != 0; ws = next) { next = ws->hash_next; - RD_Cfg *cfg = rd_cfg_from_id(ws->cfg_id); - if(cfg == &rd_nil_cfg || ws->last_frame_index_touched < rd_state->frame_index || rd_state->quit) + CFG_Node *cfg = cfg_node_from_id(ws->cfg_id); + if(cfg == &cfg_nil_node || ws->last_frame_index_touched < rd_state->frame_index || rd_state->quit) { ui_state_release(ws->ui); r_window_unequip(ws->os, ws->r); @@ -17303,7 +16537,7 @@ rd_frame(void) } for(CFG_IDNode *n = windows_to_show.first; n != 0; n = n->next) { - RD_Cfg *window = rd_cfg_from_id(n->v); + CFG_Node *window = cfg_node_from_id(n->v); RD_WindowState *ws = rd_window_state_from_cfg(window); os_window_first_paint(ws->os); } diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 7afccd02..a9af5770 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -247,59 +247,6 @@ struct RD_VocabInfoMap RD_VocabInfoMapSlot *plural_slots; }; -//////////////////////////////// -//~ rjf: Config Tree - -typedef struct RD_Cfg RD_Cfg; -struct RD_Cfg -{ - RD_Cfg *first; - RD_Cfg *last; - RD_Cfg *next; - RD_Cfg *prev; - RD_Cfg *parent; - CFG_ID id; - String8 string; -}; - -typedef struct RD_CfgNode RD_CfgNode; -struct RD_CfgNode -{ - RD_CfgNode *next; - RD_CfgNode *prev; - RD_Cfg *v; -}; - -typedef struct RD_CfgSlot RD_CfgSlot; -struct RD_CfgSlot -{ - RD_CfgNode *first; - RD_CfgNode *last; -}; - -typedef struct RD_CfgList RD_CfgList; -struct RD_CfgList -{ - RD_CfgNode *first; - RD_CfgNode *last; - U64 count; -}; - -typedef struct RD_CfgArray RD_CfgArray; -struct RD_CfgArray -{ - RD_Cfg **v; - U64 count; -}; - -typedef struct RD_CfgRec RD_CfgRec; -struct RD_CfgRec -{ - RD_Cfg *next; - S32 push_count; - S32 pop_count; -}; - //////////////////////////////// //~ rjf: Structured Locations, Parsed From Config Trees @@ -324,7 +271,7 @@ struct RD_PanelNode RD_PanelNode *prev; RD_PanelNode *parent; U64 child_count; - RD_Cfg *cfg; + CFG_Node *cfg; // rjf: split data Axis2 split_axis; @@ -334,8 +281,8 @@ struct RD_PanelNode Side tab_side; // rjf: which tabs are attached - RD_CfgList tabs; - RD_Cfg *selected_tab; + CFG_NodePtrList tabs; + CFG_Node *selected_tab; }; typedef struct RD_PanelTree RD_PanelTree; @@ -489,25 +436,6 @@ struct RD_WindowStateSlot //////////////////////////////// //~ rjf: Main Per-Process Graphical State -read_only global U64 rd_name_bucket_chunk_sizes[] = -{ - 16, - 64, - 256, - 1024, - 4096, - 16384, - 65536, - 0xffffffffffffffffull, -}; - -typedef struct RD_NameChunkNode RD_NameChunkNode; -struct RD_NameChunkNode -{ - RD_NameChunkNode *next; - U64 size; -}; - typedef struct RD_AmbiguousPathNode RD_AmbiguousPathNode; struct RD_AmbiguousPathNode { @@ -555,9 +483,6 @@ struct RD_State C_Key cmdln_cfg_string_key; C_Key transient_cfg_string_key; - // rjf: schema table - MD_NodePtrList *schemas; - // rjf: default theme table MD_Node *theme_preset_trees[RD_ThemePreset_COUNT]; @@ -645,16 +570,8 @@ struct RD_State RD_DragDropState drag_drop_state; // rjf: cfg state - RD_NameChunkNode *free_name_chunks[ArrayCount(rd_name_bucket_chunk_sizes)]; - RD_Cfg *free_cfg; - RD_Cfg *root_cfg; - U64 cfg_id_slots_count; - RD_CfgSlot *cfg_id_slots; - RD_CfgNode *free_cfg_id_node; - U64 cfg_id_gen; - CFG_ID cfg_last_accessed_id; - RD_Cfg *cfg_last_accessed; - U64 cfg_change_gen; + CFG_State *cfg; + CFG_SchemaTable *cfg_schema_table; // rjf: window state cache U64 window_state_slots_count; @@ -688,15 +605,6 @@ struct RD_State read_only global RD_VocabInfo rd_nil_vocab_info = {0}; -read_only global RD_Cfg rd_nil_cfg = -{ - &rd_nil_cfg, - &rd_nil_cfg, - &rd_nil_cfg, - &rd_nil_cfg, - &rd_nil_cfg, -}; - read_only global RD_PanelNode rd_nil_panel_node = { &rd_nil_panel_node, @@ -705,8 +613,8 @@ read_only global RD_PanelNode rd_nil_panel_node = &rd_nil_panel_node, &rd_nil_panel_node, 0, - &rd_nil_cfg, - .selected_tab = &rd_nil_cfg, + &cfg_nil_node, + .selected_tab = &cfg_nil_node, }; read_only global RD_CmdKindInfo rd_nil_cmd_kind_info = {0}; @@ -767,65 +675,30 @@ internal void rd_set_hover_regs(RD_RegSlot slot); internal RD_Regs *rd_get_hover_regs(void); //////////////////////////////// -//~ rjf: Name Allocation +//~ rjf: Config Functions -internal U64 rd_name_bucket_num_from_string_size(U64 size); -internal String8 rd_name_alloc(String8 string); -internal void rd_name_release(String8 string); - -//////////////////////////////// -//~ rjf: Config Tree Functions - -internal RD_Cfg *rd_cfg_alloc(void); -internal void rd_cfg_release(RD_Cfg *cfg); -internal void rd_cfg_release_all_children(RD_Cfg *cfg); -internal RD_Cfg *rd_cfg_from_id(CFG_ID id); -internal RD_Cfg *rd_cfg_new(RD_Cfg *parent, String8 string); -internal RD_Cfg *rd_cfg_newf(RD_Cfg *parent, char *fmt, ...); -internal RD_Cfg *rd_cfg_new_replace(RD_Cfg *parent, String8 string); -internal RD_Cfg *rd_cfg_new_replacef(RD_Cfg *parent, char *fmt, ...); -internal RD_Cfg *rd_cfg_deep_copy(RD_Cfg *src_root); -internal void rd_cfg_equip_string(RD_Cfg *cfg, String8 string); -internal void rd_cfg_equip_stringf(RD_Cfg *cfg, char *fmt, ...); -internal void rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child); -internal void rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child); -internal RD_Cfg *rd_cfg_child_from_string(RD_Cfg *parent, String8 string); -internal RD_Cfg *rd_cfg_child_from_string_or_alloc(RD_Cfg *parent, String8 string); -internal RD_Cfg *rd_cfg_child_from_string_or_parent(RD_Cfg *parent, String8 string); -internal RD_CfgList rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string); -internal RD_CfgList rd_cfg_top_level_list_from_string(Arena *arena, String8 string); -internal RD_CfgArray rd_cfg_array_from_list(Arena *arena, RD_CfgList *list); -internal RD_CfgList rd_cfg_tree_list_from_string(Arena *arena, String8 root_path, String8 string); -internal String8 rd_string_from_cfg_tree(Arena *arena, String8 root_path, RD_Cfg *cfg); -internal RD_CfgRec rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg); -internal void rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg); -internal void rd_cfg_list_push_front(Arena *arena, RD_CfgList *list, RD_Cfg *cfg); -#define rd_cfg_list_first(list) ((list)->count ? (list)->first->v : &rd_nil_cfg) -#define rd_cfg_list_last(list) ((list)->count ? (list)->last->v : &rd_nil_cfg) - -internal RD_PanelTree rd_panel_tree_from_cfg(Arena *arena, RD_Cfg *cfg); +internal RD_PanelTree rd_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root); internal RD_PanelNodeRec rd_panel_node_rec__depth_first(RD_PanelNode *root, RD_PanelNode *panel, U64 sib_off, U64 child_off); #define rd_panel_node_rec__depth_first_pre(root, p) rd_panel_node_rec__depth_first((root), (p), OffsetOf(RD_PanelNode, next), OffsetOf(RD_PanelNode, first)) #define rd_panel_node_rec__depth_first_pre_rev(root, p) rd_panel_node_rec__depth_first((root), (p), OffsetOf(RD_PanelNode, prev), OffsetOf(RD_PanelNode, last)) -internal RD_PanelNode *rd_panel_node_from_tree_cfg(RD_PanelNode *root, RD_Cfg *cfg); +internal RD_PanelNode *rd_panel_node_from_tree_cfg(RD_PanelNode *root, CFG_Node *cfg); internal Rng2F32 rd_target_rect_from_panel_node_child(Rng2F32 parent_rect, RD_PanelNode *parent, RD_PanelNode *panel); internal Rng2F32 rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNode *panel); -internal B32 rd_cfg_is_project_filtered(RD_Cfg *cfg); +internal B32 rd_cfg_is_project_filtered(CFG_Node *cfg); internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_name(Arena *arena, String8 string); internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding); -internal Vec4F32 rd_hsva_from_cfg(RD_Cfg *cfg); -internal Vec4F32 rd_color_from_cfg(RD_Cfg *cfg); +internal Vec4F32 rd_hsva_from_cfg(CFG_Node *cfg); +internal Vec4F32 rd_color_from_cfg(CFG_Node *cfg); -internal B32 rd_disabled_from_cfg(RD_Cfg *cfg); -internal RD_Location rd_location_from_cfg(RD_Cfg *cfg); -internal String8 rd_label_from_cfg(RD_Cfg *cfg); -internal String8 rd_expr_from_cfg(RD_Cfg *cfg); -internal String8 rd_path_from_cfg(RD_Cfg *cfg); -internal D_Target rd_target_from_cfg(Arena *arena, RD_Cfg *cfg); +internal B32 rd_disabled_from_cfg(CFG_Node *cfg); +internal RD_Location rd_location_from_cfg(CFG_Node *cfg); +internal String8 rd_label_from_cfg(CFG_Node *cfg); +internal String8 rd_expr_from_cfg(CFG_Node *cfg); +internal String8 rd_path_from_cfg(CFG_Node *cfg); +internal D_Target rd_target_from_cfg(Arena *arena, CFG_Node *cfg); -internal MD_NodePtrList rd_schemas_from_name(String8 name); internal String8 rd_default_setting_from_names(String8 schema_name, String8 setting_name); internal String8 rd_setting_from_name(String8 name); @@ -833,8 +706,8 @@ internal B32 rd_setting_b32_from_name(String8 name); internal U64 rd_setting_u64_from_name(String8 name); internal F32 rd_setting_f32_from_name(String8 name); -internal RD_Cfg *rd_immediate_cfg_from_key(String8 string); -internal RD_Cfg *rd_immediate_cfg_from_keyf(char *fmt, ...); +internal CFG_Node *rd_immediate_cfg_from_key(String8 string); +internal CFG_Node *rd_immediate_cfg_from_keyf(char *fmt, ...); internal String8 rd_mapped_from_file_path(Arena *arena, String8 file_path); internal String8List rd_possible_overrides_from_file_path(Arena *arena, String8 file_path); @@ -849,8 +722,8 @@ internal String8 rd_name_from_ctrl_entity(Arena *arena, CTRL_Entity *entity); //~ rjf: Evaluation Spaces //- rjf: cfg <-> eval space -internal RD_Cfg *rd_cfg_from_eval_space(E_Space space); -internal E_Space rd_eval_space_from_cfg(RD_Cfg *cfg); +internal CFG_Node *rd_cfg_from_eval_space(E_Space space); +internal E_Space rd_eval_space_from_cfg(CFG_Node *cfg); //- rjf: ctrl entity <-> eval space internal CTRL_Entity *rd_ctrl_entity_from_eval_space(E_Space space); @@ -887,8 +760,8 @@ internal String8 rd_query_from_eval_string(Arena *arena, String8 string); //////////////////////////////// //~ rjf: View Functions -internal RD_Cfg *rd_view_from_eval(RD_Cfg *parent, E_Eval eval); -internal RD_ViewState *rd_view_state_from_cfg(RD_Cfg *cfg); +internal CFG_Node *rd_view_from_eval(CFG_Node *parent, E_Eval eval); +internal RD_ViewState *rd_view_state_from_cfg(CFG_Node *cfg); internal void rd_view_ui(Rng2F32 rect); //////////////////////////////// @@ -930,8 +803,8 @@ internal void rd_store_view_paramf(String8 key, char *fmt, ...); //~ rjf: Window Functions internal String8 rd_push_window_title(Arena *arena); -internal RD_Cfg *rd_window_from_cfg(RD_Cfg *cfg); -internal RD_WindowState *rd_window_state_from_cfg(RD_Cfg *cfg); +internal CFG_Node *rd_window_from_cfg(CFG_Node *cfg); +internal RD_WindowState *rd_window_state_from_cfg(CFG_Node *cfg); internal RD_WindowState *rd_window_state_from_os_handle(OS_Handle os); internal void rd_window_frame(void); diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 291ac872..9b2891b6 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -245,7 +245,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(registers) typedef struct RD_SchemaIRExt RD_SchemaIRExt; struct RD_SchemaIRExt { - RD_Cfg *cfg; + CFG_Node *cfg; CTRL_Entity *entity; MD_NodePtrList schemas; }; @@ -262,7 +262,7 @@ E_TYPE_IREXT_FUNCTION_DEF(schema) E_Type *type = e_type_from_key(type_key); ext->cfg = rd_cfg_from_eval_space(interpret.space); ext->entity = rd_ctrl_entity_from_eval_space(interpret.space); - ext->schemas = rd_schemas_from_name(type->name); + ext->schemas = cfg_schemas_from_name(arena, rd_state->cfg_schema_table, type->name); scratch_end(scratch); } E_IRExt result = {ext}; @@ -289,9 +289,9 @@ E_TYPE_ACCESS_FUNCTION_DEF(schema) } if(child_schema != &md_nil_node) { - RD_Cfg *cfg = ext->cfg; + CFG_Node *cfg = ext->cfg; CTRL_Entity *entity = ext->entity; - RD_Cfg *child = rd_cfg_child_from_string(cfg, child_schema->string); + CFG_Node *child = cfg_node_child_from_string(cfg, child_schema->string); E_TypeKey child_type_key = zero_struct; B32 wrap_child_w_meta_expr = 0; if(0){} @@ -455,7 +455,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(schema) //- rjf: evaluate E_Space child_eval_space = zero_struct; - if(cfg != &rd_nil_cfg) + if(cfg != &cfg_nil_node) { child_eval_space = e_space_make(RD_EvalSpaceKind_MetaCfg); child_eval_space.u64s[0] = cfg->id; @@ -637,7 +637,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(cfgs) { String8 numeric_part = str8_skip(rhs->string, 1); CFG_ID id = u64_from_str8(numeric_part, 16); - RD_Cfg *cfg = rd_cfg_from_id(id); + CFG_Node *cfg = cfg_node_from_id(id); E_Space space = rd_eval_space_from_cfg(cfg); result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, 0)); result.type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, cfg->string); @@ -674,7 +674,7 @@ struct RD_CfgsIRExt { String8 cfg_name; String8Array cmds; - RD_CfgArray cfgs; + CFG_NodePtrArray cfgs; Rng1U64 cmds_idx_range; Rng1U64 cfgs_idx_range; }; @@ -691,12 +691,12 @@ E_TYPE_IREXT_FUNCTION_DEF(cfgs_slice) String8 cfg_name = rd_singular_from_code_name_plural(type->name); //- rjf: gather cfgs - RD_CfgList cfgs_list = rd_cfg_top_level_list_from_string(scratch.arena, cfg_name); + CFG_NodePtrList cfgs_list = cfg_node_top_level_list_from_string(scratch.arena, cfg_name); //- rjf: gather commands String8List cmds_list = {0}; { - MD_NodePtrList schemas = rd_schemas_from_name(cfg_name); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, cfg_name); for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) { MD_Node *schema = n->v; @@ -710,7 +710,7 @@ E_TYPE_IREXT_FUNCTION_DEF(cfgs_slice) //- rjf: package & fill ext->cfg_name = cfg_name; - ext->cfgs = rd_cfg_array_from_list(arena, &cfgs_list); + ext->cfgs = cfg_node_ptr_array_from_list(arena, &cfgs_list); ext->cmds = str8_array_from_list(arena, &cmds_list); scratch_end(scratch); @@ -722,7 +722,7 @@ E_TYPE_IREXT_FUNCTION_DEF(cfgs_slice) E_TYPE_ACCESS_FUNCTION_DEF(cfgs_slice) { E_IRTreeAndType result = {&e_irnode_nil}; - RD_Cfg *cfg = &rd_nil_cfg; + CFG_Node *cfg = &cfg_nil_node; RD_CfgsIRExt *ext = (RD_CfgsIRExt *)lhs_irtree->user_data; switch(expr->kind) { @@ -743,11 +743,11 @@ E_TYPE_ACCESS_FUNCTION_DEF(cfgs_slice) if(str8_match(str8_prefix(rhs_name, 1), str8_lit("$"), 0)) { id = u64_from_str8(str8_skip(rhs_name, 1), 16); - cfg = rd_cfg_from_id(id); + cfg = cfg_node_from_id(id); } }break; } - if(cfg != &rd_nil_cfg) + if(cfg != &cfg_nil_node) { result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0)); result.mode = E_Mode_Offset; @@ -760,7 +760,7 @@ typedef struct RD_CfgsExpandAccel RD_CfgsExpandAccel; struct RD_CfgsExpandAccel { String8Array cmds; - RD_CfgArray cfgs; + CFG_NodePtrArray cfgs; Rng1U64 cmds_idx_range; Rng1U64 cfgs_idx_range; }; @@ -775,27 +775,27 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_slice) RD_CfgsIRExt *ext = (RD_CfgsIRExt *)eval.irtree.user_data; //- rjf: filter cfgs - RD_CfgArray cfgs__filtered = ext->cfgs; + CFG_NodePtrArray cfgs__filtered = ext->cfgs; if(filter.size != 0) { - RD_CfgList cfgs_list__filtered = {0}; + CFG_NodePtrList cfgs_list__filtered = {0}; for EachIndex(idx, ext->cfgs.count) { - RD_Cfg *cfg = ext->cfgs.v[idx]; + CFG_Node *cfg = ext->cfgs.v[idx]; DR_FStrList fstrs = rd_title_fstrs_from_cfg(scratch.arena, cfg, 1); String8 string = dr_string_from_fstrs(scratch.arena, &fstrs); FuzzyMatchRangeList fuzzy_matches = fuzzy_match_find(scratch.arena, filter, string); if(fuzzy_matches.count == fuzzy_matches.needle_part_count) { - rd_cfg_list_push(scratch.arena, &cfgs_list__filtered, cfg); + cfg_node_ptr_list_push(scratch.arena, &cfgs_list__filtered, cfg); } } - cfgs__filtered = rd_cfg_array_from_list(arena, &cfgs_list__filtered); + cfgs__filtered = cfg_node_ptr_array_from_list(arena, &cfgs_list__filtered); } //- rjf: fill // TODO(rjf): @cleanup don't smuggle this through like this... - if(rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("lister")) == &rd_nil_cfg) + if(cfg_node_child_from_string(cfg_node_from_id(rd_regs()->view), str8_lit("lister")) == &cfg_nil_node) { accel->cmds = ext->cmds; accel->cmds_idx_range = r1u64(0, accel->cmds.count); @@ -813,7 +813,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_query) RD_CfgsExpandAccel *accel = push_array(arena, RD_CfgsExpandAccel, 1); { Temp scratch = scratch_begin(&arena, 1); - RD_Cfg *root_cfg = rd_cfg_from_eval_space(eval.space); + CFG_Node *root_cfg = rd_cfg_from_eval_space(eval.space); String8 child_key = e_string_from_id(eval.space.u64s[1]); String8 child_key_singular = rd_singular_from_code_name_plural(child_key); if(child_key_singular.size != 0) @@ -821,7 +821,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_query) child_key = child_key_singular; } String8List cmds = {0}; - MD_NodePtrList schemas = rd_schemas_from_name(child_key); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, child_key); for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) { MD_Node *schema = n->v; @@ -831,25 +831,25 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_query) str8_list_push(scratch.arena, &cmds, cmd->string); } } - RD_CfgList children = rd_cfg_child_list_from_string(scratch.arena, root_cfg, child_key); - RD_CfgList children__filtered = children; + CFG_NodePtrList children = cfg_node_child_list_from_string(scratch.arena, root_cfg, child_key); + CFG_NodePtrList children__filtered = children; if(filter.size != 0) { MemoryZeroStruct(&children__filtered); - for(RD_CfgNode *n = children.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = children.first; n != 0; n = n->next) { DR_FStrList cfg_fstrs = rd_title_fstrs_from_cfg(scratch.arena, n->v, 1); String8 cfg_string = dr_string_from_fstrs(scratch.arena, &cfg_fstrs); FuzzyMatchRangeList ranges = fuzzy_match_find(scratch.arena, filter, cfg_string); if(ranges.count == ranges.needle_part_count) { - rd_cfg_list_push(scratch.arena, &children__filtered, n->v); + cfg_node_ptr_list_push(scratch.arena, &children__filtered, n->v); } } } accel->cmds = str8_array_from_list(arena, &cmds); accel->cmds_idx_range = r1u64(0, accel->cmds.count); - accel->cfgs = rd_cfg_array_from_list(arena, &children__filtered); + accel->cfgs = cfg_node_ptr_array_from_list(arena, &children__filtered); accel->cfgs_idx_range = r1u64(accel->cmds.count + 0, accel->cmds.count + accel->cfgs.count); scratch_end(scratch); } @@ -883,7 +883,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(cfgs_slice) U64 read_count = dim_1u64(read_range); for(U64 idx = 0; idx < read_count; idx += 1, dst_idx += 1) { - RD_Cfg *cfg = accel->cfgs.v[idx + read_range.min - cfgs_idx_range.min]; + CFG_Node *cfg = accel->cfgs.v[idx + read_range.min - cfgs_idx_range.min]; evals_out[dst_idx] = e_eval_from_stringf("query:config.$%I64x", cfg->id); } } @@ -898,7 +898,7 @@ E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(cfgs_slice) U64 idx = num-1; if(contains_1u64(accel->cfgs_idx_range, idx)) { - RD_Cfg *cfg = accel->cfgs.v[idx - accel->cfgs_idx_range.min]; + CFG_Node *cfg = accel->cfgs.v[idx - accel->cfgs_idx_range.min]; id = cfg->id; } else if(contains_1u64(accel->cmds_idx_range, idx)) @@ -1001,7 +1001,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack) typedef struct RD_EnvironmentAccel RD_EnvironmentAccel; struct RD_EnvironmentAccel { - RD_CfgArray cfgs; + CFG_NodePtrArray cfgs; }; E_TYPE_IREXT_FUNCTION_DEF(environment) @@ -1013,16 +1013,16 @@ E_TYPE_IREXT_FUNCTION_DEF(environment) String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); E_Interpretation interpret = e_interpret(bytecode); E_Space space = interpret.space; - RD_Cfg *target = rd_cfg_from_eval_space(space); - RD_CfgList env_strings = {0}; - for(RD_Cfg *child = target->first; child != &rd_nil_cfg; child = child->next) + CFG_Node *target = rd_cfg_from_eval_space(space); + CFG_NodePtrList env_strings = {0}; + for(CFG_Node *child = target->first; child != &cfg_nil_node; child = child->next) { if(str8_match(child->string, str8_lit("environment"), 0)) { - rd_cfg_list_push(scratch.arena, &env_strings, child); + cfg_node_ptr_list_push(scratch.arena, &env_strings, child); } } - accel->cfgs = rd_cfg_array_from_list(arena, &env_strings); + accel->cfgs = cfg_node_ptr_array_from_list(arena, &env_strings); scratch_end(scratch); } E_IRExt result = {accel}; @@ -1035,11 +1035,11 @@ E_TYPE_ACCESS_FUNCTION_DEF(environment) if(expr->kind == E_ExprKind_ArrayIndex) { RD_EnvironmentAccel *accel = (RD_EnvironmentAccel *)lhs_irtree->user_data; - RD_CfgArray *cfgs = &accel->cfgs; + CFG_NodePtrArray *cfgs = &accel->cfgs; E_Value rhs_value = e_value_from_expr(expr->first->next); if(0 <= rhs_value.u64 && rhs_value.u64 < cfgs->count) { - RD_Cfg *cfg = cfgs->v[rhs_value.u64]; + CFG_Node *cfg = cfgs->v[rhs_value.u64]; result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0)); result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), cfg->first->string.size, E_TypeFlag_IsCodeText); result.mode = E_Mode_Offset; @@ -1115,7 +1115,7 @@ E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(environment) typedef struct RD_WatchesAccel RD_WatchesAccel; struct RD_WatchesAccel { - RD_CfgArray cfgs; + CFG_NodePtrArray cfgs; }; E_TYPE_IREXT_FUNCTION_DEF(watches) @@ -1127,16 +1127,16 @@ E_TYPE_IREXT_FUNCTION_DEF(watches) String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); E_Interpretation interpret = e_interpret(bytecode); E_Space space = interpret.space; - RD_Cfg *target = rd_cfg_from_eval_space(space); - RD_CfgList env_strings = {0}; - for(RD_Cfg *child = target->first; child != &rd_nil_cfg; child = child->next) + CFG_Node *target = rd_cfg_from_eval_space(space); + CFG_NodePtrList env_strings = {0}; + for(CFG_Node *child = target->first; child != &cfg_nil_node; child = child->next) { if(str8_match(child->string, str8_lit("watch"), 0)) { - rd_cfg_list_push(scratch.arena, &env_strings, child); + cfg_node_ptr_list_push(scratch.arena, &env_strings, child); } } - accel->cfgs = rd_cfg_array_from_list(arena, &env_strings); + accel->cfgs = cfg_node_ptr_array_from_list(arena, &env_strings); scratch_end(scratch); } E_IRExt result = {accel}; @@ -1149,11 +1149,11 @@ E_TYPE_ACCESS_FUNCTION_DEF(watches) if(expr->kind == E_ExprKind_ArrayIndex) { RD_WatchesAccel *accel = (RD_WatchesAccel *)lhs_irtree->user_data; - RD_CfgArray *cfgs = &accel->cfgs; + CFG_NodePtrArray *cfgs = &accel->cfgs; E_Value rhs_value = e_value_from_expr(expr->first->next); if(0 <= rhs_value.u64 && rhs_value.u64 < cfgs->count) { - RD_Cfg *cfg = cfgs->v[rhs_value.u64]; + CFG_Node *cfg = cfgs->v[rhs_value.u64]; result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0)); result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), cfg->first->string.size, E_TypeFlag_IsCodeText); result.mode = E_Mode_Offset; @@ -1167,22 +1167,22 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches) RD_WatchesAccel *ext = (RD_WatchesAccel *)eval.irtree.user_data; RD_WatchesAccel *accel = push_array(arena, RD_WatchesAccel, 1); { - RD_CfgArray cfgs__filtered = ext->cfgs; + CFG_NodePtrArray cfgs__filtered = ext->cfgs; if(filter.size != 0) { Temp scratch = scratch_begin(&arena, 1); - RD_CfgList cfgs_list__filtered = {0}; + CFG_NodePtrList cfgs_list__filtered = {0}; for EachIndex(idx, ext->cfgs.count) { - RD_Cfg *watch = ext->cfgs.v[idx]; + CFG_Node *watch = ext->cfgs.v[idx]; String8 string = watch->first->string; FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, string); if(matches.count == matches.needle_part_count) { - rd_cfg_list_push(scratch.arena, &cfgs_list__filtered, watch); + cfg_node_ptr_list_push(scratch.arena, &cfgs_list__filtered, watch); } } - cfgs__filtered = rd_cfg_array_from_list(arena, &cfgs_list__filtered); + cfgs__filtered = cfg_node_ptr_array_from_list(arena, &cfgs_list__filtered); scratch_end(scratch); } accel->cfgs = cfgs__filtered; @@ -1202,7 +1202,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches) U64 cfg_idx = read_range.min + idx; if(cfg_idx < accel->cfgs.count) { - RD_Cfg *cfg = accel->cfgs.v[cfg_idx]; + CFG_Node *cfg = accel->cfgs.v[cfg_idx]; evals_out[idx] = e_eval_from_string(cfg->first->string); } } @@ -1651,7 +1651,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) B32 stale = 0; accel->section = section; accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us, &stale); - RD_Cfg *last_successful_query_cfg = rd_immediate_cfg_from_keyf("last_successful_query_%I64x_%I64u", rd_regs()->view, (U64)section); + CFG_Node *last_successful_query_cfg = rd_immediate_cfg_from_keyf("last_successful_query_%I64x_%I64u", rd_regs()->view, (U64)section); if(stale) { String8 last_query = last_successful_query_cfg->first->string; @@ -1660,7 +1660,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) } else { - rd_cfg_new_replace(last_successful_query_cfg, filter); + cfg_node_new_replace(rd_state->cfg, last_successful_query_cfg, filter); } } diff --git a/src/raddbg/raddbg_legacy_config.c b/src/raddbg/raddbg_legacy_config.c index fb5af05c..abf6f692 100644 --- a/src/raddbg/raddbg_legacy_config.c +++ b/src/raddbg/raddbg_legacy_config.c @@ -1,10 +1,10 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal RD_CfgList +internal CFG_NodePtrList rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String8 data) { - RD_CfgList result = {0}; + CFG_NodePtrList result = {0}; { Temp scratch = scratch_begin(&arena, 1); String8 folder_path = str8_skip_last_slash(file_path); @@ -24,20 +24,20 @@ rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String String8 stderr_path = md_child_from_string(tln, str8_lit("stderr_path"), 0)->first->string; String8 stdin_path = md_child_from_string(tln, str8_lit("stdin_path"), 0)->first->string; String8 debug_subprocesses= md_child_from_string(tln, str8_lit("debug_subprocesses"), 0)->first->string; - RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, str8_lit("target")); - rd_cfg_list_push(arena, &result, dst_root); + CFG_Node *dst_root = cfg_node_new(rd_state->cfg, &cfg_nil_node, str8_lit("target")); + cfg_node_ptr_list_push(arena, &result, dst_root); { - if(executable.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("executable")), path_absolute_dst_from_relative_dst_src(scratch.arena, executable, folder_path)); } - if(arguments.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("arguments")), raw_from_escaped_str8(scratch.arena, arguments)); } - if(working_directory.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("working_directory")), path_absolute_dst_from_relative_dst_src(scratch.arena, working_directory, folder_path)); } - if(entry_point.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("entry_point")), raw_from_escaped_str8(scratch.arena, entry_point)); } - if(stdout_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stdout_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdout_path, folder_path)); } - if(stderr_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stderr_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stderr_path, folder_path)); } - if(stdin_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stdin_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdin_path, folder_path)); } - if(debug_subprocesses.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("debug_subprocesses")), raw_from_escaped_str8(scratch.arena, debug_subprocesses)); } + if(executable.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("executable")), path_absolute_dst_from_relative_dst_src(scratch.arena, executable, folder_path)); } + if(arguments.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("arguments")), raw_from_escaped_str8(scratch.arena, arguments)); } + if(working_directory.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("working_directory")), path_absolute_dst_from_relative_dst_src(scratch.arena, working_directory, folder_path)); } + if(entry_point.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("entry_point")), raw_from_escaped_str8(scratch.arena, entry_point)); } + if(stdout_path.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("stdout_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdout_path, folder_path)); } + if(stderr_path.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("stderr_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stderr_path, folder_path)); } + if(stdin_path.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("stdin_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdin_path, folder_path)); } + if(debug_subprocesses.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("debug_subprocesses")), raw_from_escaped_str8(scratch.arena, debug_subprocesses)); } if(!str8_match(disabled_string, str8_lit("1"), 0)) { - rd_cfg_new(rd_cfg_new(dst_root, str8_lit("enabled")), str8_lit("1")); + cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("enabled")), str8_lit("1")); } } } @@ -46,9 +46,9 @@ rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String if(str8_match(tln->string, str8_lit("recent_file"), 0) || str8_match(tln->string, str8_lit("recent_project"), 0)) { - RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, tln->string); - rd_cfg_list_push(arena, &result, dst_root); - rd_cfg_new(rd_cfg_new(dst_root, str8_lit("path")), path_absolute_dst_from_relative_dst_src(scratch.arena, tln->first->string, folder_path)); + CFG_Node *dst_root = cfg_node_new(rd_state->cfg, &cfg_nil_node, tln->string); + cfg_node_ptr_list_push(arena, &result, dst_root); + cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("path")), path_absolute_dst_from_relative_dst_src(scratch.arena, tln->first->string, folder_path)); } //- rjf: file path maps @@ -56,10 +56,10 @@ rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String { String8 source = md_child_from_string(tln, str8_lit("source"), 0)->first->string; String8 dest = md_child_from_string(tln, str8_lit("dest"), 0)->first->string; - RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, tln->string); - rd_cfg_list_push(arena, &result, dst_root); - rd_cfg_new(rd_cfg_new(dst_root, str8_lit("source")), path_absolute_dst_from_relative_dst_src(scratch.arena, source, folder_path)); - rd_cfg_new(rd_cfg_new(dst_root, str8_lit("dest")), path_absolute_dst_from_relative_dst_src(scratch.arena, dest, folder_path)); + CFG_Node *dst_root = cfg_node_new(rd_state->cfg, &cfg_nil_node, tln->string); + cfg_node_ptr_list_push(arena, &result, dst_root); + cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("source")), path_absolute_dst_from_relative_dst_src(scratch.arena, source, folder_path)); + cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("dest")), path_absolute_dst_from_relative_dst_src(scratch.arena, dest, folder_path)); } } } diff --git a/src/raddbg/raddbg_legacy_config.h b/src/raddbg/raddbg_legacy_config.h index 384d2fc6..1ed99e87 100644 --- a/src/raddbg/raddbg_legacy_config.h +++ b/src/raddbg/raddbg_legacy_config.h @@ -4,6 +4,6 @@ #ifndef RADDBG_LEGACY_CONFIG_H #define RADDBG_LEGACY_CONFIG_H -internal RD_CfgList rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String8 data); +internal CFG_NodePtrList rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String8 data); #endif // RADDBG_LEGACY_CONFIG_H diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 62e01c46..e63e500a 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -582,7 +582,7 @@ entry_point(CmdLine *cmd_line) if(dst_ws->cfg_id != rd_regs()->window) { Temp scratch = scratch_begin(0, 0); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, rd_cfg_from_id(dst_ws->cfg_id)); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(dst_ws->cfg_id)); rd_regs()->window = dst_ws->cfg_id; rd_regs()->panel = panel_tree.focused->cfg->id; rd_regs()->tab = panel_tree.focused->selected_tab->id; diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 68653c29..eca984d4 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -174,20 +174,20 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // if(rd_regs()->cursor.line == rd_regs()->mark.line) { - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + CFG_Node *view = cfg_node_from_id(rd_regs()->view); RD_ViewState *vs = rd_view_state_from_cfg(view); if(!vs->query_is_open) { - RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); - RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); + CFG_Node *query = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("query")); + CFG_Node *input = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("input")); String8 text = txt_string_from_info_data_txt_rng(text_info, text_data, txt_rng(rd_regs()->cursor, rd_regs()->mark)); if(text.size < 256) { - rd_cfg_new_replace(input, text); + cfg_node_new_replace(rd_state->cfg, input, text); } else { - rd_cfg_new_replace(input, str8_zero()); + cfg_node_new_replace(rd_state->cfg, input, str8_zero()); } } } @@ -217,9 +217,9 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla code_slice_params.line_text = push_array(scratch.arena, String8, visible_line_count); code_slice_params.line_ranges = push_array(scratch.arena, Rng1U64, visible_line_count); code_slice_params.line_tokens = push_array(scratch.arena, TXT_TokenArray, visible_line_count); - code_slice_params.line_bps = push_array(scratch.arena, RD_CfgList, visible_line_count); + code_slice_params.line_bps = push_array(scratch.arena, CFG_NodePtrList, visible_line_count); code_slice_params.line_ips = push_array(scratch.arena, CTRL_EntityList, visible_line_count); - code_slice_params.line_pins = push_array(scratch.arena, RD_CfgList, visible_line_count); + code_slice_params.line_pins = push_array(scratch.arena, CFG_NodePtrList, visible_line_count); code_slice_params.line_vaddrs = push_array(scratch.arena, U64, visible_line_count); code_slice_params.line_infos = push_array(scratch.arena, D_LineList, visible_line_count); code_slice_params.text_info = text_info; @@ -252,10 +252,10 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find visible breakpoints for source code if(!dasm_lines) ProfScope("find visible breakpoints for source code") { - RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); - for(RD_CfgNode *n = bps.first; n != 0; n = n->next) + CFG_NodePtrList bps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(CFG_NodePtrNode *n = bps.first; n != 0; n = n->next) { - RD_Cfg *bp = n->v; + CFG_Node *bp = n->v; RD_Location loc = rd_location_from_cfg(bp); if(visible_line_num_range.min <= loc.pt.line && loc.pt.line <= visible_line_num_range.max) { @@ -266,7 +266,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla if(path_match_normalized(loc.file_path, override_n->string)) { U64 slice_line_idx = (U64)(loc.pt.line-visible_line_num_range.min); - rd_cfg_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); + cfg_node_ptr_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); break; } } @@ -314,10 +314,10 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find visible watch pins for source code if(!dasm_lines) ProfScope("find visible watch pins for source code") { - RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); - for(RD_CfgNode *n = wps.first; n != 0; n = n->next) + CFG_NodePtrList wps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); + for(CFG_NodePtrNode *n = wps.first; n != 0; n = n->next) { - RD_Cfg *wp = n->v; + CFG_Node *wp = n->v; RD_Location loc = rd_location_from_cfg(wp); if(visible_line_num_range.min <= loc.pt.line && loc.pt.line <= visible_line_num_range.max) { @@ -328,7 +328,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla if(path_match_normalized(loc.file_path, override_n->string)) { U64 slice_line_idx = (loc.pt.line-visible_line_num_range.min); - rd_cfg_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], wp); + cfg_node_ptr_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], wp); break; } } @@ -376,10 +376,10 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find breakpoints mapping to this disasm if(dasm_lines) ProfScope("find breakpoints mapping to this disassembly") { - RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); - for(RD_CfgNode *n = bps.first; n != 0; n = n->next) + CFG_NodePtrList bps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(CFG_NodePtrNode *n = bps.first; n != 0; n = n->next) { - RD_Cfg *bp = n->v; + CFG_Node *bp = n->v; RD_Location loc = rd_location_from_cfg(bp); E_Value loc_value = e_value_from_string(loc.expr); if(contains_1u64(dasm_vaddr_range, loc_value.u64)) @@ -390,7 +390,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla if(contains_1s64(visible_line_num_range, line_num)) { U64 slice_line_idx = (line_num-visible_line_num_range.min); - rd_cfg_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); + cfg_node_ptr_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); } } } @@ -399,10 +399,10 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find watch pins mapping to this disasm if(dasm_lines) ProfScope("find watch pins mapping to this disassembly") { - RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); - for(RD_CfgNode *n = wps.first; n != 0; n = n->next) + CFG_NodePtrList wps = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); + for(CFG_NodePtrNode *n = wps.first; n != 0; n = n->next) { - RD_Cfg *wp = n->v; + CFG_Node *wp = n->v; RD_Location loc = rd_location_from_cfg(wp); E_Value loc_value = e_value_from_string(loc.expr); if(contains_1u64(dasm_vaddr_range, loc_value.u64)) @@ -413,7 +413,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla if(contains_1s64(visible_line_num_range, line_num)) { U64 slice_line_idx = (line_num-visible_line_num_range.min); - rd_cfg_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], wp); + cfg_node_ptr_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], wp); } } } @@ -942,8 +942,8 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) { .module = &ctrl_entity_nil, .can_expand = ev_row_is_expandable(row), - .group_cfg_parent = &rd_nil_cfg, - .group_cfg_child = &rd_nil_cfg, + .group_cfg_parent = &cfg_nil_node, + .group_cfg_child = &cfg_nil_node, .group_entity = &ctrl_entity_nil, .callstack_thread = &ctrl_entity_nil, .view_ui_rule = &rd_nil_view_ui_rule, @@ -962,7 +962,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) E_TypeKey block_type_key = e_type_key_unwrap(block_eval.irtree.type_key, E_TypeUnwrapFlag_Meta); E_TypeKind block_type_kind = e_type_kind_from_key(block_type_key); E_Type *block_type = e_type_from_key(block_type_key); - RD_Cfg *evalled_cfg = rd_cfg_from_eval_space(row->eval.space); + CFG_Node *evalled_cfg = rd_cfg_from_eval_space(row->eval.space); CTRL_Entity *evalled_entity = (row->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity ? rd_ctrl_entity_from_eval_space(row->eval.space) : &ctrl_entity_nil); //////////////////////////// @@ -970,7 +970,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) // are evaluating a cfg tree, or some descendant of it // B32 is_top_level = 0; - if(evalled_cfg != &rd_nil_cfg) + if(evalled_cfg != &cfg_nil_node) { E_TypeKey top_level_type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, evalled_cfg->string); is_top_level = (row->eval.value.u64 == 0 && e_type_key_match(top_level_type_key, row->eval.irtree.type_key)); @@ -1090,7 +1090,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) block_type->expand.id_from_num == E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment))) { CFG_ID id = row->key.child_id; - info.group_cfg_child = rd_cfg_from_id(id); + info.group_cfg_child = cfg_node_from_id(id); } } @@ -1129,9 +1129,9 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) { U64 column_count = maybe_table_type->count; info.cell_style_key = push_str8f(arena, "table_%I64u_cols", column_count); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *style = cfg_node_child_from_string(view, info.cell_style_key); + CFG_Node *w_cfg = style->first; F32 next_pct = 0; #define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) E_ParentKey(row->eval.key) @@ -1175,7 +1175,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) //////////////////////////// //- rjf: @watch_row_build_cells autocomplete rows // - else if(rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("autocomplete")) != &rd_nil_cfg) + else if(cfg_node_child_from_string(cfg_node_from_id(rd_regs()->view), str8_lit("autocomplete")) != &cfg_nil_node) { info.can_expand = 0; rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Button|RD_WatchCellFlag_Indented, .pct = 1.f); @@ -1184,7 +1184,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) //////////////////////////// //- rjf: @watch_row_build_cells lister rows // - else if(rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("lister")) != &rd_nil_cfg) + else if(cfg_node_child_from_string(cfg_node_from_id(rd_regs()->view), str8_lit("lister")) != &cfg_nil_node) { info.can_expand = 0; RD_WatchCellFlags extra_flags = RD_WatchCellFlag_Expr; @@ -1202,11 +1202,11 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) //////////////////////////// //- rjf: @watch_row_build_cells top-level cfg evaluations // - else if(is_top_level && evalled_cfg != &rd_nil_cfg) + else if(is_top_level && evalled_cfg != &cfg_nil_node) { - RD_Cfg *cfg = evalled_cfg; + CFG_Node *cfg = evalled_cfg; rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Button|RD_WatchCellFlag_Indented, .pct = 1.f); - MD_NodePtrList schemas = rd_schemas_from_name(cfg->string); + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, cfg->string); for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) { MD_Node *schema = n->v; @@ -1222,8 +1222,8 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) if(is_cmd_line_only) { B32 is_cmd_line = 0; - RD_Cfg *cmd_line = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); - for(RD_Cfg *p = evalled_cfg->parent; p != &rd_nil_cfg; p = p->parent) + CFG_Node *cmd_line = cfg_node_child_from_string(cfg_node_root(), str8_lit("command_line")); + for(CFG_Node *p = evalled_cfg->parent; p != &cfg_nil_node; p = p->parent) { if(p == cmd_line) { @@ -1362,7 +1362,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) //////////////////////////// //- rjf: @watch_row_build_cells "add new" expression rows // - else if(row->eval.expr == &e_expr_nil && info.group_cfg_name.size != 0 && info.group_cfg_child == &rd_nil_cfg) + else if(row->eval.expr == &e_expr_nil && info.group_cfg_name.size != 0 && info.group_cfg_child == &cfg_nil_node) { rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .pct = 1.f); @@ -1371,7 +1371,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) //////////////////////////// //- rjf: @watch_row_build_cells meta-evaluation booleans // - else if(info.group_cfg_child == &rd_nil_cfg && + else if(info.group_cfg_child == &cfg_nil_node && e_type_kind_from_key(e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)) == E_TypeKind_Bool && (row->eval.space.kind == RD_EvalSpaceKind_MetaCfg || row->eval.space.kind == RD_EvalSpaceKind_MetaCmd || @@ -1387,9 +1387,9 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) else if(block_type->kind == E_TypeKind_Set && str8_match(block_type->name, str8_lit("procedures"), 0)) { info.cell_style_key = str8_lit("procedure_expr_eval"); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *style = cfg_node_child_from_string(view, info.cell_style_key); + CFG_Node *w_cfg = style->first; F32 next_pct = 0; #define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, @@ -1409,9 +1409,9 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) CTRL_Entity *process = ctrl_process_from_entity(info.callstack_thread); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, info.callstack_vaddr); E_Eval module_eval = e_eval_from_stringf("query:control.%S", ctrl_string_from_handle(scratch.arena, module->handle)); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *style = cfg_node_child_from_string(view, info.cell_style_key); + CFG_Node *w_cfg = style->first; F32 next_pct = 0; #define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_CallStackFrame, row->eval, .default_pct = 0.05f, .pct = take_pct()); @@ -1440,9 +1440,9 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) } } info.cell_style_key = str8_lit("normal"); - RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); - RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); - RD_Cfg *w_cfg = style->first; + CFG_Node *view = cfg_node_from_id(rd_regs()->view); + CFG_Node *style = cfg_node_child_from_string(view, info.cell_style_key); + CFG_Node *w_cfg = style->first; F32 next_pct = 0; #define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, @@ -1484,7 +1484,7 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla { .flags = cell->flags, .view_ui_rule = &rd_nil_view_ui_rule, - .cfg = &rd_nil_cfg, + .cfg = &cfg_nil_node, .entity = &ctrl_entity_nil, }; @@ -1493,7 +1493,7 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla // E_Type *block_type = e_type_from_key(row->block->eval.irtree.type_key); E_Type *cell_type = e_type_from_key(cell->eval.irtree.type_key); - MD_NodePtrList cell_schemas = rd_schemas_from_name(cell_type->name); + MD_NodePtrList cell_schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, cell_type->name); if(cell->eval.space.u64s[1] == 0 && cell_schemas.count != 0) { result.cfg = rd_cfg_from_eval_space(cell->eval.space); @@ -1591,7 +1591,7 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla } //- rjf: cfg evaluation -> button for cfg - else if(result.cfg != &rd_nil_cfg) + else if(result.cfg != &cfg_nil_node) { result.expr_fstrs = rd_title_fstrs_from_cfg(arena, result.cfg, 0); result.flags |= RD_WatchCellFlag_Button; diff --git a/src/raddbg/raddbg_views.h b/src/raddbg/raddbg_views.h index b4f40702..fd497d98 100644 --- a/src/raddbg/raddbg_views.h +++ b/src/raddbg/raddbg_views.h @@ -124,8 +124,8 @@ struct RD_WatchRowInfo B32 can_expand; B32 expr_is_editable; String8 group_cfg_name; - RD_Cfg *group_cfg_parent; - RD_Cfg *group_cfg_child; + CFG_Node *group_cfg_parent; + CFG_Node *group_cfg_child; CTRL_Entity *group_entity; CTRL_Entity *callstack_thread; U64 callstack_unwind_index; @@ -140,7 +140,7 @@ typedef struct RD_WatchRowCellInfo RD_WatchRowCellInfo; struct RD_WatchRowCellInfo { RD_WatchCellFlags flags; - RD_Cfg *cfg; + CFG_Node *cfg; CTRL_Entity *entity; String8 cmd_name; String8 file_path; diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 95f84b74..761392e5 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -5,7 +5,7 @@ //~ rjf: UI Widgets: Fancy Title Strings internal DR_FStrList -rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) +rd_title_fstrs_from_cfg(Arena *arena, CFG_Node *cfg, B32 include_extras) { DR_FStrList result = {0}; { @@ -32,8 +32,8 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) RD_IconKind icon_kind = rd_icon_kind_from_code_name(cfg->string); B32 is_from_command_line = 0; { - RD_Cfg *cmd_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); - for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent) + CFG_Node *cmd_line_root = cfg_node_child_from_string(cfg_node_root(), str8_lit("command_line")); + for(CFG_Node *p = cfg->parent; p != &cfg_nil_node; p = p->parent) { if(p == cmd_line_root) { @@ -44,7 +44,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) } B32 is_within_window = 0; { - for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent) + for(CFG_Node *p = cfg->parent; p != &cfg_nil_node; p = p->parent) { if(str8_match(p->string, str8_lit("window"), 0)) { @@ -105,7 +105,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) CTRL_Event stop_event = d_ctrl_last_stop_event(); if(stop_event.cause == CTRL_EventCause_UserBreakpoint) { - RD_Cfg *bp = rd_cfg_from_id(stop_event.u64_code); + CFG_Node *bp = cfg_node_from_id(stop_event.u64_code); if(bp == cfg) { CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, stop_event.entity); @@ -147,7 +147,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) } //- rjf: push bucket name - if(cfg->parent == rd_state->root_cfg) + if(cfg->parent == cfg_node_root()) { if(str8_match(cfg->string, str8_lit("user"), 0)) { @@ -328,7 +328,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) //- rjf: push conditions { - String8 condition = rd_cfg_child_from_string(cfg, str8_lit("condition"))->first->string; + String8 condition = cfg_node_child_from_string(cfg, str8_lit("condition"))->first->string; if(condition.size != 0) { dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("if "), .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); @@ -350,7 +350,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) //- rjf: push hit count { - String8 hit_count_value_string = rd_cfg_child_from_string(cfg, str8_lit("hit_count"))->first->string; + String8 hit_count_value_string = cfg_node_child_from_string(cfg, str8_lit("hit_count"))->first->string; U64 hit_count = 0; if(try_u64_from_str8_c_rules(hit_count_value_string, &hit_count) && hit_count != 0) { @@ -362,8 +362,8 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) //- rjf: special case: type views if(str8_match(cfg->string, str8_lit("type_view"), 0)) { - String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("type"))->first->string; - String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("expr"))->first->string; + String8 src_string = cfg_node_child_from_string(cfg, str8_lit("type"))->first->string; + String8 dst_string = cfg_node_child_from_string(cfg, str8_lit("expr"))->first->string; Vec4F32 src_color = rgba; Vec4F32 dst_color = rgba; DR_FStrList src_fstrs = {0}; @@ -398,8 +398,8 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) //- rjf: special case: file path maps if(str8_match(cfg->string, str8_lit("file_path_map"), 0)) { - String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("source"))->first->string; - String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("dest"))->first->string; + String8 src_string = cfg_node_child_from_string(cfg, str8_lit("source"))->first->string; + String8 dst_string = cfg_node_child_from_string(cfg, str8_lit("dest"))->first->string; Vec4F32 src_color = rgba; Vec4F32 dst_color = rgba; if(src_string.size == 0) @@ -422,8 +422,8 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras) //- rjf: special case: colors if(str8_match(cfg->string, str8_lit("theme_color"), 0)) { - String8 tags = rd_cfg_child_from_string(cfg, str8_lit("tags"))->first->string; - String8 color_string = rd_cfg_child_from_string(cfg, str8_lit("value"))->first->string; + String8 tags = cfg_node_child_from_string(cfg, str8_lit("tags"))->first->string; + String8 color_string = cfg_node_child_from_string(cfg, str8_lit("value"))->first->string; U32 color_u32 = e_value_from_stringf("(uint32)(%S)", color_string).u32; Vec4F32 color = linear_from_srgba(rgba_from_u32(color_u32)); if(tags.size != 0) @@ -860,7 +860,7 @@ rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new) UI_Signal sig = rd_icon_button(RD_IconKind_X, 0, str8_lit("###delete_binding")); if(ui_clicked(sig)) { - rd_cfg_release(rd_cfg_from_id(rd_state->bind_change_binding_id)); + cfg_node_release(rd_state->cfg, cfg_node_from_id(rd_state->bind_change_binding_id)); rd_state->bind_change_active = 0; } } @@ -972,7 +972,7 @@ rd_cmd_list_menu_buttons(U64 count, String8 *cmd_names, U32 *fastpath_codepoints { rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_names[idx]); ui_ctx_menu_close(); - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); ws->menu_bar_focused = 0; } @@ -1308,14 +1308,14 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe //- rjf: dragging cfgs/entities/expressions? -> drop site // B32 drop_can_hit_lines = 0; - RD_Cfg *drop_cfg = &rd_nil_cfg; + CFG_Node *drop_cfg = &cfg_nil_node; CTRL_Entity *drop_thread = &ctrl_entity_nil; String8 drop_expr = {0}; Vec4F32 drop_color = pop_color; UI_Key drop_site_key = ui_key_from_stringf(top_container_box->key, "drop_site"); if(rd_drag_is_active()) { - RD_Cfg *cfg = rd_cfg_from_id(rd_state->drag_drop_regs->cfg); + CFG_Node *cfg = cfg_node_from_id(rd_state->drag_drop_regs->cfg); if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && (str8_match(cfg->string, str8_lit("breakpoint"), 0) || str8_match(cfg->string, str8_lit("watch_pin"), 0))) @@ -1553,8 +1553,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe line_num += 1, line_idx += 1) { CTRL_EntityList line_ips = params->line_ips[line_idx]; - RD_CfgList line_bps = params->line_bps[line_idx]; - RD_CfgList line_pins = params->line_pins[line_idx]; + CFG_NodePtrList line_bps = params->line_bps[line_idx]; + CFG_NodePtrList line_pins = params->line_pins[line_idx]; ui_set_next_hover_cursor(OS_Cursor_HandPoint); ui_set_next_background_color(v4f32(0, 0, 0, 0)); UI_Box *line_margin_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawActiveEffects, "line_margin_%I64x", line_num); @@ -1683,9 +1683,9 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } //- rjf: build margin breakpoint ui - for(RD_CfgNode *n = line_bps.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = line_bps.first; n != 0; n = n->next) { - RD_Cfg *bp = n->v; + CFG_Node *bp = n->v; Vec4F32 bp_rgba = rd_color_from_cfg(bp); if(bp_rgba.w == 0) { @@ -1701,14 +1701,14 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe RD_BreakpointBoxDrawExtData *bp_draw = push_array(ui_build_arena(), RD_BreakpointBoxDrawExtData, 1); { RD_Regs *hover_regs = rd_get_hover_regs(); - B32 is_hovering = (rd_cfg_from_id(hover_regs->cfg) == bp && rd_state->hover_regs_slot == RD_RegSlot_Cfg); + B32 is_hovering = (cfg_node_from_id(hover_regs->cfg) == bp && rd_state->hover_regs_slot == RD_RegSlot_Cfg); bp_draw->color = bp_rgba; bp_draw->alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "cfg_alive_t_%p", bp), 1.f, .rate = entity_alive_t_rate); bp_draw->hover_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "cfg_hover_t_%p", bp), (F32)!!is_hovering, .rate = entity_hover_t_rate); bp_draw->do_lines = do_bp_lines; bp_draw->do_glow = do_bp_glow; bp_draw->is_disabled = bp_is_disabled; - bp_draw->is_conditioned = (rd_cfg_child_from_string(bp, str8_lit("condition"))->first->string.size != 0); + bp_draw->is_conditioned = (cfg_node_child_from_string(bp, str8_lit("condition"))->first->string.size != 0); if(params->line_vaddrs[line_idx] == 0) { D_LineList *lines = ¶ms->line_infos[line_idx]; @@ -1773,9 +1773,9 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } //- rjf: build margin watch pin ui - for(RD_CfgNode *n = line_pins.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = line_pins.first; n != 0; n = n->next) { - RD_Cfg *pin = n->v; + CFG_Node *pin = n->v; Vec4F32 color = rd_color_from_cfg(pin); if(color.w == 0) { @@ -2017,7 +2017,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe line_num < params->line_num_range.max; line_num += 1, line_idx += 1) { - RD_CfgList immediate_pins = {0}; + CFG_NodePtrList immediate_pins = {0}; String8 line_text = params->line_text[line_idx]; for(U64 off = 0, next_off = line_text.size; off < line_text.size; @@ -2086,29 +2086,29 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // rjf: build immediate pin for this markup if(expr_string.size != 0) { - RD_Cfg *immediate_root = rd_immediate_cfg_from_keyf("markup_pin_%I64x_%I64x", line_num, off); - RD_Cfg *pin = rd_cfg_child_from_string_or_alloc(immediate_root, str8_lit("watch_pin")); - RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(pin, str8_lit("expression")); - rd_cfg_new_replace(expr, expr_string); - rd_cfg_list_push(scratch.arena, &immediate_pins, pin); + CFG_Node *immediate_root = rd_immediate_cfg_from_keyf("markup_pin_%I64x_%I64x", line_num, off); + CFG_Node *pin = cfg_node_child_from_string_or_alloc(rd_state->cfg, immediate_root, str8_lit("watch_pin")); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, pin, str8_lit("expression")); + cfg_node_new_replace(rd_state->cfg, expr, expr_string); + cfg_node_ptr_list_push(scratch.arena, &immediate_pins, pin); } } - RD_CfgList pin_lists[] = + CFG_NodePtrList pin_lists[] = { params->line_pins[line_idx], immediate_pins, }; E_ParentKey(e_key_zero()) for EachElement(list_idx, pin_lists) { - RD_CfgList pins = pin_lists[list_idx]; + CFG_NodePtrList pins = pin_lists[list_idx]; if(pins.count != 0) UI_Parent(line_extras_boxes[line_idx]) RD_Font(RD_FontSlot_Code) UI_FontSize(params->font_size) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) { - for(RD_CfgNode *n = pins.first; n != 0; n = n->next) + for(CFG_NodePtrNode *n = pins.first; n != 0; n = n->next) { - RD_Cfg *pin = n->v; + CFG_Node *pin = n->v; String8 pin_expr = rd_expr_from_cfg(pin); E_Eval eval = e_eval_from_string(pin_expr); String8 eval_string = {0}; @@ -2243,7 +2243,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe .cursor = line_vaddr == 0 ? txt_pt(line_num, 1) : txt_pt(0, 0), .vaddr = line_vaddr); } - if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && drop_cfg != &rd_nil_cfg) + if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && drop_cfg != &cfg_nil_node) { S64 line_num = mouse_pt.line; U64 line_idx = line_num - params->line_num_range.min; @@ -3917,7 +3917,7 @@ rd_cell(RD_CellParams *params, String8 string) // rjf: any valid *additive* op & autocomplete hint? -> perform autocomplete first, then re-compute op if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0) { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(autocomp_cursor_info->replaced_range.min+1, autocomp_cursor_info->replaced_range.max+1), autocomplete_hint_string); @@ -4015,7 +4015,7 @@ rd_cell(RD_CellParams *params, String8 string) } if(autocomplete_hint_string.size != 0) { - RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(window); RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, params->cursor->column-1 - autocomp_cursor_info->replaced_range.min); diff --git a/src/raddbg/raddbg_widgets.h b/src/raddbg/raddbg_widgets.h index 5d5a509e..66055279 100644 --- a/src/raddbg/raddbg_widgets.h +++ b/src/raddbg/raddbg_widgets.h @@ -101,9 +101,9 @@ struct RD_CodeSliceParams String8 *line_text; Rng1U64 *line_ranges; TXT_TokenArray *line_tokens; - RD_CfgList *line_bps; + CFG_NodePtrList *line_bps; CTRL_EntityList *line_ips; - RD_CfgList *line_pins; + CFG_NodePtrList *line_pins; U64 *line_vaddrs; D_LineList *line_infos; DI_KeyList relevant_dbgi_keys; @@ -139,7 +139,7 @@ struct RD_CodeSliceSignal //////////////////////////////// //~ rjf: UI Widgets: Fancy Title Strings -internal DR_FStrList rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras); +internal DR_FStrList rd_title_fstrs_from_cfg(Arena *arena, CFG_Node *cfg, B32 include_extras); internal DR_FStrList rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_extras); internal DR_FStrList rd_title_fstrs_from_code_name(Arena *arena, String8 code_name); internal DR_FStrList rd_title_fstrs_from_file_path(Arena *arena, String8 file_path); From 784476174844166d587e4e0e46853932692fe0b4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 15:19:18 -0700 Subject: [PATCH 129/133] float keymaps into config --- src/config/config_bindings.c | 111 ++++++++++++++++++++++ src/config/config_bindings.h | 59 ++++++++++++ src/config/{config.c => config_core.c} | 0 src/config/{config.h => config_core.h} | 6 +- src/config/config_inc.c | 7 ++ src/config/config_inc.h | 12 +++ src/raddbg/generated/raddbg.meta.c | 2 +- src/raddbg/raddbg.mdesk | 3 +- src/raddbg/raddbg_core.c | 125 +++---------------------- src/raddbg/raddbg_core.h | 55 +---------- src/raddbg/raddbg_eval.c | 4 +- src/raddbg/raddbg_main.c | 4 +- src/raddbg/raddbg_widgets.c | 12 +-- 13 files changed, 218 insertions(+), 182 deletions(-) create mode 100644 src/config/config_bindings.c create mode 100644 src/config/config_bindings.h rename src/config/{config.c => config_core.c} (100%) rename src/config/{config.h => config_core.h} (95%) create mode 100644 src/config/config_inc.c create mode 100644 src/config/config_inc.h diff --git a/src/config/config_bindings.c b/src/config/config_bindings.c new file mode 100644 index 00000000..5d95b3a7 --- /dev/null +++ b/src/config/config_bindings.c @@ -0,0 +1,111 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal CFG_KeyMap * +cfg_key_map_from_cfg(Arena *arena) +{ + Temp scratch = scratch_begin(&arena, 1); + CFG_KeyMap *key_map = push_array(arena, CFG_KeyMap, 1); + { + key_map->name_slots_count = 4096; + key_map->name_slots = push_array(arena, CFG_KeyMapSlot, key_map->name_slots_count); + key_map->binding_slots_count = 4096; + key_map->binding_slots = push_array(arena, CFG_KeyMapSlot, key_map->binding_slots_count); + + //- rjf: gather & parse all explicitly stored keybinding sets + CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings")); + for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next) + { + CFG_Node *keybindings_root = n->v; + for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next) + { + String8 name = {0}; + CFG_Binding binding = {0}; + for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next) + { + if(0){} + else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; } + else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; } + else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; } + else + { + OS_Key key = OS_Key_Null; + for EachEnumVal(OS_Key, k) + { + if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive)) + { + key = k; + break; + } + } + if(key != OS_Key_Null) + { + binding.key = key; + } + else + { + name = child->string; + } + } + } + if(name.size != 0) + { + U64 name_hash = d_hash_from_string(name); + U64 binding_hash = d_hash_from_string(str8_struct(&binding)); + U64 name_slot_idx = name_hash%key_map->name_slots_count; + U64 binding_slot_idx = binding_hash%key_map->binding_slots_count; + CFG_KeyMapNode *n = push_array(arena, CFG_KeyMapNode, 1); + n->cfg_id = keybinding->id; + n->name = push_str8_copy(arena, name); + n->binding = binding; + SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next); + SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next); + } + } + } + } + scratch_end(scratch); + return key_map; +} + +internal CFG_KeyMapNodePtrList +cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string) +{ + CFG_KeyMapNodePtrList list = {0}; + { + U64 hash = d_hash_from_string(string); + U64 slot_idx = hash%key_map->name_slots_count; + for(CFG_KeyMapNode *n = key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next) + { + if(str8_match(n->name, string, 0)) + { + CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1); + ptr->v = n; + SLLQueuePush(list.first, list.last, ptr); + list.count += 1; + } + } + } + return list; +} + +internal CFG_KeyMapNodePtrList +cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding) +{ + CFG_KeyMapNodePtrList list = {0}; + { + U64 hash = d_hash_from_string(str8_struct(&binding)); + U64 slot_idx = hash%key_map->binding_slots_count; + for(CFG_KeyMapNode *n = key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next) + { + if(MemoryMatchStruct(&binding, &n->binding)) + { + CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1); + ptr->v = n; + SLLQueuePush(list.first, list.last, ptr); + list.count += 1; + } + } + } + return list; +} diff --git a/src/config/config_bindings.h b/src/config/config_bindings.h new file mode 100644 index 00000000..8bb875e3 --- /dev/null +++ b/src/config/config_bindings.h @@ -0,0 +1,59 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CONFIG_BINDINGS_H +#define CONFIG_BINDINGS_H + +typedef struct CFG_Binding CFG_Binding; +struct CFG_Binding +{ + OS_Key key; + OS_Modifiers modifiers; +}; + +typedef struct CFG_KeyMapNode CFG_KeyMapNode; +struct CFG_KeyMapNode +{ + CFG_KeyMapNode *name_hash_next; + CFG_KeyMapNode *binding_hash_next; + CFG_ID cfg_id; + String8 name; + CFG_Binding binding; +}; + +typedef struct CFG_KeyMapNodePtr CFG_KeyMapNodePtr; +struct CFG_KeyMapNodePtr +{ + CFG_KeyMapNodePtr *next; + CFG_KeyMapNode *v; +}; + +typedef struct CFG_KeyMapNodePtrList CFG_KeyMapNodePtrList; +struct CFG_KeyMapNodePtrList +{ + CFG_KeyMapNodePtr *first; + CFG_KeyMapNodePtr *last; + U64 count; +}; + +typedef struct CFG_KeyMapSlot CFG_KeyMapSlot; +struct CFG_KeyMapSlot +{ + CFG_KeyMapNode *first; + CFG_KeyMapNode *last; +}; + +typedef struct CFG_KeyMap CFG_KeyMap; +struct CFG_KeyMap +{ + U64 name_slots_count; + CFG_KeyMapSlot *name_slots; + U64 binding_slots_count; + CFG_KeyMapSlot *binding_slots; +}; + +internal CFG_KeyMap *cfg_key_map_from_cfg(Arena *arena); +internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string); +internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding); + +#endif // CONFIG_BINDINGS_H diff --git a/src/config/config.c b/src/config/config_core.c similarity index 100% rename from src/config/config.c rename to src/config/config_core.c diff --git a/src/config/config.h b/src/config/config_core.h similarity index 95% rename from src/config/config.h rename to src/config/config_core.h index 3099ccc4..6598fda0 100644 --- a/src/config/config.h +++ b/src/config/config_core.h @@ -1,8 +1,8 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef CONFIG_H -#define CONFIG_H +#ifndef CONFIG_CORE_H +#define CONFIG_CORE_H //////////////////////////////// //~ rjf: IDs @@ -230,4 +230,4 @@ internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Nod //- rjf: deserialization internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string); -#endif // CONFIG_H +#endif // CONFIG_CORE_H diff --git a/src/config/config_inc.c b/src/config/config_inc.c new file mode 100644 index 00000000..081328a2 --- /dev/null +++ b/src/config/config_inc.c @@ -0,0 +1,7 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "config_core.c" +#if defined(OS_GFX_H) +# include "config_bindings.c" +#endif diff --git a/src/config/config_inc.h b/src/config/config_inc.h new file mode 100644 index 00000000..66499a5f --- /dev/null +++ b/src/config/config_inc.h @@ -0,0 +1,12 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CONFIG_INC_H +#define CONFIG_INC_H + +#include "config_core.h" +#if defined(OS_GFX_H) +# include "config_bindings.h" +#endif + +#endif // CONFIG_INC_H diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 875b6d11..80bbe9b8 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -795,7 +795,7 @@ RD_CmdKindInfo rd_cmd_kind_info_table[245] = { str8_lit_comp("geo3d"), str8_lit_comp("Opens a Geometry (3D) tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, }; -struct {String8 string; RD_Binding binding;} rd_default_binding_table[116] = +struct {String8 string; CFG_Binding binding;} rd_default_binding_table[116] = { {str8_lit_comp("kill_all"), {OS_Key_F5, 0 |OS_Modifier_Shift }}, {str8_lit_comp("step_into_inst"), {OS_Key_F11, 0 |OS_Modifier_Alt}}, diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 143b0a78..86bad0d1 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -1301,7 +1301,7 @@ RD_DefaultBindingTable: { "toggle_dev_menu" D ctrl shift alt } } -@data(`struct {String8 string; RD_Binding binding;}`) @c_file rd_default_binding_table: +@data(`struct {String8 string; CFG_Binding binding;}`) @c_file rd_default_binding_table: { @expand(RD_DefaultBindingTable a) ```{str8_lit_comp("$(a.name)"), {OS_Key_$(a.key), 0 $(a.ctrl != 0 -> `|OS_Modifier_Ctrl`) $(a.shift != 0 -> `|OS_Modifier_Shift`) $(a.alt != 0 -> `|OS_Modifier_Alt`)}}```; } @@ -1320,7 +1320,6 @@ RD_BindingVersionRemapTable: {"address_breakpoint" "add_address_breakpoint"} {"function_breakpoint" "add_function_breakpoint"} {"toggle_breakpoint_cursor" "toggle_breakpoint"} - } @data(String8) rd_binding_version_remap_old_name_table: diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index c9651f03..20af316f 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -356,48 +356,6 @@ rd_cfg_is_project_filtered(CFG_Node *cfg) return result; } -internal RD_KeyMapNodePtrList -rd_key_map_node_ptr_list_from_name(Arena *arena, String8 string) -{ - RD_KeyMapNodePtrList list = {0}; - { - U64 hash = d_hash_from_string(string); - U64 slot_idx = hash%rd_state->key_map->name_slots_count; - for(RD_KeyMapNode *n = rd_state->key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next) - { - if(str8_match(n->name, string, 0)) - { - RD_KeyMapNodePtr *ptr = push_array(arena, RD_KeyMapNodePtr, 1); - ptr->v = n; - SLLQueuePush(list.first, list.last, ptr); - list.count += 1; - } - } - } - return list; -} - -internal RD_KeyMapNodePtrList -rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding) -{ - RD_KeyMapNodePtrList list = {0}; - { - U64 hash = d_hash_from_string(str8_struct(&binding)); - U64 slot_idx = hash%rd_state->key_map->binding_slots_count; - for(RD_KeyMapNode *n = rd_state->key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next) - { - if(MemoryMatchStruct(&binding, &n->binding)) - { - RD_KeyMapNodePtr *ptr = push_array(arena, RD_KeyMapNodePtr, 1); - ptr->v = n; - SLLQueuePush(list.first, list.last, ptr); - list.count += 1; - } - } - } - return list; -} - internal Vec4F32 rd_hsva_from_cfg(CFG_Node *cfg) { @@ -10825,72 +10783,7 @@ rd_frame(void) // ProfScope("build key map from config") { - //- rjf: set up table - rd_state->key_map = push_array(rd_frame_arena(), RD_KeyMap, 1); - RD_KeyMap *key_map = rd_state->key_map; - key_map->name_slots_count = 4096; - key_map->name_slots = push_array(rd_frame_arena(), RD_KeyMapSlot, key_map->name_slots_count); - key_map->binding_slots_count = 4096; - key_map->binding_slots = push_array(rd_frame_arena(), RD_KeyMapSlot, key_map->binding_slots_count); - - //- rjf: gather & parse all explicitly stored keybinding sets - CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings")); - for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next) - { - CFG_Node *keybindings_root = n->v; - for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next) - { - String8 name = {0}; - RD_Binding binding = {0}; - for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next) - { - if(0){} - else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; } - else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; } - else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; } - else - { - OS_Key key = OS_Key_Null; - for EachEnumVal(OS_Key, k) - { - if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive)) - { - key = k; - break; - } - } - if(key != OS_Key_Null) - { - binding.key = key; - } - else - { - name = child->string; - for(U64 idx = 0; idx < ArrayCount(rd_binding_version_remap_old_name_table); idx += 1) - { - if(str8_match(rd_binding_version_remap_old_name_table[idx], name, StringMatchFlag_CaseInsensitive)) - { - name = rd_binding_version_remap_new_name_table[idx]; - } - } - } - } - } - if(name.size != 0) - { - U64 name_hash = d_hash_from_string(name); - U64 binding_hash = d_hash_from_string(str8_struct(&binding)); - U64 name_slot_idx = name_hash%key_map->name_slots_count; - U64 binding_slot_idx = binding_hash%key_map->binding_slots_count; - RD_KeyMapNode *n = push_array(rd_frame_arena(), RD_KeyMapNode, 1); - n->cfg_id = keybinding->id; - n->name = push_str8_copy(rd_frame_arena(), name); - n->binding = binding; - SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next); - SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next); - } - } - } + rd_state->key_map = cfg_key_map_from_cfg(rd_frame_arena()); } ////////////////////////////// @@ -10991,14 +10884,22 @@ rd_frame(void) //- rjf: try hotkey presses if(!take && event->kind == OS_EventKind_Press) { - RD_Binding binding = {event->key, event->modifiers}; - RD_KeyMapNodePtrList key_map_nodes = rd_key_map_node_ptr_list_from_binding(scratch.arena, binding); + CFG_Binding binding = {event->key, event->modifiers}; + CFG_KeyMapNodePtrList key_map_nodes = cfg_key_map_node_ptr_list_from_binding(scratch.arena, rd_state->key_map, binding); if(key_map_nodes.first != 0) { U32 hit_char = os_codepoint_from_modifiers_and_key(event->modifiers, event->key); if(hit_char == 0 || allow_text_hotkeys) { - rd_cmd(RD_CmdKind_RunCommand, .cmd_name = key_map_nodes.first->v->name); + String8 cmd_name = key_map_nodes.first->v->name; + for(U64 idx = 0; idx < ArrayCount(rd_binding_version_remap_old_name_table); idx += 1) + { + if(str8_match(rd_binding_version_remap_old_name_table[idx], cmd_name, StringMatchFlag_CaseInsensitive)) + { + cmd_name = rd_binding_version_remap_new_name_table[idx]; + } + } + rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_name); if(allow_text_hotkeys) { os_text(&events, event->window, hit_char); @@ -12313,7 +12214,7 @@ rd_frame(void) for EachElement(idx, rd_default_binding_table) { String8 name = rd_default_binding_table[idx].string; - RD_Binding binding = rd_default_binding_table[idx].binding; + CFG_Binding binding = rd_default_binding_table[idx].binding; CFG_Node *binding_root = cfg_node_new(rd_state->cfg, keybindings, str8_zero()); cfg_node_new(rd_state->cfg, binding_root, name); cfg_node_new(rd_state->cfg, binding_root, os_g_key_cfg_string_table[binding.key]); diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index a9af5770..e9e3b6ea 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -4,57 +4,6 @@ #ifndef RADDBG_CORE_H #define RADDBG_CORE_H -//////////////////////////////// -//~ rjf: Key Bindings - -typedef struct RD_Binding RD_Binding; -struct RD_Binding -{ - OS_Key key; - OS_Modifiers modifiers; -}; - -typedef struct RD_KeyMapNode RD_KeyMapNode; -struct RD_KeyMapNode -{ - RD_KeyMapNode *name_hash_next; - RD_KeyMapNode *binding_hash_next; - CFG_ID cfg_id; - String8 name; - RD_Binding binding; -}; - -typedef struct RD_KeyMapNodePtr RD_KeyMapNodePtr; -struct RD_KeyMapNodePtr -{ - RD_KeyMapNodePtr *next; - RD_KeyMapNode *v; -}; - -typedef struct RD_KeyMapNodePtrList RD_KeyMapNodePtrList; -struct RD_KeyMapNodePtrList -{ - RD_KeyMapNodePtr *first; - RD_KeyMapNodePtr *last; - U64 count; -}; - -typedef struct RD_KeyMapSlot RD_KeyMapSlot; -struct RD_KeyMapSlot -{ - RD_KeyMapNode *first; - RD_KeyMapNode *last; -}; - -typedef struct RD_KeyMap RD_KeyMap; -struct RD_KeyMap -{ - U64 name_slots_count; - RD_KeyMapSlot *name_slots; - U64 binding_slots_count; - RD_KeyMapSlot *binding_slots; -}; - //////////////////////////////// //~ rjf: Evaluation Spaces @@ -513,7 +462,7 @@ struct RD_State RD_AmbiguousPathNode **ambiguous_path_slots; // rjf: key map (constructed from-scratch each frame) - RD_KeyMap *key_map; + CFG_KeyMap *key_map; // rjf: slot -> font tag map (constructed from-scratch each frame) FNT_Tag font_slot_table[RD_FontSlot_COUNT]; @@ -686,8 +635,6 @@ internal Rng2F32 rd_target_rect_from_panel_node_child(Rng2F32 parent_rect, RD_Pa internal Rng2F32 rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNode *panel); internal B32 rd_cfg_is_project_filtered(CFG_Node *cfg); -internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_name(Arena *arena, String8 string); -internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding); internal Vec4F32 rd_hsva_from_cfg(CFG_Node *cfg); internal Vec4F32 rd_color_from_cfg(CFG_Node *cfg); diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 9b2891b6..f060d482 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -43,8 +43,8 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(commands) FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, display_name); FuzzyMatchRangeList tags_matches = fuzzy_match_find(scratch.arena, filter, search_tags); B32 binding_matches_good = 0; - RD_KeyMapNodePtrList bindings = rd_key_map_node_ptr_list_from_name(scratch.arena, code_name); - for(RD_KeyMapNodePtr *n = bindings.first; n != 0; n = n->next) + CFG_KeyMapNodePtrList bindings = cfg_key_map_node_ptr_list_from_name(scratch.arena, rd_state->key_map, code_name); + for(CFG_KeyMapNodePtr *n = bindings.first; n != 0; n = n->next) { String8 binding_text = os_string_from_modifiers_key(scratch.arena, n->v->binding.modifiers, n->v->binding.key); FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, binding_text); diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index e63e500a..c0432068 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -223,7 +223,7 @@ #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" #include "mdesk/mdesk.h" -#include "config/config.h" +#include "config/config_inc.h" #include "content/content.h" #include "file_stream/file_stream.h" #include "text/text.h" @@ -271,7 +271,7 @@ #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" #include "mdesk/mdesk.c" -#include "config/config.c" +#include "config/config_inc.c" #include "content/content.c" #include "file_stream/file_stream.c" #include "text/text.c" diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 761392e5..b4af8506 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -754,22 +754,22 @@ internal void rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new) { Temp scratch = scratch_begin(0, 0); - RD_KeyMapNodePtrList key_map_nodes = rd_key_map_node_ptr_list_from_name(scratch.arena, name); + CFG_KeyMapNodePtrList key_map_nodes = cfg_key_map_node_ptr_list_from_name(scratch.arena, rd_state->key_map, name); //- rjf: build buttons for each binding - UI_CornerRadius(ui_top_font_size()*0.5f) for(RD_KeyMapNodePtr *n = key_map_nodes.first; n != 0; n = n->next) + UI_CornerRadius(ui_top_font_size()*0.5f) for(CFG_KeyMapNodePtr *n = key_map_nodes.first; n != 0; n = n->next) { ui_spacer(ui_em(1.f, 1.f)); - RD_Binding binding = n->v->binding; + CFG_Binding binding = n->v->binding; B32 rebinding_active_for_this_binding = (rd_state->bind_change_active && str8_match(rd_state->bind_change_cmd_name, name, 0) && n->v->cfg_id == rd_state->bind_change_binding_id); //- rjf: grab all conflicts B32 has_conflicts = 0; - RD_KeyMapNodePtrList nodes_with_this_binding = rd_key_map_node_ptr_list_from_binding(scratch.arena, binding); + CFG_KeyMapNodePtrList nodes_with_this_binding = cfg_key_map_node_ptr_list_from_binding(scratch.arena, rd_state->key_map, binding); { - for(RD_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next) + for(CFG_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next) { if(!str8_match(n->v->name, n2->v->name, 0)) { @@ -840,7 +840,7 @@ rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new) if(ui_hovering(sig) && has_conflicts) UI_Tooltip { UI_PrefWidth(ui_children_sum(1)) rd_error_label(str8_lit("This binding conflicts with those for:")); - for(RD_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next) + for(CFG_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next) { if(!str8_match(n2->v->name, n->v->name, 0)) { From 0f277d6e6ee6103dcab7abc8b9b09beef6dec44f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 15:26:07 -0700 Subject: [PATCH 130/133] float panels into config layer --- src/config/config_inc.c | 1 + src/config/config_inc.h | 1 + src/config/config_panels.c | 217 ++++++++++++ src/config/config_panels.h | 67 ++++ src/raddbg/raddbg_core.c | 676 +++++++++++++------------------------ src/raddbg/raddbg_core.h | 62 ---- src/raddbg/raddbg_main.c | 2 +- 7 files changed, 525 insertions(+), 501 deletions(-) create mode 100644 src/config/config_panels.c create mode 100644 src/config/config_panels.h diff --git a/src/config/config_inc.c b/src/config/config_inc.c index 081328a2..f927a51d 100644 --- a/src/config/config_inc.c +++ b/src/config/config_inc.c @@ -2,6 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) #include "config_core.c" +#include "config_panels.c" #if defined(OS_GFX_H) # include "config_bindings.c" #endif diff --git a/src/config/config_inc.h b/src/config/config_inc.h index 66499a5f..0460d200 100644 --- a/src/config/config_inc.h +++ b/src/config/config_inc.h @@ -5,6 +5,7 @@ #define CONFIG_INC_H #include "config_core.h" +#include "config_panels.h" #if defined(OS_GFX_H) # include "config_bindings.h" #endif diff --git a/src/config/config_panels.c b/src/config/config_panels.c new file mode 100644 index 00000000..3746fad0 --- /dev/null +++ b/src/config/config_panels.c @@ -0,0 +1,217 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal CFG_Node * +cfg_window_from_cfg(CFG_Node *cfg) +{ + CFG_Node *result = &cfg_nil_node; + for(CFG_Node *c = cfg; c != &cfg_nil_node; c = c->parent) + { + if(c->parent->parent == cfg_node_root() && str8_match(c->string, str8_lit("window"), 0)) + { + result = c; + break; + } + } + return result; +} + +internal CFG_PanelTree +cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root) +{ + Temp scratch = scratch_begin(&arena, 1); + CFG_Node *wcfg = cfg_window_from_cfg(cfg_root); + CFG_Node *src_root = cfg_node_child_from_string(wcfg, str8_lit("panels")); + CFG_PanelNode *dst_root = &cfg_nil_panel_node; + CFG_PanelNode *dst_focused = &cfg_nil_panel_node; + { + Axis2 active_split_axis = cfg_node_child_from_string(wcfg, str8_lit("split_x")) != &cfg_nil_node ? Axis2_X : Axis2_Y; + CFG_NodeRec rec = {0}; + CFG_PanelNode *dst_active_parent = &cfg_nil_panel_node; + for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next) + { + // rjf: build a panel node + CFG_PanelNode *dst = push_array(arena, CFG_PanelNode, 1); + MemoryCopyStruct(dst, &cfg_nil_panel_node); + dst->parent = dst_active_parent; + if(dst_active_parent != &cfg_nil_panel_node) + { + DLLPushBack_NPZ(&cfg_nil_panel_node, dst_active_parent->first, dst_active_parent->last, dst, next, prev); + dst_active_parent->child_count += 1; + } + if(dst_root == &cfg_nil_panel_node) + { + dst_root = dst; + } + + // rjf: extract cfg info + B32 panel_has_children = 0; + dst->cfg = src; + dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string)); + dst->tab_side = (cfg_node_child_from_string(src, str8_lit("tabs_on_bottom")) != &cfg_nil_node ? Side_Max : Side_Min); + dst->split_axis = active_split_axis; + for(CFG_Node *src_child = src->first; src_child != &cfg_nil_node; src_child = src_child->next) + { + MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string); + if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric) + { + panel_has_children = 1; + } + else if(str8_match(src_child->string, str8_lit("tabs_on_bottom"), 0)) + { + // NOTE(rjf): skip - this is a panel option. + } + else if(str8_match(src_child->string, str8_lit("selected"), 0)) + { + dst_focused = dst; + } + else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier) + { + cfg_node_ptr_list_push(arena, &dst->tabs, src_child); + if(cfg_node_child_from_string(src_child, str8_lit("selected")) != &cfg_nil_node) + { + dst->selected_tab = src_child; + } + } + } + + // rjf: recurse + rec = cfg_node_rec__depth_first(src_root, src); + if(!panel_has_children) + { + MemoryZeroStruct(&rec); + rec.next = &cfg_nil_node; + for(CFG_Node *p = src; p != src_root && p != &cfg_nil_node; p = p->parent, rec.pop_count += 1) + { + if(p->next != &cfg_nil_node) + { + rec.next = p->next; + break; + } + } + } + if(rec.push_count > 0) + { + dst_active_parent = dst; + active_split_axis = axis2_flip(active_split_axis); + } + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + dst_active_parent = dst_active_parent->parent; + active_split_axis = axis2_flip(active_split_axis); + } + } + } + scratch_end(scratch); + CFG_PanelTree tree = {dst_root, dst_focused}; + return tree; +} + +internal CFG_PanelNodeRec +cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off) +{ + CFG_PanelNodeRec rec = {&cfg_nil_panel_node}; + if(*MemberFromOffset(CFG_PanelNode **, panel, child_off) != &cfg_nil_panel_node) + { + rec.next = *MemberFromOffset(CFG_PanelNode **, panel, child_off); + rec.push_count += 1; + } + else for(CFG_PanelNode *p = panel; p != &cfg_nil_panel_node && p != root; p = p->parent, rec.pop_count += 1) + { + if(*MemberFromOffset(CFG_PanelNode **, p, sib_off) != &cfg_nil_panel_node) + { + rec.next = *MemberFromOffset(CFG_PanelNode **, p, sib_off); + break; + } + } + return rec; +} + +internal CFG_PanelNode * +cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg) +{ + CFG_PanelNode *result = &cfg_nil_panel_node; + for(CFG_PanelNode *p = root; + p != &cfg_nil_panel_node; + p = cfg_panel_node_rec__depth_first_pre(root, p).next) + { + if(p->cfg == cfg) + { + result = p; + break; + } + } + return result; +} + +internal Rng2F32 +cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel) +{ + Rng2F32 rect = parent_rect; + if(parent != &cfg_nil_panel_node) + { + Vec2F32 parent_rect_size = dim_2f32(parent_rect); + Axis2 axis = parent->split_axis; + rect.p1.v[axis] = rect.p0.v[axis]; + for(CFG_PanelNode *child = parent->first; child != &cfg_nil_panel_node; child = child->next) + { + rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent; + if(child == panel) + { + break; + } + rect.p0.v[axis] = rect.p1.v[axis]; + } + //rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis]; + //rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)]; + } + rect.x0 = round_f32(rect.x0); + rect.x1 = round_f32(rect.x1); + rect.y0 = round_f32(rect.y0); + rect.y1 = round_f32(rect.y1); + return rect; +} + +internal Rng2F32 +cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel) +{ + Temp scratch = scratch_begin(0, 0); + + // rjf: count ancestors + U64 ancestor_count = 0; + for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent) + { + ancestor_count += 1; + } + + // rjf: gather ancestors + CFG_PanelNode **ancestors = push_array(scratch.arena, CFG_PanelNode *, ancestor_count); + { + U64 ancestor_idx = 0; + for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent) + { + ancestors[ancestor_idx] = p; + ancestor_idx += 1; + } + } + + // rjf: go from highest ancestor => panel and calculate rect + Rng2F32 parent_rect = root_rect; + for(S64 ancestor_idx = (S64)ancestor_count-1; + 0 <= ancestor_idx && ancestor_idx < ancestor_count; + ancestor_idx -= 1) + { + CFG_PanelNode *ancestor = ancestors[ancestor_idx]; + CFG_PanelNode *parent = ancestor->parent; + if(parent != &cfg_nil_panel_node) + { + parent_rect = cfg_target_rect_from_panel_node_child(parent_rect, parent, ancestor); + } + } + + // rjf: calculate final rect + Rng2F32 rect = cfg_target_rect_from_panel_node_child(parent_rect, panel->parent, panel); + + scratch_end(scratch); + return rect; +} diff --git a/src/config/config_panels.h b/src/config/config_panels.h new file mode 100644 index 00000000..5733ccf8 --- /dev/null +++ b/src/config/config_panels.h @@ -0,0 +1,67 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CONFIG_PANELS_H +#define CONFIG_PANELS_H + +typedef struct CFG_PanelNode CFG_PanelNode; +struct CFG_PanelNode +{ + // rjf: links data + CFG_PanelNode *first; + CFG_PanelNode *last; + CFG_PanelNode *next; + CFG_PanelNode *prev; + CFG_PanelNode *parent; + U64 child_count; + CFG_Node *cfg; + + // rjf: split data + Axis2 split_axis; + F32 pct_of_parent; + + // rjf: tab params + Side tab_side; + + // rjf: which tabs are attached + CFG_NodePtrList tabs; + CFG_Node *selected_tab; +}; + +typedef struct CFG_PanelTree CFG_PanelTree; +struct CFG_PanelTree +{ + CFG_PanelNode *root; + CFG_PanelNode *focused; +}; + +typedef struct CFG_PanelNodeRec CFG_PanelNodeRec; +struct CFG_PanelNodeRec +{ + CFG_PanelNode *next; + S32 push_count; + S32 pop_count; +}; + +read_only global CFG_PanelNode cfg_nil_panel_node = +{ + &cfg_nil_panel_node, + &cfg_nil_panel_node, + &cfg_nil_panel_node, + &cfg_nil_panel_node, + &cfg_nil_panel_node, + 0, + &cfg_nil_node, + .selected_tab = &cfg_nil_node, +}; + +internal CFG_Node *cfg_window_from_cfg(CFG_Node *cfg); +internal CFG_PanelTree cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root); +internal CFG_PanelNodeRec cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off); +#define cfg_panel_node_rec__depth_first_pre(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, next), OffsetOf(CFG_PanelNode, first)) +#define cfg_panel_node_rec__depth_first_pre_rev(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, prev), OffsetOf(CFG_PanelNode, last)) +internal CFG_PanelNode *cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg); +internal Rng2F32 cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel); +internal Rng2F32 cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel); + +#endif // CONFIG_PANELS_H diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 20af316f..32deec8f 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -148,206 +148,6 @@ rd_get_hover_regs(void) //////////////////////////////// //~ rjf: Config Functions -internal RD_PanelTree -rd_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root) -{ - Temp scratch = scratch_begin(&arena, 1); - CFG_Node *wcfg = rd_window_from_cfg(cfg_root); - CFG_Node *src_root = cfg_node_child_from_string(wcfg, str8_lit("panels")); - RD_PanelNode *dst_root = &rd_nil_panel_node; - RD_PanelNode *dst_focused = &rd_nil_panel_node; - { - Axis2 active_split_axis = cfg_node_child_from_string(wcfg, str8_lit("split_x")) != &cfg_nil_node ? Axis2_X : Axis2_Y; - CFG_NodeRec rec = {0}; - RD_PanelNode *dst_active_parent = &rd_nil_panel_node; - for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next) - { - // rjf: build a panel node - RD_PanelNode *dst = push_array(arena, RD_PanelNode, 1); - MemoryCopyStruct(dst, &rd_nil_panel_node); - dst->parent = dst_active_parent; - if(dst_active_parent != &rd_nil_panel_node) - { - DLLPushBack_NPZ(&rd_nil_panel_node, dst_active_parent->first, dst_active_parent->last, dst, next, prev); - dst_active_parent->child_count += 1; - } - if(dst_root == &rd_nil_panel_node) - { - dst_root = dst; - } - - // rjf: extract cfg info - B32 panel_has_children = 0; - dst->cfg = src; - dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string)); - dst->tab_side = (cfg_node_child_from_string(src, str8_lit("tabs_on_bottom")) != &cfg_nil_node ? Side_Max : Side_Min); - dst->split_axis = active_split_axis; - for(CFG_Node *src_child = src->first; src_child != &cfg_nil_node; src_child = src_child->next) - { - MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string); - if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric) - { - panel_has_children = 1; - } - else if(str8_match(src_child->string, str8_lit("tabs_on_bottom"), 0)) - { - // NOTE(rjf): skip - this is a panel option. - } - else if(str8_match(src_child->string, str8_lit("selected"), 0)) - { - dst_focused = dst; - } - else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier) - { - cfg_node_ptr_list_push(arena, &dst->tabs, src_child); - if(cfg_node_child_from_string(src_child, str8_lit("selected")) != &cfg_nil_node) - { - dst->selected_tab = src_child; - } - } - } - - // rjf: recurse - rec = cfg_node_rec__depth_first(src_root, src); - if(!panel_has_children) - { - MemoryZeroStruct(&rec); - rec.next = &cfg_nil_node; - for(CFG_Node *p = src; p != src_root && p != &cfg_nil_node; p = p->parent, rec.pop_count += 1) - { - if(p->next != &cfg_nil_node) - { - rec.next = p->next; - break; - } - } - } - if(rec.push_count > 0) - { - dst_active_parent = dst; - active_split_axis = axis2_flip(active_split_axis); - } - else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) - { - dst_active_parent = dst_active_parent->parent; - active_split_axis = axis2_flip(active_split_axis); - } - } - } - scratch_end(scratch); - RD_PanelTree tree = {dst_root, dst_focused}; - return tree; -} - -internal RD_PanelNodeRec -rd_panel_node_rec__depth_first(RD_PanelNode *root, RD_PanelNode *panel, U64 sib_off, U64 child_off) -{ - RD_PanelNodeRec rec = {&rd_nil_panel_node}; - if(*MemberFromOffset(RD_PanelNode **, panel, child_off) != &rd_nil_panel_node) - { - rec.next = *MemberFromOffset(RD_PanelNode **, panel, child_off); - rec.push_count += 1; - } - else for(RD_PanelNode *p = panel; p != &rd_nil_panel_node && p != root; p = p->parent, rec.pop_count += 1) - { - if(*MemberFromOffset(RD_PanelNode **, p, sib_off) != &rd_nil_panel_node) - { - rec.next = *MemberFromOffset(RD_PanelNode **, p, sib_off); - break; - } - } - return rec; -} - -internal RD_PanelNode * -rd_panel_node_from_tree_cfg(RD_PanelNode *root, CFG_Node *cfg) -{ - RD_PanelNode *result = &rd_nil_panel_node; - for(RD_PanelNode *p = root; - p != &rd_nil_panel_node; - p = rd_panel_node_rec__depth_first_pre(root, p).next) - { - if(p->cfg == cfg) - { - result = p; - break; - } - } - return result; -} - -internal Rng2F32 -rd_target_rect_from_panel_node_child(Rng2F32 parent_rect, RD_PanelNode *parent, RD_PanelNode *panel) -{ - Rng2F32 rect = parent_rect; - if(parent != &rd_nil_panel_node) - { - Vec2F32 parent_rect_size = dim_2f32(parent_rect); - Axis2 axis = parent->split_axis; - rect.p1.v[axis] = rect.p0.v[axis]; - for(RD_PanelNode *child = parent->first; child != &rd_nil_panel_node; child = child->next) - { - rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent; - if(child == panel) - { - break; - } - rect.p0.v[axis] = rect.p1.v[axis]; - } - //rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis]; - //rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)]; - } - rect.x0 = round_f32(rect.x0); - rect.x1 = round_f32(rect.x1); - rect.y0 = round_f32(rect.y0); - rect.y1 = round_f32(rect.y1); - return rect; -} - -internal Rng2F32 -rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNode *panel) -{ - Temp scratch = scratch_begin(0, 0); - - // rjf: count ancestors - U64 ancestor_count = 0; - for(RD_PanelNode *p = panel->parent; p != &rd_nil_panel_node; p = p->parent) - { - ancestor_count += 1; - } - - // rjf: gather ancestors - RD_PanelNode **ancestors = push_array(scratch.arena, RD_PanelNode *, ancestor_count); - { - U64 ancestor_idx = 0; - for(RD_PanelNode *p = panel->parent; p != &rd_nil_panel_node; p = p->parent) - { - ancestors[ancestor_idx] = p; - ancestor_idx += 1; - } - } - - // rjf: go from highest ancestor => panel and calculate rect - Rng2F32 parent_rect = root_rect; - for(S64 ancestor_idx = (S64)ancestor_count-1; - 0 <= ancestor_idx && ancestor_idx < ancestor_count; - ancestor_idx -= 1) - { - RD_PanelNode *ancestor = ancestors[ancestor_idx]; - RD_PanelNode *parent = ancestor->parent; - if(parent != &rd_nil_panel_node) - { - parent_rect = rd_target_rect_from_panel_node_child(parent_rect, parent, ancestor); - } - } - - // rjf: calculate final rect - Rng2F32 rect = rd_target_rect_from_panel_node_child(parent_rect, panel->parent, panel); - - scratch_end(scratch); - return rect; -} - internal B32 rd_cfg_is_project_filtered(CFG_Node *cfg) { @@ -4429,9 +4229,9 @@ rd_view_ui(Rng2F32 rect) { if(cfg != &cfg_nil_node) { - RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, cfg); - RD_PanelNode *parent_panel_node = rd_panel_node_from_tree_cfg(panels.root, cfg->parent); - if(parent_panel_node != &rd_nil_panel_node) + CFG_PanelTree panels = cfg_panel_tree_from_cfg(scratch.arena, cfg); + CFG_PanelNode *parent_panel_node = cfg_panel_node_from_tree_cfg(panels.root, cfg->parent); + if(parent_panel_node != &cfg_nil_panel_node) { rd_regs()->tab = rd_regs()->view = cfg->id; } @@ -5152,7 +4952,7 @@ rd_window_frame(void) // CFG_Node *window = cfg_node_from_id(rd_regs()->window); RD_WindowState *ws = rd_window_state_from_cfg(cfg_node_from_id(rd_regs()->window)); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); B32 window_is_focused = (os_window_is_focused(ws->os) || ws->window_temporarily_focused_ipc); B32 popup_is_open = (rd_state->popup_active); B32 query_is_open = (ws->query_is_active); @@ -6215,16 +6015,16 @@ rd_window_frame(void) // rjf: disable hover eval if hovered view is actively scrolling if(hover_eval_is_open) { - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(panel->first != &rd_nil_panel_node) { continue; } + if(panel->first != &cfg_nil_panel_node) { continue; } CFG_Node *tab = panel->selected_tab; if(tab != &cfg_nil_node) { RD_ViewState *vs = rd_view_state_from_cfg(tab); - Rng2F32 panel_rect = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); + Rng2F32 panel_rect = cfg_target_rect_from_panel_node(content_rect, panel_tree.root, panel); if(contains_2f32(panel_rect, ui_mouse()) && (abs_f32(vs->scroll_pos.x.off) > 0.01f || abs_f32(vs->scroll_pos.y.off) > 0.01f)) @@ -7409,14 +7209,14 @@ rd_window_frame(void) // B32 is_changing_panel_boundaries = 0; ProfScope("non-leaf panel UI") - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { ////////////////////////// //- rjf: continue on leaf panels // - if(panel->first == &rd_nil_panel_node) + if(panel->first == &cfg_nil_panel_node) { continue; } @@ -7425,7 +7225,7 @@ rd_window_frame(void) //- rjf: grab info // Axis2 split_axis = panel->split_axis; - Rng2F32 panel_rect = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); + Rng2F32 panel_rect = cfg_target_rect_from_panel_node(content_rect, panel_tree.root, panel); ////////////////////////// //- rjf: boundary tab-drag/drop sites @@ -7523,7 +7323,7 @@ rd_window_frame(void) Dir2_Invalid); if(dir != Dir2_Invalid) { - RD_PanelNode *split_panel = panel; + CFG_PanelNode *split_panel = panel; rd_cmd(RD_CmdKind_SplitPanel, .dst_panel = split_panel->cfg->id, .panel = rd_state->drag_drop_regs->panel, @@ -7536,10 +7336,10 @@ rd_window_frame(void) //- rjf: iterate all children, build boundary drop sites Axis2 split_axis = panel->split_axis; - UI_CornerRadius(corner_radius) for(RD_PanelNode *child = panel->first;; child = child->next) + UI_CornerRadius(corner_radius) for(CFG_PanelNode *child = panel->first;; child = child->next) { // rjf: form rect - Rng2F32 child_rect = rd_target_rect_from_panel_node_child(panel_rect, panel, child); + Rng2F32 child_rect = cfg_target_rect_from_panel_node_child(panel_rect, panel, child); Vec2F32 child_rect_center = center_2f32(child_rect); UI_Key key = ui_key_from_stringf(ui_key_zero(), "drop_boundary_%p_%p", panel->cfg, child->cfg); Rng2F32 site_rect = r2f32(child_rect_center, child_rect_center); @@ -7610,8 +7410,8 @@ rd_window_frame(void) if(ui_key_match(site_box->key, ui_drop_hot_key()) && rd_drag_drop()) { Dir2 dir = (panel->split_axis == Axis2_X ? Dir2_Left : Dir2_Up); - RD_PanelNode *split_panel = child; - if(split_panel == &rd_nil_panel_node) + CFG_PanelNode *split_panel = child; + if(split_panel == &cfg_nil_panel_node) { split_panel = panel->last; dir = (panel->split_axis == Axis2_X ? Dir2_Right : Dir2_Down); @@ -7624,7 +7424,7 @@ rd_window_frame(void) } // rjf: exit on opl child - if(child == &rd_nil_panel_node) + if(child == &cfg_nil_panel_node) { break; } @@ -7635,14 +7435,14 @@ rd_window_frame(void) ////////////////////////// //- rjf: do UI for drag boundaries between all children // - for(RD_PanelNode *child = panel->first; - child != &rd_nil_panel_node && child->next != &rd_nil_panel_node; + for(CFG_PanelNode *child = panel->first; + child != &cfg_nil_panel_node && child->next != &cfg_nil_panel_node; child = child->next) { - RD_PanelNode *min_child = child; - RD_PanelNode *max_child = min_child->next; - Rng2F32 min_child_rect = rd_target_rect_from_panel_node_child(panel_rect, panel, min_child); - Rng2F32 max_child_rect = rd_target_rect_from_panel_node_child(panel_rect, panel, max_child); + CFG_PanelNode *min_child = child; + CFG_PanelNode *max_child = min_child->next; + Rng2F32 min_child_rect = cfg_target_rect_from_panel_node_child(panel_rect, panel, min_child); + Rng2F32 max_child_rect = cfg_target_rect_from_panel_node_child(panel_rect, panel, max_child); Rng2F32 boundary_rect = {0}; { boundary_rect.p0.v[split_axis] = min_child_rect.p1.v[split_axis] - ui_top_font_size()/3; @@ -7713,11 +7513,11 @@ rd_window_frame(void) Vec2F32 content_rect_dim = dim_2f32(content_rect); if(content_rect_dim.x > 0 && content_rect_dim.y > 0) { - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - Rng2F32 target_rect_px = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); + Rng2F32 target_rect_px = cfg_target_rect_from_panel_node(content_rect, panel_tree.root, panel); Rng2F32 target_rect_pct = r2f32p(target_rect_px.x0/content_rect_dim.x, target_rect_px.y0/content_rect_dim.y, target_rect_px.x1/content_rect_dim.x, @@ -7738,11 +7538,11 @@ rd_window_frame(void) if(content_rect.x1 > content_rect.x0 && content_rect.y1 > content_rect.y0) { ProfScope("leaf panel UI") - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(panel->first != &rd_nil_panel_node) {continue;} + if(panel->first != &cfg_nil_panel_node) {continue;} B32 panel_is_focused = (window_is_focused && !ws->menu_bar_focused && !query_is_open && @@ -7758,7 +7558,7 @@ rd_window_frame(void) //- rjf: calculate UI rectangles // Vec2F32 content_rect_dim = dim_2f32(content_rect); - Rng2F32 target_rect_px = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); + Rng2F32 target_rect_px = cfg_target_rect_from_panel_node(content_rect, panel_tree.root, panel); Rng2F32 target_rect_pct = r2f32p(target_rect_px.x0 / content_rect_dim.x, target_rect_px.y0 / content_rect_dim.y, target_rect_px.x1 / content_rect_dim.x, @@ -8061,7 +7861,7 @@ rd_window_frame(void) } //- rjf: build empty view - UI_Parent(view_container_box) if(selected_tab == &cfg_nil_node && panel->parent != &rd_nil_panel_node) + UI_Parent(view_container_box) if(selected_tab == &cfg_nil_node && panel->parent != &cfg_nil_panel_node) { ui_set_next_flags(UI_BoxFlag_DefaultFocusNav); UI_Focus(UI_FocusKind_On) UI_WidthFill UI_HeightFill UI_NamedColumn(str8_lit("empty_view")) UI_TagF("weak") @@ -10473,8 +10273,8 @@ rd_frame(void) for(CFG_NodePtrNode *n = windows.first; n != 0; n = n->next) { CFG_Node *window = n->v; - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + for(CFG_PanelNode *p = panel_tree.root; p != &cfg_nil_panel_node; p = cfg_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { for(CFG_NodePtrNode *n = p->tabs.first; n != 0; n = n->next) { @@ -10821,7 +10621,7 @@ rd_frame(void) if(ws != 0 && ws != rd_window_state_from_cfg(cfg_node_from_id(rd_regs()->window))) { Temp scratch = scratch_begin(0, 0); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(ws->cfg_id)); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(ws->cfg_id)); rd_regs()->window = ws->cfg_id; rd_regs()->panel = panel_tree.focused->cfg->id; rd_regs()->tab = panel_tree.focused->selected_tab->id; @@ -11218,10 +11018,10 @@ rd_frame(void) expr->type_key = type_key; e_string2expr_map_insert(scratch.arena, macro_map, push_str8f(scratch.arena, "query:config.$%I64x", window->id), expr); } - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - for(RD_PanelNode *p = panel_tree.root; - p != &rd_nil_panel_node; - p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + for(CFG_PanelNode *p = panel_tree.root; + p != &cfg_nil_panel_node; + p = cfg_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { for(CFG_NodePtrNode *tab_n = p->tabs.first; tab_n != 0; tab_n = tab_n->next) { @@ -11972,7 +11772,7 @@ rd_frame(void) case RD_CmdKind_OpenPalette: { CFG_Node *window = cfg_node_from_id(rd_regs()->window); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); CFG_Node *tab = panel_tree.focused->selected_tab; String8List exprs = {0}; { @@ -12386,8 +12186,8 @@ rd_frame(void) CFG_NodePtrList windows = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("window")); for(CFG_NodePtrNode *n = windows.first; n != 0; n = n->next) { - RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, n->v); - for(RD_PanelNode *panel = panels.root; panel != &rd_nil_panel_node; panel = rd_panel_node_rec__depth_first_pre(panels.root, panel).next) + CFG_PanelTree panels = cfg_panel_tree_from_cfg(scratch.arena, n->v); + for(CFG_PanelNode *panel = panels.root; panel != &cfg_nil_panel_node; panel = cfg_panel_node_rec__depth_first_pre(panels.root, panel).next) { if(rd_cfg_is_project_filtered(panel->selected_tab)) { @@ -12625,20 +12425,20 @@ rd_frame(void) split_panel = cfg_node_from_id(rd_regs()->panel); } CFG_Node *new_panel_cfg = &cfg_nil_node; - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, split_panel); - RD_PanelNode *panel_root = panel_tree.root; - RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_root, split_panel); - RD_PanelNode *parent = panel->parent; + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, split_panel); + CFG_PanelNode *panel_root = panel_tree.root; + CFG_PanelNode *panel = cfg_panel_node_from_tree_cfg(panel_root, split_panel); + CFG_PanelNode *parent = panel->parent; // rjf: splitting on same axis as parent -> insert new sibling on same axis, adjust sizes - if(parent != &rd_nil_panel_node && parent->split_axis == split_axis) + if(parent != &cfg_nil_panel_node && parent->split_axis == split_axis) { CFG_Node *parent_cfg = parent->cfg; CFG_Node *panel_cfg = panel->cfg; CFG_Node *new_cfg = cfg_node_alloc(rd_state->cfg); cfg_node_insert_child(rd_state->cfg, parent_cfg, split_side == Side_Max ? panel_cfg : panel_cfg->prev, new_cfg); cfg_node_equip_stringf(rd_state->cfg, new_cfg, "%f", 1.f/(parent->child_count+1)); - for(RD_PanelNode *child = parent->first; child != &rd_nil_panel_node; child = child->next) + for(CFG_PanelNode *child = parent->first; child != &cfg_nil_panel_node; child = child->next) { F32 old_pct = child->pct_of_parent; F32 new_pct = old_pct * ((F32)(parent->child_count) / (parent->child_count+1)); @@ -12693,18 +12493,18 @@ rd_frame(void) if(ws != &rd_nil_window_state) { ui_select_state(ws->ui); - RD_PanelTree new_panel_tree = rd_panel_tree_from_cfg(scratch.arena, new_panel_cfg); - RD_PanelNode *new_panel = rd_panel_node_from_tree_cfg(new_panel_tree.root, new_panel_cfg); + CFG_PanelTree new_panel_tree = cfg_panel_tree_from_cfg(scratch.arena, new_panel_cfg); + CFG_PanelNode *new_panel = cfg_panel_node_from_tree_cfg(new_panel_tree.root, new_panel_cfg); Rng2F32 stub_content_rect = r2f32p(0, 0, 1000, 1000); Vec2F32 stub_content_rect_dim = dim_2f32(stub_content_rect); - Rng2F32 new_rect_px = rd_target_rect_from_panel_node(stub_content_rect, new_panel_tree.root, new_panel); + Rng2F32 new_rect_px = cfg_target_rect_from_panel_node(stub_content_rect, new_panel_tree.root, new_panel); Rng2F32 new_rect_pct = r2f32p(new_rect_px.x0/stub_content_rect_dim.x, new_rect_px.y0/stub_content_rect_dim.y, new_rect_px.x1/stub_content_rect_dim.x, new_rect_px.y1/stub_content_rect_dim.y); - if(new_panel->prev != &rd_nil_panel_node) + if(new_panel->prev != &cfg_nil_panel_node) { - Rng2F32 target_prev_rect_px = rd_target_rect_from_panel_node(stub_content_rect, panel_tree.root, rd_panel_node_from_tree_cfg(panel_tree.root, new_panel->prev->cfg)); + Rng2F32 target_prev_rect_px = cfg_target_rect_from_panel_node(stub_content_rect, panel_tree.root, cfg_panel_node_from_tree_cfg(panel_tree.root, new_panel->prev->cfg)); Rng2F32 target_prev_rect_pct = r2f32p(target_prev_rect_px.x0/stub_content_rect_dim.x, target_prev_rect_px.y0/stub_content_rect_dim.y, target_prev_rect_px.x1/stub_content_rect_dim.x, @@ -12716,9 +12516,9 @@ rd_frame(void) new_rect_pct = prev_rect_pct; new_rect_pct.p0.v[split_axis] = new_rect_pct.p1.v[split_axis]; } - if(new_panel->next != &rd_nil_panel_node) + if(new_panel->next != &cfg_nil_panel_node) { - Rng2F32 target_next_rect_px = rd_target_rect_from_panel_node(stub_content_rect, panel_tree.root, rd_panel_node_from_tree_cfg(panel_tree.root, new_panel->next->cfg)); + Rng2F32 target_next_rect_px = cfg_target_rect_from_panel_node(stub_content_rect, panel_tree.root, cfg_panel_node_from_tree_cfg(panel_tree.root, new_panel->next->cfg)); Rng2F32 target_next_rect_pct = r2f32p(target_next_rect_px.x0/stub_content_rect_dim.x, target_next_rect_px.y0/stub_content_rect_dim.y, target_next_rect_px.x1/stub_content_rect_dim.x, @@ -12746,8 +12546,8 @@ rd_frame(void) { cfg_node_unhook(rd_state->cfg, dragdrop_origin_panel_cfg, dragdrop_tab); cfg_node_insert_child(rd_state->cfg, new_panel_cfg, new_panel_cfg->last, dragdrop_tab); - RD_PanelTree origin_panel_tree = rd_panel_tree_from_cfg(scratch.arena, dragdrop_origin_panel_cfg); - RD_PanelNode *origin_panel = rd_panel_node_from_tree_cfg(origin_panel_tree.root, dragdrop_origin_panel_cfg); + CFG_PanelTree origin_panel_tree = cfg_panel_tree_from_cfg(scratch.arena, dragdrop_origin_panel_cfg); + CFG_PanelNode *origin_panel = cfg_panel_node_from_tree_cfg(origin_panel_tree.root, dragdrop_origin_panel_cfg); if(origin_panel->selected_tab == &cfg_nil_node) { for(CFG_NodePtrNode *n = origin_panel->tabs.first; n != 0; n = n->next) @@ -12783,10 +12583,10 @@ rd_frame(void) case RD_CmdKind_RotatePanelColumns: { CFG_Node *panel_cfg = cfg_node_from_id(rd_regs()->panel); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel_cfg); - RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, panel_cfg); - RD_PanelNode *parent = &rd_nil_panel_node; - for(RD_PanelNode *p = panel->parent; p != &rd_nil_panel_node; p = p->parent) + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, panel_cfg); + CFG_PanelNode *panel = cfg_panel_node_from_tree_cfg(panel_tree.root, panel_cfg); + CFG_PanelNode *parent = &cfg_nil_panel_node; + for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent) { if(p->split_axis == Axis2_X) { @@ -12794,7 +12594,7 @@ rd_frame(void) break; } } - if(parent != &rd_nil_panel_node && parent->child_count > 1) + if(parent != &cfg_nil_panel_node && parent->child_count > 1) { CFG_Node *rotated = parent->first->cfg; cfg_node_unhook(rd_state->cfg, parent->cfg, parent->first->cfg); @@ -12803,29 +12603,29 @@ rd_frame(void) }break; //- rjf: panel focusing - case RD_CmdKind_NextPanel: panel_sib_off = OffsetOf(RD_PanelNode, next); panel_child_off = OffsetOf(RD_PanelNode, first); goto cycle; - case RD_CmdKind_PrevPanel: panel_sib_off = OffsetOf(RD_PanelNode, prev); panel_child_off = OffsetOf(RD_PanelNode, last); goto cycle; + case RD_CmdKind_NextPanel: panel_sib_off = OffsetOf(CFG_PanelNode, next); panel_child_off = OffsetOf(CFG_PanelNode, first); goto cycle; + case RD_CmdKind_PrevPanel: panel_sib_off = OffsetOf(CFG_PanelNode, prev); panel_child_off = OffsetOf(CFG_PanelNode, last); goto cycle; cycle:; { - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(rd_regs()->window)); - RD_PanelNode *next_focused = &rd_nil_panel_node; - for(RD_PanelNode *p = panel_tree.focused; - p != &rd_nil_panel_node; - p = rd_panel_node_rec__depth_first(panel_tree.root, p, panel_sib_off, panel_child_off).next) + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(rd_regs()->window)); + CFG_PanelNode *next_focused = &cfg_nil_panel_node; + for(CFG_PanelNode *p = panel_tree.focused; + p != &cfg_nil_panel_node; + p = cfg_panel_node_rec__depth_first(panel_tree.root, p, panel_sib_off, panel_child_off).next) { - if(p != panel_tree.focused && p->first == &rd_nil_panel_node) + if(p != panel_tree.focused && p->first == &cfg_nil_panel_node) { next_focused = p; break; } } - if(next_focused == &rd_nil_panel_node) + if(next_focused == &cfg_nil_panel_node) { - for(RD_PanelNode *p = panel_tree.root; - p != &rd_nil_panel_node; - p = rd_panel_node_rec__depth_first(panel_tree.root, p, panel_sib_off, panel_child_off).next) + for(CFG_PanelNode *p = panel_tree.root; + p != &cfg_nil_panel_node; + p = cfg_panel_node_rec__depth_first(panel_tree.root, p, panel_sib_off, panel_child_off).next) { - if(p != panel_tree.focused && p->first == &rd_nil_panel_node) + if(p != panel_tree.focused && p->first == &cfg_nil_panel_node) { next_focused = p; break; @@ -12837,11 +12637,11 @@ rd_frame(void) case RD_CmdKind_FocusPanel: { CFG_Node *panel = cfg_node_from_id(rd_regs()->panel); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, panel); CFG_Node *selection_cfg = &cfg_nil_node; - for(RD_PanelNode *p = panel_tree.root; - p != &rd_nil_panel_node; - p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) + for(CFG_PanelNode *p = panel_tree.root; + p != &cfg_nil_panel_node; + p = cfg_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { CFG_Node *p_cfg = p->cfg; CFG_Node *p_selection = cfg_node_child_from_string(p_cfg, str8_lit("selected")); @@ -12876,33 +12676,33 @@ rd_frame(void) focus_panel_dir:; { CFG_Node *window = cfg_node_from_id(rd_regs()->window); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *src_panel = panel_tree.focused; - Rng2F32 src_panel_rect = rd_target_rect_from_panel_node(r2f32(v2f32(0, 0), v2f32(1000, 1000)), panel_tree.root, src_panel); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelNode *src_panel = panel_tree.focused; + Rng2F32 src_panel_rect = cfg_target_rect_from_panel_node(r2f32(v2f32(0, 0), v2f32(1000, 1000)), panel_tree.root, src_panel); Vec2F32 src_panel_center = center_2f32(src_panel_rect); Vec2F32 src_panel_half_dim = scale_2f32(dim_2f32(src_panel_rect), 0.5f); Vec2F32 travel_dim = add_2f32(src_panel_half_dim, v2f32(10.f, 10.f)); Vec2F32 travel_dst = add_2f32(src_panel_center, mul_2f32(travel_dim, v2f32((F32)panel_change_dir.x, (F32)panel_change_dir.y))); - RD_PanelNode *dst_root = &rd_nil_panel_node; - for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) + CFG_PanelNode *dst_root = &cfg_nil_panel_node; + for(CFG_PanelNode *p = panel_tree.root; p != &cfg_nil_panel_node; p = cfg_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { - if(p == src_panel || p->first != &rd_nil_panel_node) + if(p == src_panel || p->first != &cfg_nil_panel_node) { continue; } - Rng2F32 p_rect = rd_target_rect_from_panel_node(r2f32(v2f32(0, 0), v2f32(1000, 1000)), panel_tree.root, p); + Rng2F32 p_rect = cfg_target_rect_from_panel_node(r2f32(v2f32(0, 0), v2f32(1000, 1000)), panel_tree.root, p); if(contains_2f32(p_rect, travel_dst)) { dst_root = p; break; } } - if(dst_root != &rd_nil_panel_node) + if(dst_root != &cfg_nil_panel_node) { - RD_PanelNode *dst_panel = &rd_nil_panel_node; - for(RD_PanelNode *p = dst_root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(dst_root, p).next) + CFG_PanelNode *dst_panel = &cfg_nil_panel_node; + for(CFG_PanelNode *p = dst_root; p != &cfg_nil_panel_node; p = cfg_panel_node_rec__depth_first_pre(dst_root, p).next) { - if(p->first == &rd_nil_panel_node && p != src_panel) + if(p->first == &cfg_nil_panel_node && p != src_panel) { dst_panel = p; break; @@ -13025,10 +12825,10 @@ rd_frame(void) case RD_CmdKind_ClosePanel: { CFG_Node *window = cfg_node_from_id(rd_regs()->window); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, cfg_node_from_id(rd_regs()->panel)); - RD_PanelNode *parent = panel->parent; - if(parent != &rd_nil_panel_node) + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelNode *panel = cfg_panel_node_from_tree_cfg(panel_tree.root, cfg_node_from_id(rd_regs()->panel)); + CFG_PanelNode *parent = panel->parent; + if(parent != &cfg_nil_panel_node) { Axis2 split_axis = parent->split_axis; @@ -13036,17 +12836,17 @@ rd_frame(void) // we should just remove both children. if(parent->child_count == 2) { - RD_PanelNode *discard_child = panel; - RD_PanelNode *keep_child = (panel == parent->first ? parent->last : parent->first); - RD_PanelNode *grandparent = parent->parent; - RD_PanelNode *parent_prev = parent->prev; + CFG_PanelNode *discard_child = panel; + CFG_PanelNode *keep_child = (panel == parent->first ? parent->last : parent->first); + CFG_PanelNode *grandparent = parent->parent; + CFG_PanelNode *parent_prev = parent->prev; F32 pct_of_parent = parent->pct_of_parent; // rjf: unhook kept child cfg_node_unhook(rd_state->cfg, parent->cfg, keep_child->cfg); // rjf: unhook this subtree - if(grandparent != &rd_nil_panel_node) + if(grandparent != &cfg_nil_panel_node) { cfg_node_unhook(rd_state->cfg, grandparent->cfg, parent->cfg); } @@ -13057,7 +12857,7 @@ rd_frame(void) } // rjf: re-hook our kept child into the overall tree - if(grandparent == &rd_nil_panel_node) + if(grandparent == &cfg_nil_panel_node) { if(keep_child->split_axis == Axis2_X) { @@ -13077,11 +12877,11 @@ rd_frame(void) } // rjf: keep-child split-axis == grandparent split-axis? bubble keep-child up into grandparent's children - if(grandparent != &rd_nil_panel_node && grandparent->split_axis == keep_child->split_axis && keep_child->first != &rd_nil_panel_node) + if(grandparent != &cfg_nil_panel_node && grandparent->split_axis == keep_child->split_axis && keep_child->first != &cfg_nil_panel_node) { cfg_node_unhook(rd_state->cfg, grandparent->cfg, keep_child->cfg); CFG_Node *prev = parent_prev->cfg; - for(RD_PanelNode *child = keep_child->first, *next = &rd_nil_panel_node; child != &rd_nil_panel_node; child = next) + for(CFG_PanelNode *child = keep_child->first, *next = &cfg_nil_panel_node; child != &cfg_nil_panel_node; child = next) { next = child->next; cfg_node_unhook(rd_state->cfg, keep_child->cfg, child->cfg); @@ -13097,9 +12897,9 @@ rd_frame(void) // rjf: reset focus, if needed if(panel_tree.focused == discard_child) { - RD_PanelTree new_panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *new_focused = rd_panel_node_from_tree_cfg(panel_tree.root, keep_child->cfg); - for(RD_PanelNode *grandchild = new_focused; grandchild != &rd_nil_panel_node; grandchild = grandchild->first) + CFG_PanelTree new_panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelNode *new_focused = cfg_panel_node_from_tree_cfg(panel_tree.root, keep_child->cfg); + for(CFG_PanelNode *grandchild = new_focused; grandchild != &cfg_nil_panel_node; grandchild = grandchild->first) { new_focused = grandchild; } @@ -13110,18 +12910,18 @@ rd_frame(void) else { // rjf: remove - RD_PanelNode *next = &rd_nil_panel_node; + CFG_PanelNode *next = &cfg_nil_panel_node; F32 removed_size_pct = panel->pct_of_parent; - if(next == &rd_nil_panel_node) { next = panel->prev; } - if(next == &rd_nil_panel_node) { next = panel->next; } + if(next == &cfg_nil_panel_node) { next = panel->prev; } + if(next == &cfg_nil_panel_node) { next = panel->next; } cfg_node_unhook(rd_state->cfg, parent->cfg, panel->cfg); cfg_node_release(rd_state->cfg, panel->cfg); // rjf: resize siblings to this node { - RD_PanelTree new_panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *new_parent = rd_panel_node_from_tree_cfg(new_panel_tree.root, parent->cfg); - for(RD_PanelNode *child = new_parent->first; child != &rd_nil_panel_node; child = child->next) + CFG_PanelTree new_panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelNode *new_parent = cfg_panel_node_from_tree_cfg(new_panel_tree.root, parent->cfg); + for(CFG_PanelNode *child = new_parent->first; child != &cfg_nil_panel_node; child = child->next) { CFG_Node *cfg = child->cfg; F32 old_pct = child->pct_of_parent; @@ -13133,9 +12933,9 @@ rd_frame(void) // rjf: reset focus, if needed if(panel_tree.focused == panel) { - RD_PanelTree new_panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *new_focused = rd_panel_node_from_tree_cfg(panel_tree.root, next->cfg); - for(RD_PanelNode *grandchild = new_focused; grandchild != &rd_nil_panel_node; grandchild = grandchild->first) + CFG_PanelTree new_panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelNode *new_focused = cfg_panel_node_from_tree_cfg(panel_tree.root, next->cfg); + for(CFG_PanelNode *grandchild = new_focused; grandchild != &cfg_nil_panel_node; grandchild = grandchild->first) { new_focused = grandchild; } @@ -13150,8 +12950,8 @@ rd_frame(void) { CFG_Node *tab = cfg_node_from_id(rd_regs()->tab); CFG_Node *panel = tab->parent; - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel); - RD_PanelNode *panel_node = rd_panel_node_from_tree_cfg(panel_tree.root, panel); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, panel); + CFG_PanelNode *panel_node = cfg_panel_node_from_tree_cfg(panel_tree.root, panel); CFG_Node *selection_cfg = &cfg_nil_node; for(CFG_NodePtrNode *n = panel_node->tabs.first; n != 0; n = n->next) { @@ -13175,8 +12975,8 @@ rd_frame(void) case RD_CmdKind_NextTab: { CFG_Node *window = cfg_node_from_id(rd_regs()->window); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *focused = panel_tree.focused; + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelNode *focused = panel_tree.focused; CFG_NodePtrNode *selected_tab_n = 0; for(CFG_NodePtrNode *n = focused->tabs.first; n != 0; n = n->next) { @@ -13206,8 +13006,8 @@ rd_frame(void) case RD_CmdKind_PrevTab: { CFG_Node *window = cfg_node_from_id(rd_regs()->window); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *focused = panel_tree.focused; + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelNode *focused = panel_tree.focused; CFG_NodePtrNode *selected_tab_n = 0; for(CFG_NodePtrNode *n = focused->tabs.last; n != 0; n = n->prev) { @@ -13239,8 +13039,8 @@ rd_frame(void) { CFG_Node *tab = cfg_node_from_id(rd_regs()->tab); CFG_Node *window = rd_window_from_cfg(tab); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, tab->parent); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelNode *panel = cfg_panel_node_from_tree_cfg(panel_tree.root, tab->parent); CFG_NodePtrList filtered_tabs = {0}; for(CFG_NodePtrNode *n = panel->tabs.first; n != 0; n = n->next) { @@ -13310,8 +13110,8 @@ rd_frame(void) case RD_CmdKind_CloseTab: { CFG_Node *tab = cfg_node_from_id(rd_regs()->tab); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, tab); - RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, tab->parent); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, tab); + CFG_PanelNode *panel = cfg_panel_node_from_tree_cfg(panel_tree.root, tab->parent); if(panel->selected_tab == tab) { B32 found_selected = 0; @@ -13347,8 +13147,8 @@ rd_frame(void) cfg_node_insert_child(rd_state->cfg, dst_panel, prev_tab, view); rd_cmd(RD_CmdKind_FocusTab, .panel = dst_panel->id, .tab = view->id); rd_cmd(RD_CmdKind_FocusPanel, .panel = dst_panel->id); - RD_PanelTree src_panel_tree = rd_panel_tree_from_cfg(scratch.arena, src_panel); - RD_PanelNode *src_panel_node = rd_panel_node_from_tree_cfg(src_panel_tree.root, src_panel); + CFG_PanelTree src_panel_tree = cfg_panel_tree_from_cfg(scratch.arena, src_panel); + CFG_PanelNode *src_panel_node = cfg_panel_node_from_tree_cfg(src_panel_tree.root, src_panel); B32 src_panel_is_empty = 0; if(src_panel != dst_panel) { @@ -13519,7 +13319,7 @@ rd_frame(void) { CFG_Node *window = cfg_node_from_id(rd_regs()->window); CFG_Node *panels = cfg_node_child_from_string(window, str8_lit("panels")); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); //- rjf: define all of the "fixed" tabs we care about #define X(name) CFG_Node *name = &cfg_nil_node; @@ -13533,9 +13333,9 @@ rd_frame(void) //- rjf: find all the fixed tabs, and all text viewers B32 any_fixed_tabs_found = 0; CFG_NodePtrList texts = {0}; - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { for(CFG_NodePtrNode *n = panel->tabs.first; n != 0; n = n->next) { @@ -14071,36 +13871,36 @@ rd_frame(void) { WindowInfo *next; CFG_Node *window; - RD_PanelTree panel_tree; - RD_PanelNode *panel_w_this_src_code; + CFG_PanelTree panel_tree; + CFG_PanelNode *panel_w_this_src_code; CFG_Node *view_w_this_src_code; - RD_PanelNode *panel_w_auto; + CFG_PanelNode *panel_w_auto; CFG_Node *view_w_auto; - RD_PanelNode *panel_w_any_src_code; - RD_PanelNode *panel_w_disasm; + CFG_PanelNode *panel_w_any_src_code; + CFG_PanelNode *panel_w_disasm; CFG_Node *view_w_disasm; - RD_PanelNode *biggest_panel; - RD_PanelNode *biggest_empty_panel; + CFG_PanelNode *biggest_panel; + CFG_PanelNode *biggest_empty_panel; }; WindowInfo *first_window_info = 0; WindowInfo *last_window_info = 0; for(WindowTask *t = first_window_task; t != 0; t = t->next) { CFG_Node *window = t->window; - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); WindowInfo *info = push_array(scratch.arena, WindowInfo, 1); SLLQueuePush(first_window_info, last_window_info, info); info->window = window; info->panel_tree = panel_tree; // rjf: first, try to find panel/view pair that already has the src file open - info->panel_w_this_src_code = &rd_nil_panel_node; + info->panel_w_this_src_code = &cfg_nil_panel_node; info->view_w_this_src_code = &cfg_nil_node; - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(panel->first != &rd_nil_panel_node) + if(panel->first != &cfg_nil_panel_node) { continue; } @@ -14124,13 +13924,13 @@ rd_frame(void) } // rjf: try to find panel/view pair that has any *auto* source code tab open - info->panel_w_auto = &rd_nil_panel_node; + info->panel_w_auto = &cfg_nil_panel_node; info->view_w_auto = &cfg_nil_node; - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(panel->first != &rd_nil_panel_node) + if(panel->first != &cfg_nil_panel_node) { continue; } @@ -14151,19 +13951,19 @@ rd_frame(void) } // rjf: find a panel that already has *any* code open (prioritize largest) - info->panel_w_any_src_code = &rd_nil_panel_node; + info->panel_w_any_src_code = &cfg_nil_panel_node; { Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); F32 best_panel_area = 0; - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(panel->first != &rd_nil_panel_node) + if(panel->first != &cfg_nil_panel_node) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); + Rng2F32 panel_rect = cfg_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) @@ -14183,20 +13983,20 @@ rd_frame(void) } // rjf: try to find panel/view pair that has disassembly open (prioritize largest) - info->panel_w_disasm = &rd_nil_panel_node; + info->panel_w_disasm = &cfg_nil_panel_node; info->view_w_disasm = &cfg_nil_node; { Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); F32 best_panel_area = 0; - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(panel->first != &rd_nil_panel_node) + if(panel->first != &cfg_nil_panel_node) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); + Rng2F32 panel_rect = cfg_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) @@ -14223,19 +14023,19 @@ rd_frame(void) } // rjf: find the biggest panel - info->biggest_panel = &rd_nil_panel_node; + info->biggest_panel = &cfg_nil_panel_node; { Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); F32 best_panel_area = 0; - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(panel->first != &rd_nil_panel_node) + if(panel->first != &cfg_nil_panel_node) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); + Rng2F32 panel_rect = cfg_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; if((best_panel_area == 0 || panel_area > best_panel_area)) @@ -14247,19 +14047,19 @@ rd_frame(void) } // rjf: find the biggest empty panel - info->biggest_empty_panel = &rd_nil_panel_node; + info->biggest_empty_panel = &cfg_nil_panel_node; { Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); F32 best_panel_area = 0; - for(RD_PanelNode *panel = panel_tree.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + for(CFG_PanelNode *panel = panel_tree.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(panel->first != &rd_nil_panel_node) + if(panel->first != &cfg_nil_panel_node) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); + Rng2F32 panel_rect = cfg_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; B32 panel_is_empty = 1; @@ -14288,13 +14088,13 @@ rd_frame(void) { FindCodeLocTask *next; CFG_Node *window; - RD_PanelNode *src_code_dst_panel; - RD_PanelNode *disasm_dst_panel; - RD_PanelNode *panel_w_this_src_code; + CFG_PanelNode *src_code_dst_panel; + CFG_PanelNode *disasm_dst_panel; + CFG_PanelNode *panel_w_this_src_code; CFG_Node *view_w_this_src_code; - RD_PanelNode *panel_w_auto; + CFG_PanelNode *panel_w_auto; CFG_Node *view_w_auto; - RD_PanelNode *panel_w_disasm; + CFG_PanelNode *panel_w_disasm; CFG_Node *view_w_disasm; }; FindCodeLocTask *first_task = 0; @@ -14304,21 +14104,21 @@ rd_frame(void) for(WindowInfo *info = first_window_info; info != 0; info = info->next) { // rjf: choose panel for source code - RD_PanelNode *src_code_dst_panel = &rd_nil_panel_node; + CFG_PanelNode *src_code_dst_panel = &cfg_nil_panel_node; if(file_path.size != 0 && info->panel_w_this_src_code->selected_tab == info->view_w_this_src_code) { src_code_dst_panel = info->panel_w_this_src_code; } // rjf: choose panel for disassembly - RD_PanelNode *disasm_dst_panel = &rd_nil_panel_node; + CFG_PanelNode *disasm_dst_panel = &cfg_nil_panel_node; if(vaddr != 0 && info->panel_w_disasm->selected_tab == info->view_w_disasm) { disasm_dst_panel = info->panel_w_disasm; } // rjf: push task - if(src_code_dst_panel != &rd_nil_panel_node || disasm_dst_panel != &rd_nil_panel_node) + if(src_code_dst_panel != &cfg_nil_panel_node || disasm_dst_panel != &cfg_nil_panel_node) { FindCodeLocTask *t = push_array(scratch.arena, FindCodeLocTask, 1); SLLQueuePush(first_task, last_task, t); @@ -14331,8 +14131,8 @@ rd_frame(void) t->view_w_auto = info->view_w_auto; t->panel_w_disasm = info->panel_w_disasm; t->view_w_disasm = info->view_w_disasm; - if(src_code_dst_panel != &rd_nil_panel_node) { did_src_code_snap = 1; } - if(disasm_dst_panel != &rd_nil_panel_node) { did_disasm_snap = 1; } + if(src_code_dst_panel != &cfg_nil_panel_node) { did_src_code_snap = 1; } + if(disasm_dst_panel != &cfg_nil_panel_node) { did_disasm_snap = 1; } } } @@ -14341,22 +14141,22 @@ rd_frame(void) for(WindowInfo *info = first_window_info; info != 0; info = info->next) { // rjf: choose panel for source code - RD_PanelNode *src_code_dst_panel = &rd_nil_panel_node; + CFG_PanelNode *src_code_dst_panel = &cfg_nil_panel_node; if(!did_src_code_snap && file_path.size != 0) { - if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = info->panel_w_this_src_code; } - if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = info->panel_w_auto; } + if(src_code_dst_panel == &cfg_nil_panel_node) { src_code_dst_panel = info->panel_w_this_src_code; } + if(src_code_dst_panel == &cfg_nil_panel_node) { src_code_dst_panel = info->panel_w_auto; } } // rjf: choose panel for disassembly - RD_PanelNode *disasm_dst_panel = &rd_nil_panel_node; + CFG_PanelNode *disasm_dst_panel = &cfg_nil_panel_node; if(!did_disasm_snap && vaddr != 0) { - if(disasm_dst_panel == &rd_nil_panel_node) { disasm_dst_panel = info->panel_w_disasm; } + if(disasm_dst_panel == &cfg_nil_panel_node) { disasm_dst_panel = info->panel_w_disasm; } } // rjf: push task - if(src_code_dst_panel != &rd_nil_panel_node || disasm_dst_panel != &rd_nil_panel_node) + if(src_code_dst_panel != &cfg_nil_panel_node || disasm_dst_panel != &cfg_nil_panel_node) { FindCodeLocTask *t = push_array(scratch.arena, FindCodeLocTask, 1); SLLQueuePush(first_task, last_task, t); @@ -14369,8 +14169,8 @@ rd_frame(void) t->view_w_auto = info->view_w_auto; t->panel_w_disasm = info->panel_w_disasm; t->view_w_disasm = info->view_w_disasm; - if(src_code_dst_panel != &rd_nil_panel_node) { did_src_code_snap = 1; } - if(disasm_dst_panel != &rd_nil_panel_node) { did_disasm_snap = 1; } + if(src_code_dst_panel != &cfg_nil_panel_node) { did_src_code_snap = 1; } + if(disasm_dst_panel != &cfg_nil_panel_node) { did_disasm_snap = 1; } } } @@ -14378,27 +14178,27 @@ rd_frame(void) for(WindowInfo *info = first_window_info; info != 0; info = info->next) { // rjf: choose panel for source code - RD_PanelNode *src_code_dst_panel = &rd_nil_panel_node; + CFG_PanelNode *src_code_dst_panel = &cfg_nil_panel_node; if(!did_src_code_snap && file_path.size != 0) { - if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = info->panel_w_auto; } + if(src_code_dst_panel == &cfg_nil_panel_node) { src_code_dst_panel = info->panel_w_auto; } } // rjf: push task - if(src_code_dst_panel != &rd_nil_panel_node) + if(src_code_dst_panel != &cfg_nil_panel_node) { FindCodeLocTask *t = push_array(scratch.arena, FindCodeLocTask, 1); SLLQueuePush(first_task, last_task, t); t->window = info->window; t->src_code_dst_panel = src_code_dst_panel; - t->disasm_dst_panel = &rd_nil_panel_node; + t->disasm_dst_panel = &cfg_nil_panel_node; t->panel_w_this_src_code= info->panel_w_this_src_code; t->view_w_this_src_code = info->view_w_this_src_code; t->panel_w_auto = info->panel_w_auto; t->view_w_auto = info->view_w_auto; t->panel_w_disasm = info->panel_w_disasm; t->view_w_disasm = info->view_w_disasm; - if(src_code_dst_panel != &rd_nil_panel_node) { did_src_code_snap = 1; } + if(src_code_dst_panel != &cfg_nil_panel_node) { did_src_code_snap = 1; } } } @@ -14408,27 +14208,27 @@ rd_frame(void) for(WindowInfo *info = first_window_info; info != 0; info = info->next) { // rjf: choose panel for source code - RD_PanelNode *src_code_dst_panel = &rd_nil_panel_node; + CFG_PanelNode *src_code_dst_panel = &cfg_nil_panel_node; if(!did_src_code_snap && file_path.size != 0) { - if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = info->panel_w_this_src_code; } - if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = info->panel_w_auto; } - if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = info->panel_w_any_src_code; } - if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = info->biggest_empty_panel; } - if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = info->biggest_panel; } + if(src_code_dst_panel == &cfg_nil_panel_node) { src_code_dst_panel = info->panel_w_this_src_code; } + if(src_code_dst_panel == &cfg_nil_panel_node) { src_code_dst_panel = info->panel_w_auto; } + if(src_code_dst_panel == &cfg_nil_panel_node) { src_code_dst_panel = info->panel_w_any_src_code; } + if(src_code_dst_panel == &cfg_nil_panel_node) { src_code_dst_panel = info->biggest_empty_panel; } + if(src_code_dst_panel == &cfg_nil_panel_node) { src_code_dst_panel = info->biggest_panel; } } // rjf: choose panel for disassembly - RD_PanelNode *disasm_dst_panel = &rd_nil_panel_node; + CFG_PanelNode *disasm_dst_panel = &cfg_nil_panel_node; if(!did_disasm_snap && vaddr != 0) { - if(disasm_dst_panel == &rd_nil_panel_node) { disasm_dst_panel = info->panel_w_disasm; } - if(disasm_dst_panel == &rd_nil_panel_node) { disasm_dst_panel = info->biggest_empty_panel; } - if(disasm_dst_panel == &rd_nil_panel_node) { disasm_dst_panel = info->biggest_panel; } + if(disasm_dst_panel == &cfg_nil_panel_node) { disasm_dst_panel = info->panel_w_disasm; } + if(disasm_dst_panel == &cfg_nil_panel_node) { disasm_dst_panel = info->biggest_empty_panel; } + if(disasm_dst_panel == &cfg_nil_panel_node) { disasm_dst_panel = info->biggest_panel; } } // rjf: push task - if(src_code_dst_panel != &rd_nil_panel_node || disasm_dst_panel != &rd_nil_panel_node) + if(src_code_dst_panel != &cfg_nil_panel_node || disasm_dst_panel != &cfg_nil_panel_node) { FindCodeLocTask *t = push_array(scratch.arena, FindCodeLocTask, 1); SLLQueuePush(first_task, last_task, t); @@ -14447,8 +14247,8 @@ rd_frame(void) //- rjf: perform the find-code-location for each task for(FindCodeLocTask *t = first_task; t != 0; t = t->next) { - RD_PanelNode *src_code_dst_panel = t->src_code_dst_panel; - RD_PanelNode *disasm_dst_panel = t->disasm_dst_panel; + CFG_PanelNode *src_code_dst_panel = t->src_code_dst_panel; + CFG_PanelNode *disasm_dst_panel = t->disasm_dst_panel; // rjf: if disasm and source code match: // if disasm preferred, cancel source @@ -14457,20 +14257,20 @@ rd_frame(void) { if(rd_regs()->prefer_disasm) { - src_code_dst_panel = &rd_nil_panel_node; + src_code_dst_panel = &cfg_nil_panel_node; } else { - disasm_dst_panel = &rd_nil_panel_node; + disasm_dst_panel = &cfg_nil_panel_node; } } // rjf: if disasm is not preferred, and we have no disassembly view // open at all, cancel disasm, so that it doesn't open if the user // doesn't want it. - if(!rd_regs()->prefer_disasm && t->panel_w_disasm == &rd_nil_panel_node && file_path.size != 0) + if(!rd_regs()->prefer_disasm && t->panel_w_disasm == &cfg_nil_panel_node && file_path.size != 0) { - disasm_dst_panel = &rd_nil_panel_node; + disasm_dst_panel = &cfg_nil_panel_node; } // rjf: if disasm is not preferred, and we have no disassembly view @@ -14479,13 +14279,13 @@ rd_frame(void) if(!rd_regs()->prefer_disasm && t->view_w_disasm != &cfg_nil_node && cfg_node_child_from_string(t->view_w_disasm, str8_lit("selected")) == &cfg_nil_node && file_path.size != 0) { - disasm_dst_panel = &rd_nil_panel_node; + disasm_dst_panel = &cfg_nil_panel_node; } // rjf: snap to source code - if(file_path.size != 0 && src_code_dst_panel != &rd_nil_panel_node) + if(file_path.size != 0 && src_code_dst_panel != &cfg_nil_panel_node) { - RD_PanelNode *dst_panel = src_code_dst_panel; + CFG_PanelNode *dst_panel = src_code_dst_panel; // rjf: construct new view if needed CFG_Node *dst_tab = t->view_w_this_src_code; @@ -14501,7 +14301,7 @@ rd_frame(void) cfg_node_new_replace(rd_state->cfg, cfg_node_child_from_string_or_alloc(rd_state->cfg, dst_tab, str8_lit("mark_line")), str8_lit("1")); cfg_node_new_replace(rd_state->cfg, cfg_node_child_from_string_or_alloc(rd_state->cfg, dst_tab, str8_lit("mark_column")), str8_lit("1")); } - else if(dst_panel != &rd_nil_panel_node && dst_tab == &cfg_nil_node) + else if(dst_panel != &cfg_nil_panel_node && dst_tab == &cfg_nil_node) { dst_tab = cfg_node_new(rd_state->cfg, dst_panel->cfg, str8_lit("text")); CFG_Node *expr = cfg_node_new(rd_state->cfg, dst_tab, str8_lit("expression")); @@ -14512,16 +14312,16 @@ rd_frame(void) // rjf: determine if we need a contain or center RD_CmdKind cursor_snap_kind = RD_CmdKind_CenterCursor; - if(dst_panel != &rd_nil_panel_node && dst_tab == t->view_w_this_src_code && dst_panel->selected_tab == dst_tab) + if(dst_panel != &cfg_nil_panel_node && dst_tab == t->view_w_this_src_code && dst_panel->selected_tab == dst_tab) { cursor_snap_kind = RD_CmdKind_ContainCursor; } // rjf: move cursor & snap-to-cursor - if(dst_panel != &rd_nil_panel_node) RD_RegsScope(.window = t->window->id, - .panel = dst_panel->cfg->id, - .view = dst_tab->id, - .tab = dst_tab->id) + if(dst_panel != &cfg_nil_panel_node) RD_RegsScope(.window = t->window->id, + .panel = dst_panel->cfg->id, + .view = dst_tab->id, + .tab = dst_tab->id) { if(rd_regs()->force_focus) { @@ -14540,13 +14340,13 @@ rd_frame(void) } // rjf: snap to disasm - if(process != &ctrl_entity_nil && vaddr != 0 && disasm_dst_panel != &rd_nil_panel_node) + if(process != &ctrl_entity_nil && vaddr != 0 && disasm_dst_panel != &cfg_nil_panel_node) { - RD_PanelNode *dst_panel = disasm_dst_panel; + CFG_PanelNode *dst_panel = disasm_dst_panel; // rjf: construct new tab if needed CFG_Node *dst_tab = t->view_w_disasm; - if(dst_panel != &rd_nil_panel_node && t->view_w_disasm == &cfg_nil_node) + if(dst_panel != &cfg_nil_panel_node && t->view_w_disasm == &cfg_nil_node) { dst_tab = cfg_node_new(rd_state->cfg, dst_panel->cfg, str8_lit("disasm")); } @@ -14559,10 +14359,10 @@ rd_frame(void) } // rjf: move cursor & snap-to-cursor - if(dst_panel != &rd_nil_panel_node) RD_RegsScope(.window = t->window->id, - .panel = dst_panel->cfg->id, - .tab = dst_tab->id, - .view = dst_tab->id) + if(dst_panel != &cfg_nil_panel_node) RD_RegsScope(.window = t->window->id, + .panel = dst_panel->cfg->id, + .tab = dst_tab->id, + .view = dst_tab->id) { rd_cmd(RD_CmdKind_FocusTab); rd_cmd(RD_CmdKind_GoToAddress, .process = process->handle, .vaddr = vaddr); @@ -15114,10 +14914,10 @@ rd_frame(void) for(CFG_NodePtrNode *n = windows.first; n != 0; n = n->next) { CFG_Node *window = n->v; - RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, window); - for(RD_PanelNode *panel = panels.root; - panel != &rd_nil_panel_node; - panel = rd_panel_node_rec__depth_first_pre(panels.root, panel).next) + CFG_PanelTree panels = cfg_panel_tree_from_cfg(scratch.arena, window); + for(CFG_PanelNode *panel = panels.root; + panel != &cfg_nil_panel_node; + panel = cfg_panel_node_rec__depth_first_pre(panels.root, panel).next) { for(CFG_NodePtrNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { @@ -16244,8 +16044,8 @@ rd_frame(void) for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) { CFG_Node *window = cfg_node_from_id(ws->cfg_id); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, window); + for(CFG_PanelNode *p = panel_tree.root; p != &cfg_nil_panel_node; p = cfg_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { for(CFG_NodePtrNode *tab_n = p->tabs.first; tab_n != 0; tab_n = tab_n->next) { diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index e9e3b6ea..c18d216d 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -207,48 +207,6 @@ struct RD_Location String8 expr; }; -//////////////////////////////// -//~ rjf: Structured Panel Trees, Parsed From Config Trees - -typedef struct RD_PanelNode RD_PanelNode; -struct RD_PanelNode -{ - // rjf: links data - RD_PanelNode *first; - RD_PanelNode *last; - RD_PanelNode *next; - RD_PanelNode *prev; - RD_PanelNode *parent; - U64 child_count; - CFG_Node *cfg; - - // rjf: split data - Axis2 split_axis; - F32 pct_of_parent; - - // rjf: tab params - Side tab_side; - - // rjf: which tabs are attached - CFG_NodePtrList tabs; - CFG_Node *selected_tab; -}; - -typedef struct RD_PanelTree RD_PanelTree; -struct RD_PanelTree -{ - RD_PanelNode *root; - RD_PanelNode *focused; -}; - -typedef struct RD_PanelNodeRec RD_PanelNodeRec; -struct RD_PanelNodeRec -{ - RD_PanelNode *next; - S32 push_count; - S32 pop_count; -}; - //////////////////////////////// //~ rjf: Command Types @@ -554,18 +512,6 @@ struct RD_State read_only global RD_VocabInfo rd_nil_vocab_info = {0}; -read_only global RD_PanelNode rd_nil_panel_node = -{ - &rd_nil_panel_node, - &rd_nil_panel_node, - &rd_nil_panel_node, - &rd_nil_panel_node, - &rd_nil_panel_node, - 0, - &cfg_nil_node, - .selected_tab = &cfg_nil_node, -}; - read_only global RD_CmdKindInfo rd_nil_cmd_kind_info = {0}; RD_VIEW_UI_FUNCTION_DEF(null); @@ -626,14 +572,6 @@ internal RD_Regs *rd_get_hover_regs(void); //////////////////////////////// //~ rjf: Config Functions -internal RD_PanelTree rd_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root); -internal RD_PanelNodeRec rd_panel_node_rec__depth_first(RD_PanelNode *root, RD_PanelNode *panel, U64 sib_off, U64 child_off); -#define rd_panel_node_rec__depth_first_pre(root, p) rd_panel_node_rec__depth_first((root), (p), OffsetOf(RD_PanelNode, next), OffsetOf(RD_PanelNode, first)) -#define rd_panel_node_rec__depth_first_pre_rev(root, p) rd_panel_node_rec__depth_first((root), (p), OffsetOf(RD_PanelNode, prev), OffsetOf(RD_PanelNode, last)) -internal RD_PanelNode *rd_panel_node_from_tree_cfg(RD_PanelNode *root, CFG_Node *cfg); -internal Rng2F32 rd_target_rect_from_panel_node_child(Rng2F32 parent_rect, RD_PanelNode *parent, RD_PanelNode *panel); -internal Rng2F32 rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNode *panel); - internal B32 rd_cfg_is_project_filtered(CFG_Node *cfg); internal Vec4F32 rd_hsva_from_cfg(CFG_Node *cfg); diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index c0432068..956241f1 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -582,7 +582,7 @@ entry_point(CmdLine *cmd_line) if(dst_ws->cfg_id != rd_regs()->window) { Temp scratch = scratch_begin(0, 0); - RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(dst_ws->cfg_id)); + CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(dst_ws->cfg_id)); rd_regs()->window = dst_ws->cfg_id; rd_regs()->panel = panel_tree.focused->cfg->id; rd_regs()->tab = panel_tree.focused->selected_tab->id; From 52680a81feb0594b44f953c85150e84b44a5a4ae Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 16 Oct 2025 15:57:43 -0700 Subject: [PATCH 131/133] require data field members when looking for links w/ list lens; config node ptr lists need dll --- src/config/config_core.c | 4 ++-- src/eval/eval_types.c | 4 ++++ src/mule/mule_main.cpp | 8 ++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/config/config_core.c b/src/config/config_core.c index e41f8ed1..65ad565e 100644 --- a/src/config/config_core.c +++ b/src/config/config_core.c @@ -31,7 +31,7 @@ internal void cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node) { CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1); - SLLQueuePush(list->first, list->last, n); + DLLPushBack(list->first, list->last, n); list->count += 1; n->v = node; } @@ -40,7 +40,7 @@ internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node) { CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1); - SLLQueuePushFront(list->first, list->last, n); + DLLPushFront(list->first, list->last, n); list->count += 1; n->v = node; } diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 1d29a8d9..f509145b 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -2744,6 +2744,10 @@ E_TYPE_IREXT_FUNCTION_DEF(list) { for EachIndex(idx, node_type->count) { + if(node_type->members[idx].kind != E_MemberKind_DataField) + { + continue; + } E_TypeKey member_type_key = node_type->members[idx].type_key; E_TypeKey member_type_key_undecorated = e_type_key_unwrap(member_type_key, E_TypeUnwrapFlag_AllDecorative); E_TypeKey member_ptee_type_key = e_type_key_unwrap(member_type_key_undecorated, E_TypeUnwrapFlag_All); diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index 28bb2355..e0383f61 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #if !_WIN32 # define RADDBG_MARKUP_STUBS @@ -663,6 +664,13 @@ type_coverage_eval_tests(void) int_vector.push_back(6); int_vector.push_back(7); + std::unordered_map people = + { + {"Peter", 1}, + {"Oliver", 2}, + {"Jack", 3}, + }; + std::vector *pint_vector = &int_vector; std::vector &rint_vector = int_vector; From a96c822440e23bdf177eb18ce1ef69612f3f2555 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 17 Oct 2025 07:37:36 -0700 Subject: [PATCH 132/133] use process handles in list evaluations rather than spaces - we will need to upgrade this once eval has been upgraded --- src/eval/eval_types.c | 28 ++++++++++++++++++++++------ src/raddbg/generated/raddbg.meta.c | 3 ++- src/raddbg/generated/raddbg.meta.h | 2 +- src/raddbg/raddbg.mdesk | 12 ++++++++++++ 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index f509145b..93f426f9 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -2579,14 +2579,15 @@ e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U Temp scratch = scratch_begin(0, 0); //- rjf: unpack key - E_Space space = {0}; + // TODO(rjf): this needs to take any `E_Space`, once eval has been upgraded. + CTRL_Handle process = {0}; U64 base_off = 0; U64 member_element_off = 0; U64 member_size = 0; E_SpaceRWFunction *space_read = 0; { U64 key_read_off = 0; - key_read_off += str8_deserial_read_struct(key, key_read_off, &space); + key_read_off += str8_deserial_read_struct(key, key_read_off, &process); key_read_off += str8_deserial_read_struct(key, key_read_off, &base_off); key_read_off += str8_deserial_read_struct(key, key_read_off, &member_element_off); key_read_off += str8_deserial_read_struct(key, key_read_off, &member_size); @@ -2611,6 +2612,7 @@ e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U OffsetChunk *first_chunk = 0; OffsetChunk *last_chunk = 0; U64 total_count = 0; + B32 retry = 0; { U64 hit_slots_count = 4096; HitOffsetNode **hit_slots = push_array(scratch.arena, HitOffsetNode *, hit_slots_count); @@ -2652,18 +2654,30 @@ e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U total_count += 1; //- rjf: read next offset, advance - if(!space_read(space, &next_off, r1u64(off + member_element_off, off + member_element_off + member_size))) + B32 read_stale = 0; + B32 read_good = ctrl_process_memory_read(process, r1u64(off + member_element_off, off + member_size), &read_stale, &next_off, 0); + if(read_stale) + { + retry = 1; + } + if(!read_good) { break; } } } + //- rjf: retry + if(retry) + { + retry_out[0] = 1; + } + //- rjf: flatten Arena *arena = 0; U64 node_offs_count = 0; U64 *node_offs = 0; - if(total_count != 0) + if(!retry && total_count != 0) { arena = arena_alloc(); node_offs_count = total_count; @@ -2782,7 +2796,7 @@ E_TYPE_IREXT_FUNCTION_DEF(list) #pragma pack(push, 1) struct { - E_Space space; + CTRL_Handle process; U64 base_off; U64 member_element_off; U64 member_size; @@ -2790,7 +2804,9 @@ E_TYPE_IREXT_FUNCTION_DEF(list) } key_data = { - base_off_interpret.space, + // TODO(rjf): we cannot use `rd_` here - only doing this because the base eval layer does not + // support what we need yet... + rd_ctrl_entity_from_eval_space(base_off_interpret.space)->handle, base_off_interpret.value.u64, next_link_member.off, e_type_byte_size_from_key(next_link_member.type_key), diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 80bbe9b8..19bb9e17 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -416,7 +416,7 @@ RD_VocabInfo rd_vocab_info_table[352] = {str8_lit_comp("geo3d"), str8_lit_comp(""), str8_lit_comp("Geometry (3D)"), str8_lit_comp(""), RD_IconKind_Cube}, }; -RD_NameSchemaInfo rd_name_schema_info_table[24] = +RD_NameSchemaInfo rd_name_schema_info_table[25] = { {str8_lit_comp("user"), str8_lit_comp("@expand_commands(edit_user_theme) x:\n{\n //- rjf: animations\n @display_name('Animations') @description(\"Enables animations.\")\n @default(1) 'animations': bool,\n @display_name('Scrolling Animations') @description(\"Enables scrolling animations.\")\n @expand_if(\"$.animations\") @default(1) 'scrolling_animations': bool,\n @display_name('Tooltip Animations') @description(\"Enables tooltip animations.\")\n @expand_if(\"$.animations\") @default(1) 'tooltip_animations': bool,\n @display_name('Menu Animations') @description(\"Enables menu animations.\")\n @expand_if(\"$.animations\") @default(1) 'menu_animations': bool,\n\n //- rjf: fonts\n @display_name('UI Font') @description(\"The name of, or path to, the font used when displaying non-code UI elements.\")\n @default('') 'main_font': string,\n @display_name('Code Font') @description(\"The name of, or path to, the font used when displaying code.\")\n @default('') 'code_font': string,\n\n //- rjf: theme\n @default(\"Default (Dark)\") @display_name('User Theme')\n @description(\"The user's theme, which describes all colors used throughout the UI.\")\n 'theme': string,\n @no_expand @display_name('User Theme')\n 'theme_colors': query,\n\n //- rjf: autocompletion\n @display_name('Autocompletion Lister') @description(\"Enables the autocompletion lister while typing expressions.\") @default(1)\n 'autocompletion_lister': bool,\n @display_name('View Call Argument Helper') @description(\"Enables the view call argument helper, which shows view arguments and documentation, while typing expressions.\") @default(1)\n 'view_call_argument_helper': bool,\n\n //- rjf: scope decorations\n @default(1) @display_name('Cursor Scope Lines') @description(\"Controls whether or not scopes containing the cursor in text views are drawn.\")\n 'cursor_scope_lines': bool,\n\n //- rjf: thread & breakpoint decorations\n @default(1) @display_name('Thread Lines') @description(\"Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.\")\n 'thread_lines': bool,\n @default(1) @display_name('Thread Glow') @description(\"Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.\")\n 'thread_glow': bool,\n @default(1) @display_name('Breakpoint Lines') @description(\"Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.\")\n 'breakpoint_lines': bool,\n @default(1) @display_name('Breakpoint Glow') @description(\"Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.\")\n 'breakpoint_glow': bool,\n\n //- rjf: occluding background settings\n @default(0) @display_name('Opaque Backgrounds') @description(\"Controls whether or not all floating background colors are forced to be fully opaque.\")\n 'opaque_backgrounds': bool,\n @default(1) @display_name('Background Blur') @description(\"Controls whether or not occluded regions behind floating elements are blurred.\")\n 'background_blur': bool,\n\n //- rjf: appearance settings\n @default(1) @display_name('Drop Shadows') @description(\"Controls whether or not drop shadows are drawn.\")\n 'drop_shadows': bool,\n @default(1.f) @display_name('Rounded Corner Amount') @description(\"Controls the degree to which UI corners are rounded.\")\n 'rounded_corner_amount': @range[0, 1] f32,\n\n //- rjf: code formatting settings\n @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: windows style menu bar\n @default(1) @display_name('Focus Menu Bar With Alt') @description(\"Mimics standard Windows behavior of focusing the menu bar using the Alt key.\")\n 'focus_menu_bar_with_alt': bool,\n\n //- rjf: native filesystem dialogues\n @default(0) @display_name('Use Native File System Dialog') @description(\"Uses the operating system's file system dialog box, rather than the debugger's built-in UI.\")\n 'use_native_file_system_dialog': bool,\n}\n")}, {str8_lit_comp("project"), str8_lit_comp("@expand_commands(edit_project_theme) x:\n{\n @default(2) @display_name('Project Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: visualizers\n @display_name('Use Default C++ STL Type Visualizers') @description(\"Enables the built-in type views for C++ STL types.\")\n @default(1) use_default_stl_type_views: bool,\n @display_name('Use Default Unreal Engine Type Visualizers') @description(\"Enables the built-in type views for Unreal Engine types.\")\n @default(1) use_default_ue_type_views: bool,\n\n //- rjf: theme\n @default(\"None\") @display_name('Project Theme') @description(\"The project's theme, which describes all colors used throughout the UI, and can override the user's theme.\")\n 'theme': string,\n @no_expand @display_name('Project Theme') @description(\"The project's theme, which describes all colors used throughout the UI, and can override the user's theme.\")\n 'theme_colors': query,\n\n //- rjf: exception settings\n @default(1) @display_name(\"Break On Win32 Control-C Exceptions\") @description(\"Code: 0x40010005\")\n win32_ctrl_c: bool;\n @default(1) @display_name(\"Break On Win32 Control-Break Exceptions\") @description(\"Code: 0x40010008\")\n win32_ctrl_break: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Originate Error Exceptions\") @description(\"Code: 0x40080201\")\n win32_win_rt_originate_error: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Transform Error Exceptions\") @description(\"Code: 0x40080202\")\n win32_win_rt_transform_error: bool;\n @default(0) @display_name(\"Break On Win32 RPC Call Cancelled Exceptions\") @description(\"Code: 0x0000071a\")\n win32_rpc_call_cancelled: bool;\n @default(0) @display_name(\"Break On Win32 Data Type Misalignment Exceptions\") @description(\"Code: 0x80000002\")\n win32_datatype_misalignment: bool;\n @default(1) @display_name(\"Break On Win32 Access Violation Exceptions\") @description(\"Code: 0xc0000005\")\n win32_access_violation: bool;\n @default(0) @display_name(\"Break On Win32 In Page Error Exceptions\") @description(\"Code: 0xc0000006\")\n win32_in_page_error: bool;\n @default(1) @display_name(\"Break On Win32 Invalid Handle Specified Exceptions\") @description(\"Code: 0xc0000008\")\n win32_invalid_handle: bool;\n @default(0) @display_name(\"Break On Win32 Not Enough Quota Exceptions\") @description(\"Code: 0xc0000017\")\n win32_not_enough_quota: bool;\n @default(0) @display_name(\"Break On Win32 Illegal Instruction Exceptions\") @description(\"Code: 0xc000001d\")\n win32_illegal_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Cannot Continue From Exception Exceptions\") @description(\"Code: 0xc0000025\")\n win32_cannot_continue_exception: bool;\n @default(0) @display_name(\"Break On Win32 Invalid Exception Disposition Returned By Handler Exceptions\") @description(\"Code: 0xc0000026\")\n win32_invalid_exception_disposition: bool;\n @default(0) @display_name(\"Break On Win32 Array Bounds Exceeded Exceptions\") @description(\"Code: 0xc000008c\")\n win32_array_bounds_exceeded: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Denormal Operand Exceptions\") @description(\"Code: 0xc000008d\")\n win32_floating_point_denormal_operand: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Division By Zero Exceptions\") @description(\"Code: 0xc000008e\")\n win32_floating_point_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Inexact Result Exceptions\") @description(\"Code: 0xc000008f\")\n win32_floating_point_inexact_result: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Invalid Operation Exceptions\") @description(\"Code: 0xc0000090\")\n win32_floating_point_invalid_operation: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Overflow Exceptions\") @description(\"Code: 0xc0000091\")\n win32_floating_point_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Stack Check Exceptions\") @description(\"Code: 0xc0000092\")\n win32_floating_point_stack_check: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Underflow Exceptions\") @description(\"Code: 0xc0000093\")\n win32_floating_point_underflow: bool;\n @default(0) @display_name(\"Break On Win32 Integer Division By Zero Exceptions\") @description(\"Code: 0xc0000094\")\n win32_integer_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Integer Overflow Exceptions\") @description(\"Code: 0xc0000095\")\n win32_integer_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Privileged Instruction Exceptions\") @description(\"Code: 0xc0000096\")\n win32_privileged_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Stack Overflow Exceptions\") @description(\"Code: 0xc00000fd\")\n win32_stack_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Unable To Locate DLL Exceptions\") @description(\"Code: 0xc0000135\")\n win32_unable_to_locate_dll: bool;\n @default(0) @display_name(\"Break On Win32 Ordinal Not Found Exceptions\") @description(\"Code: 0xc0000138\")\n win32_ordinal_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Entry Point Not Found Exceptions\") @description(\"Code: 0xc0000139\")\n win32_entry_point_not_found: bool;\n @default(0) @display_name(\"Break On Win32 DLL Initialization Failed Exceptions\") @description(\"Code: 0xc0000142\")\n win32_dll_initialization_failed: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Faults Exceptions\") @description(\"Code: 0xc00002b4\")\n win32_floating_point_sse_multiple_faults: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Traps Exceptions\") @description(\"Code: 0xc00002b5\")\n win32_floating_point_sse_multiple_traps: bool;\n @default(1) @display_name(\"Break On Win32 Assertion Failed Exceptions\") @description(\"Code: 0xc0000420\")\n win32_assertion_failed: bool;\n @default(0) @display_name(\"Break On Win32 Module Not Found Exceptions\") @description(\"Code: 0xc06d007e\")\n win32_module_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Procedure Not Found Exceptions\") @description(\"Code: 0xc06d007f\")\n win32_procedure_not_found: bool;\n @default(1) @display_name(\"Break On Win32 Sanitizer Error Detected Exceptions\") @description(\"Code: 0xe073616e\")\n win32_sanitizer_error_detected: bool;\n @default(0) @display_name(\"Break On Win32 Sanitizer Raw Access Violation Exceptions\") @description(\"Code: 0xe0736171\")\n win32_sanitizer_raw_access_violation: bool;\n @default(1) @display_name(\"Break On Win32 DirectX Debug Layer Exceptions\") @description(\"Code: 0x0000087a\")\n win32_directx_debug_layer: bool;\n}\n")}, @@ -424,6 +424,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[24] = {str8_lit_comp("window"), str8_lit_comp("x:\n{\n //- rjf: text rasterization settings\n @default(1) @display_name('Smooth UI Text') @description(\"Controls whether or not UI text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_ui_text': bool,\n @default(1) @display_name('Hint UI Text') @description(\"Controls whether or not UI text is hinted, for better text readability at small sizes.\")\n 'hint_ui_text': bool,\n @default(0) @display_name('Smooth Code Text') @description(\"Controls whether or not code text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_code_text': bool,\n @default(1) @display_name('Hint Code Text') @description(\"Controls whether or not code text is hinted, for better text readability at small sizes.\")\n 'hint_code_text': bool,\n @default(11) @display_name('Window Font Size') @description(\"Controls the window's default font size. Does not apply to tabs with their own font size set.\")\n 'font_size': @range[6, 72] u64,\n\n //- rjf: size settings\n @default(3.f) @display_name('Window Row Height') @description(\"Controls the window's default row height, in multiples of the font size. Does not apply to tabs with their own row height set.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @default(3.f) @description(\"Controls the height of tabs, in multiples of the font size.\")\n 'tab_height': @range[1.75f, 5.f] f32,\n\n //- rjf: theme settings\n @default(1) @display_name('Use Project Theme') @description(\"Prefer using the project theme for this window, if any. If off, only the user's theme settings will be used.\")\n 'use_project_theme': bool,\n}\n")}, {str8_lit_comp("tab"), str8_lit_comp("@row_commands(@file copy_tab_full_path, @file show_file_in_explorer, duplicate_tab, close_tab)\nx:\n{\n @override @display_name('Tab Font Size') @description(\"Controls the tab's font size.\") @no_callee_helper\n 'font_size': @range[6, 72] u64,\n}\n")}, {str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @override @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': expr_string,\n @no_expand 'watches': query,\n}\n")}, +{str8_lit_comp("list"), str8_lit_comp("x:\n{\n @description(\"An expression describing the first node in the list.\")\n 'expression': expr_string,\n @order(0) @description(\"The name of the member which encodes the link to the next node.\")\n 'member_name': code_string,\n}\n")}, {str8_lit_comp("text"), str8_lit_comp("@inherit(tab) @expand_commands(@output clear_output) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(1) @display_name('Line Wrapping') @description(\"Splits textual lines into multiple visual lines, so that all text is within the visible area.\")\n 'line_wrapping': bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change': bool,\n @no_callee_helper @no_revert @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n}\n")}, {str8_lit_comp("disasm"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': expr_string,\n 'arch': code_string,\n 'syntax': code_string,\n 'size': expr_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @no_callee_helper @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n\n}\n")}, {str8_lit_comp("memory"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the base address of data which should be viewed as memory.\")\n 'expression': expr_string,\n @display_name(\"Address Range Size\") @description(\"The number of bytes of the viewed memory range.\")\n 'size': expr_string,\n @display_name(\"Cursor Address\") @description(\"The address of the cursor.\")\n 'cursor': expr_string,\n @display_name(\"Cursor Size\") @description(\"The size, in bytes, of the cursor.\")\n 'cursor_size': @range[1, 16] u64,\n @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n @default(1) @display_name(\"Track Mark To Cursor\") @description(\"Ensures that the mark always follows the cursor, if the cursor value is updated.\")\n 'track_mark_to_cursor': bool,\n}\n")}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index da4c5954..0f048756 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -592,7 +592,7 @@ C_LINKAGE_BEGIN extern String8 rd_tab_fast_path_view_name_table[24]; extern String8 rd_tab_fast_path_query_name_table[24]; extern RD_VocabInfo rd_vocab_info_table[352]; -extern RD_NameSchemaInfo rd_name_schema_info_table[24]; +extern RD_NameSchemaInfo rd_name_schema_info_table[25]; extern String8 rd_reg_slot_code_name_table[47]; extern Rng1U64 rd_reg_slot_range_table[47]; extern String8 rd_binding_version_remap_old_name_table[8]; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 86bad0d1..f084b96d 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -470,6 +470,18 @@ RD_VocabTable: } ``` } + { + list, + ``` + x: + { + @description("An expression describing the first node in the list.") + 'expression': expr_string, + @order(0) @description("The name of the member which encodes the link to the next node.") + 'member_name': code_string, + } + ``` + } { text, ``` From f5b94436366105a2b1be7b98090fde792133b37b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 17 Oct 2025 07:44:49 -0700 Subject: [PATCH 133/133] notes --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92924ad5..dfa120f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ - Reintroduced the `list` lens, which gathers all nodes in a linked list, and visualizes them as a flat list of pointers (the same as how an array of pointers is visualized). +- Fixed a crash when closing empty Geometry 3D views. (#652, #657) +- Fixed the debugger not visualizing `enum` types when evaluated through a + bitfield type. (#655) +- Fixed the PDB -> RDI conversion not correctly generating location information + for function parameters, when the EXE/PDB were built to include support for + Edit and Continue (`-ZI` switch). (#656) + +## Binary Utility Changes + +- Fixed a crash when using the `--compress` option, when generating RDI files. # v0.9.22-alpha