diff --git a/CHANGELOG.md b/CHANGELOG.md index dfa120f5..562dc77c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,35 @@ +# v0.9.24-alpha + +## Debugger Changes + +- Added the ability for the debugger to load, use, and evaluate using debug + info, even when not actively debugging. The debugger will now keep a process' + debug info loaded, even after the process ends. It stores the set of loaded + debug info files in the project configuration file, meaning it will also + automatically load the same debug info across many runs. Debug info can also + be loaded manually (without ever launching a process) with the + `Load Debug Info` command. There is also a new tab, `Debug Info`, which allows + viewing and managing the set of loaded debug info files. +- Improved the debugger's behavior when used as a drag & drop target, to allow + for debug info loading as an option (when relevant), and to better handle the + case where many files (potentially of different types) are dropped together. +- Improved debug info searching performance and reponsiveness in large projects. +- Fixed some crashes and incorrect results with the new `list` view. +- Fixed some cases where RDIs did not contain some basic types from their + originating PDBs. +- Allowed `.` and `->` operators to be used with array types. +- Fixed the debugger's treatment of quoted command line arguments when building + targets. In previous versions, calling `raddbg main.exe "foo bar baz"` would + create a target `main.exe` with arguments `foo bar baz` (dropping the quotes). + This is now fixed, such that the target's arguments string will also contain + the quotes, and pass them to the target when launched. +- Fixed the debugger not correctly responding (through font and UI scale) to DPI + changes. +- Fixed the debugger incorrectly generating conflicting source line info records + in PDB -> RDI conversion, which in some scenarios was preventing source line + maps from working (leading to breakpoint resolution failing). +- Other small fixes, improvements, and tweaks. + # v0.9.23-alpha ## Debugger Changes diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 16f7a221..679a50fe 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -18,6 +18,9 @@ ac_init(void) ac_shared->req_batches[idx].mutex = mutex_alloc(); ac_shared->req_batches[idx].arena = arena_alloc(); } + ac_shared->cancel_thread = thread_launch(ac_cancel_thread_entry_point, 0); + ac_shared->cancel_thread_mutex = mutex_alloc(); + mutex_take(ac_shared->cancel_thread_mutex); } //////////////////////////////// @@ -138,9 +141,9 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 node->key = str8_copy(stripe->arena, key); node->working_count = 1; node->evict_threshold_us = params->evict_threshold_us; - node->access_pt.last_time_touched_us = os_now_microseconds(); - node->access_pt.last_update_idx_touched = update_tick_idx(); } + node->access_pt.last_time_touched_us = os_now_microseconds(); + node->access_pt.last_update_idx_touched = update_tick_idx(); // rjf: request if(need_request) @@ -161,8 +164,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.cancel_signal = &node->cancelled; 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); @@ -210,6 +213,14 @@ ac_async_tick(void) { Temp scratch = scratch_begin(0, 0); + ////////////////////////////// + //- rjf: enable cancellation scanning + // + if(lane_idx() == 0) + { + mutex_drop(ac_shared->cancel_thread_mutex); + } + ////////////////////////////// //- rjf: do eviction pass across all caches // @@ -574,5 +585,70 @@ ac_async_tick(void) } lane_sync(); + ////////////////////////////// + //- rjf: disable cancellation scanning + // + if(lane_idx() == 0) + { + mutex_take(ac_shared->cancel_thread_mutex); + } scratch_end(scratch); } + +//////////////////////////////// +//~ rjf: Cancel Thread + +internal void +ac_cancel_thread_entry_point(void *p) +{ + for(;;) + { + os_sleep_milliseconds(50); + MutexScope(ac_shared->cancel_thread_mutex) + { + for EachIndex(cache_slot_idx, ac_shared->cache_slots_count) + { + Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); + RWMutexScope(cache_stripe->rw_mutex, 0) + { + for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx]) + { + Rng1U64 slot_range = lane_range(cache->slots_count); + for EachInRange(slot_idx, slot_range) + { + AC_Slot *slot = &cache->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + { + B32 slot_has_work = 0; + RWMutexScope(stripe->rw_mutex, write_mode) + { + for(AC_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) > 0) + { + slot_has_work = 1; + if(!write_mode) + { + break; + } + else + { + n->cancelled = 1; + } + } + } + } + if(!slot_has_work) + { + break; + } + } + } + } + } + } + } + } +} diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 1f5bf00c..3e433e5f 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -37,7 +37,6 @@ struct AC_ArtifactParams U64 gen; U64 evict_threshold_us; B32 *stale_out; - B32 *cancel_signal; AC_Flags flags; }; @@ -127,6 +126,10 @@ struct AC_Shared // rjf: requests AC_RequestBatch req_batches[2]; // 0: high priority, 1: low priority + + // rjf: cancel thread + Thread cancel_thread; + Mutex cancel_thread_mutex; }; //////////////////////////////// @@ -139,11 +142,6 @@ global AC_Shared *ac_shared = 0; internal void ac_init(void); -//////////////////////////////// -//~ rjf: Helpers - -internal B32 ac_cancelled(void); - //////////////////////////////// //~ rjf: Cache Lookups @@ -155,4 +153,9 @@ internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_Artif internal void ac_async_tick(void); +//////////////////////////////// +//~ rjf: Cancel Thread + +internal void ac_cancel_thread_entry_point(void *p); + #endif // ARTIFACT_CACHE_H diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h index 4065b166..82af7918 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 23 +# define BUILD_VERSION_PATCH 24 #endif #define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 97fd4e2d..451669bc 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -108,6 +108,11 @@ main_thread_base_entry_point(int arguments_count, char **arguments) U64 num_async_threads = os_get_system_info()->logical_processor_count; U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads); num_async_threads -= num_main_threads_clamped; + String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count")); + if(num_async_threads_string.size != 0) + { + try_u64_from_str8_c_rules(num_async_threads_string, &num_async_threads); + } num_async_threads = Max(1, num_async_threads); Barrier barrier = barrier_alloc(num_async_threads); LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads); @@ -189,7 +194,7 @@ async_thread_entry_point(void *params) { if(!ins_atomic_u32_eval(&async_loop_again)) { - MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); + MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+1000000); } ins_atomic_u32_eval_assign(&async_loop_again, 0); ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0); diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 84e3f448..7c39715d 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -85,25 +85,40 @@ correct_slash_from_char(U8 c) internal U64 cstring8_length(U8 *c) { - U8 *p = c; - for (;*p != 0; p += 1); - return (p - c); + U64 length = 0; + if(c) + { + U8 *p = c; + for (;*p != 0; p += 1); + length = (U64)(p - c); + } + return length; } internal U64 cstring16_length(U16 *c) { - U16 *p = c; - for (;*p != 0; p += 1); - return (p - c); + U64 length = 0; + if(c) + { + U16 *p = c; + for (;*p != 0; p += 1); + length = (U64)(p - c); + } + return length; } internal U64 cstring32_length(U32 *c) { - U32 *p = c; - for (;*p != 0; p += 1); - return (p - c); + U64 length = 0; + if(c) + { + U32 *p = c; + for (;*p != 0; p += 1); + length = (U64)(p - c); + } + return length; } //////////////////////////////// diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index 5b1726be..494d1804 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -120,7 +120,7 @@ internal void access_touch(Access *access, AccessPt *pt, CondVar cv); //- rjf: access points internal B32 access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params); -#define access_pt_is_expired(pt, ...) access_pt_is_expired_((pt), &(AccessPtExpireParams){.time = 2000000, .update_idxs = 10, __VA_ARGS__}) +#define access_pt_is_expired(pt, ...) access_pt_is_expired_((pt), &(AccessPtExpireParams){.time = 2000000, .update_idxs = 2, __VA_ARGS__}) //- rjf: progress counters #define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr)) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index d7627784..e343fa14 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3189,7 +3189,7 @@ ctrl_thread__entry_point(void *p) 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 = di_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp); - di_close(old_dbgi_key); + di_close(old_dbgi_key, 0); 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)); @@ -4112,7 +4112,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt->entity = module_handle; out_evt->string = module_path; DI_Key dbgi_key = ctrl_dbgi_key_from_module(module_ent); - di_close(dbgi_key); + di_close(dbgi_key, 0); }break; case DMN_EventKind_DebugString: { @@ -4274,15 +4274,19 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); ////////////////////////////// - //- rjf: gather evaluation modules + //- rjf: gather evaluation debug infos & modules // U64 eval_modules_count = Max(1, entity_ctx->entity_kind_counts[CTRL_EntityKind_Module]); E_Module *eval_modules = push_array(arena, E_Module, eval_modules_count); E_Module *eval_modules_primary = &eval_modules[0]; - eval_modules_primary->rdi = &rdi_parsed_nil; eval_modules_primary->vaddr_range = r1u64(0, max_U64); + U64 eval_dbg_infos_count = Max(1, entity_ctx->entity_kind_counts[CTRL_EntityKind_Module]); + E_DbgInfo *eval_dbg_infos = push_array(arena, E_DbgInfo, eval_dbg_infos_count); + E_DbgInfo *eval_dbg_infos_primary = &eval_dbg_infos[0]; + MemoryCopyStruct(eval_dbg_infos_primary, &e_dbg_info_nil); { U64 eval_module_idx = 0; + U64 eval_dbg_info_idx = 0; for(CTRL_Entity *machine = entity_ctx->root->first; machine != &ctrl_entity_nil; machine = machine->next) @@ -4392,10 +4396,18 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C rdi = di_rdi_from_key(scope->access, dbgi_key, 1, max_U64); } + //- rjf: fill debug info + eval_dbg_infos[eval_dbg_info_idx].dbgi_key = dbgi_key; + eval_dbg_infos[eval_dbg_info_idx].rdi = rdi; + if(mod == module) + { + eval_dbg_infos_primary = &eval_dbg_infos[eval_dbg_info_idx]; + } + eval_dbg_info_idx += 1; + //- 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].dbg_info_num= (U32)eval_dbg_info_idx; eval_modules[eval_module_idx].vaddr_range = mod->vaddr_range; eval_modules[eval_module_idx].space = e_space_make(CTRL_EvalSpaceKind_Entity); eval_modules[eval_module_idx].space.u64_0 = (U64)process; @@ -4427,6 +4439,11 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C ctx->thread_reg_space = e_space_make(CTRL_EvalSpaceKind_Entity); ctx->thread_reg_space.u64_0 = (U64)thread; + //- rjf: fill debug infos + ctx->dbg_infos = eval_dbg_infos; + ctx->dbg_infos_count = eval_dbg_infos_count; + ctx->primary_dbg_info = eval_dbg_infos_primary; + //- rjf: fill modules ctx->modules = eval_modules; ctx->modules_count = eval_modules_count; @@ -4445,8 +4462,8 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C E_IRCtx *ctx = &scope->ir_ctx; ctx->regs_map = ctrl_string2reg_from_arch(arch); ctx->reg_alias_map = ctrl_string2alias_from_arch(arch); - ctx->locals_map = e_push_locals_map_from_rdi_voff(arena, eval_modules_primary->rdi, thread_rip_voff); - ctx->member_map = e_push_member_map_from_rdi_voff(arena, eval_modules_primary->rdi, thread_rip_voff); + ctx->locals_map = e_push_locals_map_from_rdi_voff(arena, eval_dbg_infos_primary->rdi, thread_rip_voff); + ctx->member_map = e_push_member_map_from_rdi_voff(arena, eval_dbg_infos_primary->rdi, thread_rip_voff); ctx->macro_map = push_array(arena, E_String2ExprMap, 1); ctx->macro_map[0] = e_string2expr_map_make(arena, 512); ctx->auto_hook_map = push_array(arena, E_AutoHookMap, 1); @@ -4469,7 +4486,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C // TODO(rjf): need to compute this out here somehow... ctx->frame_base[0] = ; ctx->tls_base = push_array(arena, U64, 1); } - e_select_interpret_ctx(&scope->interpret_ctx, eval_modules_primary->rdi, thread_rip_voff); + e_select_interpret_ctx(&scope->interpret_ctx, eval_dbg_infos_primary->rdi, thread_rip_voff); ProfEnd(); return scope; @@ -6485,6 +6502,7 @@ ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, //- rjf: compute call stack CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, thread_handle); B32 good = 1; + B32 retry = 0; Arena *arena = 0; CTRL_CallStack *call_stack = 0; if(thread != &ctrl_entity_nil) @@ -6507,12 +6525,17 @@ ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, good = 1; call_stack[0] = ctrl_call_stack_from_unwind(arena, process, &unwind); } + if(unwind.flags & CTRL_UnwindFlag_Stale) + { + retry = 1; + } post_reg_gen = ctrl_reg_gen(); post_mem_gen = ctrl_mem_gen(); } if(pre_reg_gen != post_reg_gen || pre_mem_gen != post_mem_gen) { good = 0; + retry = 1; } if(!good) { @@ -6533,11 +6556,8 @@ ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, artifact.u64[1] = (U64)call_stack; } - //- rjf: retry on bad - if(!good) - { - retry_out[0] = 1; - } + //- rjf: mark retry + retry_out[0] = retry; scratch_end(scratch); } diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index 960d9a68..0d7587ca 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -1500,6 +1500,16 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P evt->code = event->u64_code; }break; + case CTRL_EventKind_NewModule: + { + D_EventNode *n = push_array(arena, D_EventNode, 1); + SLLQueuePush(result.first, result.last, n); + result.count += 1; + D_Event *evt = &n->v; + evt->kind = D_EventKind_ModuleLoad; + evt->module = event->entity; + }break; + //- rjf: debug strings case CTRL_EventKind_DebugString: diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index 769c7f6d..1104bd33 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -86,6 +86,7 @@ struct D_TrapNet typedef enum D_EventKind { D_EventKind_Null, + D_EventKind_ModuleLoad, D_EventKind_ProcessEnd, D_EventKind_Stop, D_EventKind_COUNT @@ -107,6 +108,7 @@ struct D_Event { D_EventKind kind; D_EventCause cause; + CTRL_Handle module; CTRL_Handle thread; U64 vaddr; U64 code; diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 994fcb39..5a4cd680 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -313,8 +313,8 @@ di_open(DI_Key key) } internal void -di_close(DI_Key key) -{ +di_close(DI_Key key, B32 force_closed) +{ //- rjf: unpack key U64 hash = u64_hash_from_str8(str8_struct(&key)); U64 slot_idx = hash%di_shared->slots_count; @@ -340,8 +340,15 @@ di_close(DI_Key key) } } if(node) - { - node->refcount -= 1; + { + if(force_closed) + { + node->refcount = 0; + } + else + { + node->refcount -= 1; + } if(node->refcount == 0) { for(;;) @@ -377,7 +384,7 @@ di_close(DI_Key key) { arena_release(arena); } - } + } } //////////////////////////////// @@ -670,12 +677,12 @@ di_async_tick(void) } } - //- rjf: analyze O.G. debug info + //- 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); + 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 && @@ -685,11 +692,12 @@ di_async_tick(void) } os_file_close(file); } - U64 og_size = t->og_size; + U64 og_size = t->og_size; B32 og_is_rdi = t->og_is_rdi; + B32 og_is_good = (og_size > 0); //- rjf: compute key's RDI path - String8 rdi_path = {0}; + String8 rdi_path = {0}; { if(og_is_rdi) { @@ -754,8 +762,31 @@ di_async_tick(void) threads_available = (max_threads >= needed_threads); } + //- rjf: if this conversion will overwrite an RDI we already have in cache, + // then we need to evict the old one from the cache. + B32 ready_to_launch_conversion = (threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI_LoadTaskStatus_Active); + if(ready_to_launch_conversion) + { + U64 path2key_hash = u64_hash_from_str8(og_path); + U64 path2key_slot_idx = path2key_hash%di_shared->path2key_slots_count; + DI_KeySlot *path2key_slot = &di_shared->path2key_slots[path2key_slot_idx]; + Stripe *path2key_stripe = stripe_from_slot_idx(&di_shared->path2key_stripes, path2key_slot_idx); + RWMutexScope(path2key_stripe->rw_mutex, 0) + { + // NOTE(rjf): we need to iterate from last -> first, since we want to evict the + // most recent key. + for(DI_KeyPathNode *n = path2key_slot->last; n != 0; n = n->prev) + { + if(str8_match(n->path, og_path, 0) && !di_key_match(key, n->key)) + { + di_close(n->key, 1); + } + } + } + } + //- rjf: launch conversion processes - if(threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI_LoadTaskStatus_Active) + if(og_is_good && ready_to_launch_conversion) { B32 should_compress = 0; OS_ProcessLaunchParams params = {0}; @@ -818,7 +849,13 @@ di_async_tick(void) di_shared->conversion_thread_count -= t->thread_count; } } - } + } + + //- rjf: ready to launch, but bad O.G. file -> just immediately mark as done + if(!og_is_good && ready_to_launch_conversion) + { + t->status = DI_LoadTaskStatus_Done; + } //- 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 @@ -960,8 +997,11 @@ di_async_tick(void) 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); + node->working_count -= 1; + if(node->rdi.raw_data_size != 0) + { + ins_atomic_u64_inc_eval(&di_shared->load_gen); + } ins_atomic_u64_inc_eval(&di_shared->load_count); } else @@ -1142,9 +1182,10 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * Rng1U64 range = lane_range(element_count); for EachInRange(idx, range) { - //- rjf: every so often, check if we need to cancel, and cancel + //- rjf: every so often, check if we need to cancel, and cancel + if(idx%10000 == 0 && !!ins_atomic_u32_eval(cancel_signal)) { - // TODO(rjf) + break; } //- rjf: get element, map to string; if empty, continue to next element @@ -1244,7 +1285,15 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * } } lane_sync(); - + + //- rjf: decide if we cancelled + B32 cancelled = 0; + if(lane_idx() == 0 && !!ins_atomic_u32_eval(cancel_signal)) + { + cancelled = 1; + } + lane_sync_u64(&cancelled, 0); + //- rjf: produce sort records typedef struct SortRecord SortRecord; struct SortRecord @@ -1255,15 +1304,15 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * U64 sort_records_count = all_items->total_count; SortRecord *sort_records = 0; SortRecord *sort_records__swap = 0; - ProfScope("produce sort records") + if(!cancelled) ProfScope("produce sort records") { if(lane_idx() == 0) { - sort_records = push_array(scratch.arena, SortRecord, sort_records_count); + sort_records = push_array_no_zero(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); + sort_records__swap = push_array_no_zero(scratch.arena, SortRecord, sort_records_count); } lane_sync_u64(&sort_records, 0); lane_sync_u64(&sort_records__swap, lane_from_task_idx(1)); @@ -1283,7 +1332,7 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * lane_sync(); //- rjf: sort records - ProfScope("sort records") + if(!cancelled) ProfScope("sort records") { //- rjf: set up common data U64 bits_per_digit = 8; @@ -1382,12 +1431,12 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * //- rjf: produce final array DI_SearchItemArray items = {0}; - ProfScope("produce final array") + if(!cancelled) ProfScope("produce final array") { if(lane_idx() == 0) { items.count = all_items->total_count; - items.v = push_array(arena, DI_SearchItem, items.count); + items.v = push_array_no_zero(arena, DI_SearchItem, items.count); } lane_sync_u64(&items.count, 0); lane_sync_u64(&items.v, 0); @@ -1401,11 +1450,20 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * } lane_sync(); - //- rjf: bundle as artifact - artifact.u64[0] = (U64)arenas; - artifact.u64[1] = arenas_count; - artifact.u64[2] = (U64)items.v; - artifact.u64[3] = items.count; + //- rjf: bundle as artifact + if(!cancelled) + { + artifact.u64[0] = (U64)arenas; + artifact.u64[1] = arenas_count; + artifact.u64[2] = (U64)items.v; + artifact.u64[3] = items.count; + } + + //- rjf: release results on cancel + else + { + arena_release(arena); + } } scratch_end(scratch); access_close(access); @@ -1446,7 +1504,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, .stale_out = stale_out); + 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, .evict_threshold_us = 100000, .stale_out = stale_out); // rjf: unpack artifact result.v = (DI_SearchItem *)artifact.u64[2]; @@ -1481,73 +1539,87 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *g //- rjf: get all loaded keys DI_KeyArray dbgi_keys = di_push_all_loaded_keys(scratch.arena); - + + //- rjf: take cancellation signal + B32 cancelled = 0; + if(lane_idx() == 0) + { + cancelled = ins_atomic_u32_eval(cancel_signal); + } + lane_sync_u64(&cancelled, 0); + //- 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[] = + DI_Match *lane_matches = 0; + if(!cancelled) + { + if(lane_idx() == 0) { - 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[] = + lane_matches = push_array(scratch.arena, DI_Match, lane_count()); + } + lane_sync_u64(&lane_matches, 0); { - 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(); + read_only local_persist RDI_NameMapKind name_map_kinds[] = { - 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_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(); { - 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) + 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) { - 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]; + 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); } - access_close(access); - } - } - lane_sync(); - + } + } + lane_sync(); + //- rjf: pick match - DI_Match match = {0}; - for EachIndex(idx, lane_count()) - { - if(lane_matches[idx].idx != 0) + DI_Match match = {0}; + if(lane_matches != 0) + { + for EachIndex(idx, lane_count()) { - match = lane_matches[idx]; - if(di_key_match(di_key_zero(), preferred_key) || di_key_match(match.key, preferred_key)) - { - break; - } + if(lane_matches[idx].idx != 0) + { + match = lane_matches[idx]; + if(di_key_match(di_key_zero(), preferred_key) || di_key_match(match.key, preferred_key)) + { + break; + } + } } - } - + } + //- rjf: package as artifact AC_Artifact artifact = {0}; { @@ -1579,7 +1651,7 @@ di_match_from_string(String8 string, U64 index, DI_Key preferred_dbgi_key, U64 e 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()); + 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(), .evict_threshold_us = wide ? 20000000 : 10000000); 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 8280a8a0..f2ff52f5 100644 --- a/src/dbg_info/dbg_info.h +++ b/src/dbg_info/dbg_info.h @@ -323,7 +323,7 @@ internal DI_Key di_key_from_path_timestamp(String8 path, U64 min_timestamp); //~ rjf: Debug Info Opening / Closing internal void di_open(DI_Key key); -internal void di_close(DI_Key key); +internal void di_close(DI_Key key, B32 force_closed); //////////////////////////////// //~ rjf: Debug Info Lookups diff --git a/src/eval/eval_core.c b/src/eval/eval_core.c index ac1e174b..0adf8c3c 100644 --- a/src/eval/eval_core.c +++ b/src/eval/eval_core.c @@ -676,8 +676,10 @@ internal void e_select_base_ctx(E_BaseCtx *ctx) { //- rjf: select base context - if(ctx->modules == 0) { ctx->modules = &e_module_nil; } - if(ctx->primary_module == 0) { ctx->primary_module = &e_module_nil; } + if(ctx->modules == 0) { ctx->modules = &e_module_nil; } + if(ctx->primary_module == 0) { ctx->primary_module = &e_module_nil; } + if(ctx->dbg_infos == 0) { ctx->dbg_infos = &e_dbg_info_nil; } + if(ctx->primary_dbg_info == 0) { ctx->primary_dbg_info = &e_dbg_info_nil; } e_base_ctx = ctx; //- rjf: reset the evaluation cache @@ -718,7 +720,7 @@ e_select_base_ctx(E_BaseCtx *ctx) .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(folder), .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(folder), }); - e_cache->thread_ip_procedure = rdi_procedure_from_voff(e_base_ctx->primary_module->rdi, e_base_ctx->thread_ip_voff); + e_cache->thread_ip_procedure = rdi_procedure_from_voff(e_base_ctx->primary_dbg_info->rdi, e_base_ctx->thread_ip_voff); e_cache->used_expr_map = push_array(e_cache->arena, E_UsedExprMap, 1); e_cache->used_expr_map->slots_count = 64; e_cache->used_expr_map->slots = push_array(e_cache->arena, E_UsedExprSlot, e_cache->used_expr_map->slots_count); @@ -744,6 +746,32 @@ e_select_ir_ctx(E_IRCtx *ctx) e_ir_ctx = ctx; } +//////////////////////////////// +//~ rjf: Context Accessors + +internal E_DbgInfo * +e_dbg_info_from_module(E_Module *module) +{ + E_DbgInfo *result = &e_dbg_info_nil; + if(0 < module->dbg_info_num && module->dbg_info_num <= e_base_ctx->dbg_infos_count) + { + result = &e_base_ctx->dbg_infos[module->dbg_info_num-1]; + } + return result; +} + +internal E_DbgInfo * +e_dbg_info_from_type_key(E_TypeKey type_key) +{ + E_DbgInfo *result = &e_dbg_info_nil; + if(type_key.kind == E_TypeKeyKind_Ext && + 0 < type_key.u32[2] && type_key.u32[2] <= e_base_ctx->dbg_infos_count) + { + result = &e_base_ctx->dbg_infos[type_key.u32[2]-1]; + } + return result; +} + //////////////////////////////// //~ rjf: Cache Accessing Functions diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index 19e35783..ed300e59 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -174,8 +174,8 @@ struct E_TypeKey E_TypeKeyKind kind; U32 u32[3]; // [0] -> E_TypeKind (Basic, Cons, Ext); Arch (Reg, RegAlias) - // [1] -> Type Index In RDI (Ext); Code (Reg, RegAlias); Type Index In Constructed (Cons) - // [2] -> RDI Index (Ext) + // [1] -> Type Index In Debug Info (Ext); Code (Reg, RegAlias); Type Index In Constructed (Cons) + // [2] -> Debug Info Number (Ext) }; typedef struct E_TypeKeyNode E_TypeKeyNode; @@ -384,11 +384,12 @@ enum E_TypeFlag_IsCodeText = (1<<4), E_TypeFlag_IsPathText = (1<<5), E_TypeFlag_IsNotText = (1<<6), - E_TypeFlag_EditableChildren = (1<<7), - E_TypeFlag_InheritedByMembers = (1<<8), - E_TypeFlag_InheritedByElements = (1<<9), - E_TypeFlag_ArrayLikeExpansion = (1<<10), - E_TypeFlag_StubSingleLineExpansion = (1<<11), + E_TypeFlag_IsNotEditable = (1<<7), + E_TypeFlag_EditableChildren = (1<<8), + E_TypeFlag_InheritedByMembers = (1<<9), + E_TypeFlag_InheritedByElements = (1<<10), + E_TypeFlag_ArrayLikeExpansion = (1<<11), + E_TypeFlag_StubSingleLineExpansion = (1<<12), }; typedef struct E_Member E_Member; @@ -564,15 +565,24 @@ struct E_ConsTypeSlot E_ConsTypeNode *last; }; +//////////////////////////////// +//~ rjf: Debug Info + +typedef struct E_DbgInfo E_DbgInfo; +struct E_DbgInfo +{ + DI_Key dbgi_key; + RDI_Parsed *rdi; +}; + //////////////////////////////// //~ rjf: Modules typedef struct E_Module E_Module; struct E_Module { - DI_Key dbgi_key; - RDI_Parsed *rdi; Rng1U64 vaddr_range; + U32 dbg_info_num; Arch arch; E_Space space; }; @@ -760,6 +770,11 @@ struct E_BaseCtx Arch thread_arch; U64 thread_unwind_count; + // rjf: debug infos + E_DbgInfo *dbg_infos; + U64 dbg_infos_count; + E_DbgInfo *primary_dbg_info; + // rjf: modules E_Module *modules; U64 modules_count; @@ -1111,7 +1126,8 @@ 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 = {{0}, &rdi_parsed_nil}; +read_only global E_DbgInfo e_dbg_info_nil = {{0}, &rdi_parsed_nil}; +read_only global E_Module e_module_nil = {0}; 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; @@ -1203,6 +1219,12 @@ internal void e_select_cache(E_Cache *cache); internal void e_select_base_ctx(E_BaseCtx *ctx); internal void e_select_ir_ctx(E_IRCtx *ctx); +//////////////////////////////// +//~ rjf: Context Accessors + +internal E_DbgInfo *e_dbg_info_from_module(E_Module *module); +internal E_DbgInfo *e_dbg_info_from_type_key(E_TypeKey type_key); + //////////////////////////////// //~ rjf: Base Cache Accessing Functions // diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index cdf5a029..0293a03d 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -389,7 +389,8 @@ E_TYPE_ACCESS_FUNCTION_DEF(default) E_TypeKind check_type_kind = l_restype_kind; if(l_restype_kind == E_TypeKind_Ptr || l_restype_kind == E_TypeKind_LRef || - l_restype_kind == E_TypeKind_RRef) + l_restype_kind == E_TypeKind_RRef || + l_restype_kind == E_TypeKind_Array) { check_type_key = e_type_key_unwrap(l.type_key, E_TypeUnwrapFlag_All); check_type_kind = e_type_kind_from_key(check_type_key); @@ -698,6 +699,10 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I result = new_result_maybe; break; } + else if(new_result_maybe.msgs.count != 0 && result.msgs.count == 0) + { + result = new_result_maybe; + } } if(result.root != &e_irnode_nil) { @@ -963,28 +968,27 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); E_Interpretation interpretation = e_interpret(bytecode); E_Module *module = &e_module_nil; - U32 rdi_idx = 0; for EachIndex(idx, e_base_ctx->modules_count) { E_Module *m = &e_base_ctx->modules[idx]; if(e_space_match(interpretation.space, m->space) && contains_1u64(m->vaddr_range, interpretation.value.u64)) { module = m; - rdi_idx = (U32)idx; break; } } if(module != &e_module_nil) { + E_DbgInfo *dbg_info = e_dbg_info_from_module(module); U64 voff = interpretation.value.u64 - module->vaddr_range.min; U64 new_vaddr = 0; - RDI_Procedure *p = rdi_procedure_from_voff(module->rdi, voff); - RDI_GlobalVariable *g = rdi_global_variable_from_voff(module->rdi, voff); + RDI_Procedure *p = rdi_procedure_from_voff(dbg_info->rdi, voff); + RDI_GlobalVariable *g = rdi_global_variable_from_voff(dbg_info->rdi, voff); U32 type_idx = 0; if(p->name_string_idx != 0) { type_idx = p->type_idx; - new_vaddr = module->vaddr_range.min + rdi_first_voff_from_procedure(module->rdi, p); + new_vaddr = module->vaddr_range.min + rdi_first_voff_from_procedure(dbg_info->rdi, p); } else if(g->name_string_idx != 0) { @@ -993,10 +997,10 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } if(type_idx != 0) { - RDI_TypeNode *t = rdi_element_from_name_idx(module->rdi, TypeNodes, type_idx); + RDI_TypeNode *t = rdi_element_from_name_idx(dbg_info->rdi, TypeNodes, type_idx); result.root = e_irtree_const_u(arena, new_vaddr); result.mode = E_Mode_Value; - result.type_key = e_type_key_ext(e_type_kind_from_rdi(t->kind), type_idx, rdi_idx); + result.type_key = e_type_key_ext(e_type_kind_from_rdi(t->kind), type_idx, module->dbg_info_num); } } }break; @@ -1792,12 +1796,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("member"), 0))) { E_Module *module = e_base_ctx->primary_module; - U32 module_idx = (U32)(module - e_base_ctx->modules); - RDI_Parsed *rdi = module->rdi; + E_DbgInfo *dbg_info = e_dbg_info_from_module(module); + RDI_Parsed *rdi = dbg_info->rdi; RDI_Procedure *procedure = e_cache->thread_ip_procedure; RDI_UDT *udt = rdi_container_udt_from_procedure(rdi, procedure); RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); - E_TypeKey container_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), udt->self_type_idx, module_idx); + E_TypeKey container_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), udt->self_type_idx, module->dbg_info_num); E_Member member = e_type_member_from_key_name__cached(container_type_key, string); if(member.kind != E_MemberKind_Null) { @@ -1811,8 +1815,8 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("local"), 0))) { E_Module *module = e_base_ctx->primary_module; - U32 module_idx = (U32)(module - e_base_ctx->modules); - RDI_Parsed *rdi = module->rdi; + E_DbgInfo *dbg_info = e_dbg_info_from_module(module); + RDI_Parsed *rdi = dbg_info->rdi; U64 local_num = e_num_from_string(e_ir_ctx->locals_map, string__redirected); if(local_num != 0) { @@ -1820,7 +1824,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I // rjf: extract local's type key RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, local->type_idx); - mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), local->type_idx, module_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), local->type_idx, module->dbg_info_num); // rjf: extract local's location block B32 got_location_block = 0; @@ -1887,13 +1891,14 @@ 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, e_base_ctx->primary_module->dbgi_key, 0); + DI_Match match = di_match_from_string(string, 0, e_base_ctx->primary_dbg_info->dbgi_key, 0); if(match.idx == 0) { String8List namespaceified_strings = {0}; { E_Module *module = e_base_ctx->primary_module; - RDI_Parsed *rdi = module->rdi; + E_DbgInfo *dbg_info = e_dbg_info_from_module(module); + RDI_Parsed *rdi = dbg_info->rdi; RDI_Procedure *procedure = e_cache->thread_ip_procedure; U64 name_size = 0; U8 *name_ptr = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); @@ -1916,7 +1921,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, e_base_ctx->primary_module->dbgi_key, 0); + match = di_match_from_string(n->string, 0, e_base_ctx->primary_dbg_info->dbgi_key, 0); if(match.idx != 0) { break; @@ -1927,17 +1932,27 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I // rjf: match -> RDI RDI_Parsed *rdi = di_rdi_from_key(access, match.key, 0, 0); + // rjf: find dbg info from rdi + E_DbgInfo *dbg_info = &e_dbg_info_nil; + U32 dbg_info_num = 0; + for EachIndex(idx, e_base_ctx->dbg_infos_count) + { + if(e_base_ctx->dbg_infos[idx].rdi == rdi) + { + dbg_info = &e_base_ctx->dbg_infos[idx]; + dbg_info_num = idx+1; + break; + } + } + // rjf: find module from dbgi key - U32 dbgi_idx = 0; E_Module *module = &e_module_nil; for EachIndex(idx, e_base_ctx->modules_count) { - if(e_base_ctx->modules[idx].rdi == rdi) + if(e_base_ctx->modules[idx].dbg_info_num == dbg_info_num) { module = &e_base_ctx->modules[idx]; - dbgi_idx = (U32)idx; - if(module == e_base_ctx->primary_module || - e_space_match(module->space, e_base_ctx->primary_module->space)) + if(module == e_base_ctx->primary_module || e_space_match(module->space, e_base_ctx->primary_module->space)) { break; } @@ -1945,7 +1960,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } // rjf: form result - if(match.idx != 0 && module != &e_module_nil) + if(match.idx != 0 && dbg_info != &e_dbg_info_nil) { switch(match.section_kind) { @@ -1958,7 +1973,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, dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbg_info_num); mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Offset; mapped_bytecode_space = module->space; @@ -1971,7 +1986,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, dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbg_info_num); mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Offset; mapped_bytecode_space = module->space; @@ -1994,7 +2009,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, dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbg_info_num); mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Value; mapped_bytecode_space = module->space; @@ -2012,7 +2027,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, dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbg_info_num); mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); mapped_bytecode_mode = E_Mode_Value; mapped_bytecode_space = module->space; @@ -2021,7 +2036,7 @@ 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, dbgi_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbg_info_num); string_mapped = 1; }break; } @@ -2106,9 +2121,10 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I if(!generated && mapped_location_block != 0) { E_Module *module = mapped_location_block_module; + E_DbgInfo *dbg_info = e_dbg_info_from_module(module); E_Space space = module->space; Arch arch = module->arch; - RDI_Parsed *rdi = module->rdi; + RDI_Parsed *rdi = dbg_info->rdi; RDI_LocationBlock *block = mapped_location_block; U64 all_location_data_size = 0; U8 *all_location_data = rdi_table_from_name(rdi, LocationData, &all_location_data_size); @@ -2461,17 +2477,18 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I if(e_space_read(interpret.space, &vtable_vaddr, r1u64(class_base_vaddr, class_base_vaddr+addr_size))) { Arch arch = e_base_ctx->primary_module->arch; - U32 rdi_idx = 0; + U32 dbg_info_num = 0; RDI_Parsed *rdi = 0; U64 module_base = 0; for(U64 idx = 0; idx < e_base_ctx->modules_count; idx += 1) { if(contains_1u64(e_base_ctx->modules[idx].vaddr_range, vtable_vaddr)) { + E_DbgInfo *dbg_info = e_dbg_info_from_module(&e_base_ctx->modules[idx]); arch = e_base_ctx->modules[idx].arch; - rdi_idx = (U32)idx; - rdi = e_base_ctx->modules[idx].rdi; module_base = e_base_ctx->modules[idx].vaddr_range.min; + dbg_info_num = e_base_ctx->modules[idx].dbg_info_num; + rdi = dbg_info->rdi; break; } } @@ -2484,7 +2501,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I { RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, global_var->container_idx); RDI_TypeNode *type = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); - E_TypeKey derived_type_key = e_type_key_ext(e_type_kind_from_rdi(type->kind), udt->self_type_idx, rdi_idx); + E_TypeKey derived_type_key = e_type_key_ext(e_type_kind_from_rdi(type->kind), udt->self_type_idx, dbg_info_num); E_TypeKey ptr_to_derived_type_key = e_type_key_cons_ptr(arch, derived_type_key, 1, 0); result.type_key = ptr_to_derived_type_key; } diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index 4b59a1ac..d3d0d40f 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -585,19 +585,19 @@ 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, e_base_ctx->primary_module->dbgi_key, 0); + DI_Match match = di_match_from_string(name, 0, e_base_ctx->primary_dbg_info->dbgi_key, 0); if(match.section_kind == RDI_SectionKind_TypeNodes) { Access *access = access_open(); RDI_Parsed *rdi = di_rdi_from_key(access, match.key, 0, 0); - for EachIndex(idx, e_base_ctx->modules_count) + for EachIndex(idx, e_base_ctx->dbg_infos_count) { - E_Module *module = &e_base_ctx->modules[idx]; - if(module->rdi == rdi) + E_DbgInfo *dbg_info = &e_base_ctx->dbg_infos[idx]; + if(dbg_info->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); + key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)idx+1); break; } } diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 93f426f9..7a395e3b 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -271,7 +271,7 @@ e_type_key_basic(E_TypeKind kind) } internal E_TypeKey -e_type_key_ext(E_TypeKind kind, U32 type_idx, U32 rdi_idx) +e_type_key_ext(E_TypeKind kind, U32 type_idx, U32 rdi_num) { E_TypeKey key = {E_TypeKeyKind_Ext}; key.u32[0] = (U32)kind; @@ -282,7 +282,7 @@ e_type_key_ext(E_TypeKind kind, U32 type_idx, U32 rdi_idx) else { key.u32[1] = type_idx; - key.u32[2] = rdi_idx; + key.u32[2] = rdi_num; } return key; } @@ -646,10 +646,13 @@ e_type_byte_size_from_key(E_TypeKey key) case E_TypeKeyKind_Ext: { U64 type_node_idx = key.u32[1]; - U32 rdi_idx = key.u32[2]; - RDI_Parsed *rdi = e_base_ctx->modules[rdi_idx].rdi; - RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx); - result = rdi_type->byte_size; + U32 rdi_num = key.u32[2]; + if(0 < rdi_num && rdi_num <= e_base_ctx->dbg_infos_count) + { + RDI_Parsed *rdi = e_base_ctx->dbg_infos[rdi_num-1].rdi; + RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx); + result = rdi_type->byte_size; + } }break; case E_TypeKeyKind_Cons: { @@ -758,322 +761,327 @@ e_push_type_from_key(Arena *arena, E_TypeKey key) case E_TypeKeyKind_Ext: { U64 type_node_idx = key.u32[1]; - U32 rdi_idx = key.u32[2]; - RDI_Parsed *rdi = e_base_ctx->modules[rdi_idx].rdi; - RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx); - if(rdi_type->kind != RDI_TypeKind_NULL) + U32 rdi_num = key.u32[2]; + if(0 < rdi_num && rdi_num <= e_base_ctx->dbg_infos_count) { - E_TypeKind kind = e_type_kind_from_rdi(rdi_type->kind); - - //- rjf: record types => unpack name * members & produce - if(RDI_TypeKind_FirstRecord <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastRecord) + RDI_Parsed *rdi = e_base_ctx->dbg_infos[rdi_num-1].rdi; + RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); + Arch arch = arch_from_rdi_arch(tli->arch); + RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx); + if(rdi_type->kind != RDI_TypeKind_NULL) { - // rjf: unpack name - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); + E_TypeKind kind = e_type_kind_from_rdi(rdi_type->kind); - // rjf: unpack UDT info - RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, rdi_type->user_defined.udt_idx); - - // rjf: unpack members - E_Member *members = 0; - U32 members_count = 0; + //- rjf: record types => unpack name * members & produce + if(RDI_TypeKind_FirstRecord <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastRecord) { - members_count = udt->member_count; - members = push_array(arena, E_Member, members_count); - if(members_count != 0) + // rjf: unpack name + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); + + // rjf: unpack UDT info + RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, rdi_type->user_defined.udt_idx); + + // rjf: unpack members + E_Member *members = 0; + U32 members_count = 0; { + members_count = udt->member_count; + members = push_array(arena, E_Member, members_count); + if(members_count != 0) + { + for(U32 member_idx = udt->member_first; + member_idx < udt->member_first+udt->member_count; + member_idx += 1) + { + RDI_Member *src = rdi_element_from_name_idx(rdi, Members, member_idx); + E_TypeKind member_type_kind = E_TypeKind_Null; + RDI_TypeNode *member_type = rdi_element_from_name_idx(rdi, TypeNodes, src->type_idx); + member_type_kind = e_type_kind_from_rdi(member_type->kind); + E_Member *dst = &members[member_idx-udt->member_first]; + dst->kind = e_member_kind_from_rdi(src->kind); + dst->type_key = e_type_key_ext(member_type_kind, src->type_idx, rdi_num); + dst->name.str = rdi_string_from_idx(rdi, src->name_string_idx, &dst->name.size); + dst->off = (U64)src->off; + } + } + } + + // rjf: produce + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->name = push_str8_copy(arena, name); + type->byte_size = (U64)rdi_type->byte_size; + type->count = members_count; + type->arch = arch; + type->members = members; + } + + //- rjf: enum types => unpack name * values & produce + else if(rdi_type->kind == RDI_TypeKind_Enum) + { + // rjf: unpack name + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); + + // rjf: unpack direct type + E_TypeKey direct_type_key = zero_struct; + if(rdi_type->user_defined.direct_type_idx < type_node_idx) + { + RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->user_defined.direct_type_idx); + E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); + direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->user_defined.direct_type_idx, rdi_num); + } + + // rjf: unpack members + E_EnumVal *enum_vals = 0; + U32 enum_vals_count = 0; + { + U32 udt_idx = rdi_type->user_defined.udt_idx; + RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, udt_idx); + enum_vals_count = udt->member_count; + enum_vals = push_array(arena, E_EnumVal, enum_vals_count); for(U32 member_idx = udt->member_first; member_idx < udt->member_first+udt->member_count; member_idx += 1) { - RDI_Member *src = rdi_element_from_name_idx(rdi, Members, member_idx); - E_TypeKind member_type_kind = E_TypeKind_Null; - RDI_TypeNode *member_type = rdi_element_from_name_idx(rdi, TypeNodes, src->type_idx); - member_type_kind = e_type_kind_from_rdi(member_type->kind); - E_Member *dst = &members[member_idx-udt->member_first]; - dst->kind = e_member_kind_from_rdi(src->kind); - dst->type_key = e_type_key_ext(member_type_kind, src->type_idx, rdi_idx); + RDI_EnumMember *src = rdi_element_from_name_idx(rdi, EnumMembers, member_idx); + E_EnumVal *dst = &enum_vals[member_idx-udt->member_first]; dst->name.str = rdi_string_from_idx(rdi, src->name_string_idx, &dst->name.size); - dst->off = (U64)src->off; + dst->val = src->val; } } - } - - // rjf: produce - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->name = push_str8_copy(arena, name); - type->byte_size = (U64)rdi_type->byte_size; - type->count = members_count; - type->arch = e_base_ctx->modules[rdi_idx].arch; - type->members = members; - } - - //- rjf: enum types => unpack name * values & produce - else if(rdi_type->kind == RDI_TypeKind_Enum) - { - // rjf: unpack name - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); - - // rjf: unpack direct type - E_TypeKey direct_type_key = zero_struct; - if(rdi_type->user_defined.direct_type_idx < type_node_idx) - { - RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->user_defined.direct_type_idx); - E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); - direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->user_defined.direct_type_idx, rdi_idx); - } - - // rjf: unpack members - E_EnumVal *enum_vals = 0; - U32 enum_vals_count = 0; - { - U32 udt_idx = rdi_type->user_defined.udt_idx; - RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, udt_idx); - enum_vals_count = udt->member_count; - enum_vals = push_array(arena, E_EnumVal, enum_vals_count); - for(U32 member_idx = udt->member_first; - member_idx < udt->member_first+udt->member_count; - member_idx += 1) - { - RDI_EnumMember *src = rdi_element_from_name_idx(rdi, EnumMembers, member_idx); - E_EnumVal *dst = &enum_vals[member_idx-udt->member_first]; - dst->name.str = rdi_string_from_idx(rdi, src->name_string_idx, &dst->name.size); - dst->val = src->val; - } - } - - // rjf: produce - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->name = push_str8_copy(arena, name); - type->byte_size = (U64)rdi_type->byte_size; - type->count = enum_vals_count; - type->arch = e_base_ctx->modules[rdi_idx].arch; - type->enum_vals = enum_vals; - type->direct_type_key = direct_type_key; - } - - //- rjf: constructed types - else if(RDI_TypeKind_FirstConstructed <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastConstructed) - { - // rjf: unpack direct type - B32 direct_type_is_good = 0; - E_TypeKey direct_type_key = zero_struct; - U64 direct_type_byte_size = 0; - if(rdi_type->constructed.direct_type_idx < type_node_idx) - { - RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->constructed.direct_type_idx); - E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); - direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->constructed.direct_type_idx, rdi_idx); - direct_type_is_good = 1; - direct_type_byte_size = (U64)direct_type_node->byte_size; - } - - // rjf: construct based on kind - switch(rdi_type->kind) - { - case RDI_TypeKind_Modifier: - { - E_TypeFlags flags = 0; - if(rdi_type->flags & RDI_TypeModifierFlag_Const) - { - flags |= E_TypeFlag_Const; - } - if(rdi_type->flags & RDI_TypeModifierFlag_Volatile) - { - flags |= E_TypeFlag_Volatile; - } - if(rdi_type->flags & RDI_TypeModifierFlag_Restrict) - { - flags |= E_TypeFlag_Restrict; - } - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->direct_type_key = direct_type_key; - type->byte_size = direct_type_byte_size; - type->flags = flags; - type->arch = e_base_ctx->modules[rdi_idx].arch; - }break; - case RDI_TypeKind_Ptr: - case RDI_TypeKind_LRef: - case RDI_TypeKind_RRef: - { - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->direct_type_key = direct_type_key; - type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8; - type->count = 1; - type->arch = e_base_ctx->modules[rdi_idx].arch; - }break; - case RDI_TypeKind_Array: + // rjf: produce + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->name = push_str8_copy(arena, name); + type->byte_size = (U64)rdi_type->byte_size; + type->count = enum_vals_count; + type->arch = arch; + type->enum_vals = enum_vals; + type->direct_type_key = direct_type_key; + } + + //- rjf: constructed types + else if(RDI_TypeKind_FirstConstructed <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastConstructed) + { + // rjf: unpack direct type + B32 direct_type_is_good = 0; + E_TypeKey direct_type_key = zero_struct; + U64 direct_type_byte_size = 0; + if(rdi_type->constructed.direct_type_idx < type_node_idx) { - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->direct_type_key = direct_type_key; - type->count = rdi_type->constructed.count; - type->byte_size = direct_type_byte_size * type->count; - type->arch = e_base_ctx->modules[rdi_idx].arch; - }break; - case RDI_TypeKind_Function: + RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->constructed.direct_type_idx); + E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); + direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->constructed.direct_type_idx, rdi_num); + direct_type_is_good = 1; + direct_type_byte_size = (U64)direct_type_node->byte_size; + } + + // rjf: construct based on kind + switch(rdi_type->kind) { - U32 count = rdi_type->constructed.count; - U32 idx_run_first = rdi_type->constructed.param_idx_run_first; - U32 check_count = 0; - U32 *idx_run = rdi_idx_run_from_first_count(rdi, idx_run_first, count, &check_count); - if(check_count == count) + case RDI_TypeKind_Modifier: { + E_TypeFlags flags = 0; + if(rdi_type->flags & RDI_TypeModifierFlag_Const) + { + flags |= E_TypeFlag_Const; + } + if(rdi_type->flags & RDI_TypeModifierFlag_Volatile) + { + flags |= E_TypeFlag_Volatile; + } + if(rdi_type->flags & RDI_TypeModifierFlag_Restrict) + { + flags |= E_TypeFlag_Restrict; + } type = push_array(arena, E_Type, 1); type->kind = kind; - type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8; type->direct_type_key = direct_type_key; - type->count = count; - type->param_type_keys = push_array(arena, E_TypeKey, type->count); - type->arch = e_base_ctx->modules[rdi_idx].arch; - for(U32 idx = 0; idx < type->count; idx += 1) - { - U32 param_type_idx = idx_run[idx]; - if(param_type_idx < type_node_idx) - { - RDI_TypeNode *param_type_node = rdi_element_from_name_idx(rdi, TypeNodes, param_type_idx); - E_TypeKind param_kind = e_type_kind_from_rdi(param_type_node->kind); - type->param_type_keys[idx] = e_type_key_ext(param_kind, param_type_idx, rdi_idx); - } - else - { - break; - } - } - } - }break; - case RDI_TypeKind_Method: - { - // NOTE(rjf): for methods, the `direct` type points at the owner type. - // the return type, instead of being encoded via the `direct` type, is - // encoded via the first parameter. - U32 count = rdi_type->constructed.count; - U32 idx_run_first = rdi_type->constructed.param_idx_run_first; - U32 check_count = 0; - U32 *idx_run = rdi_idx_run_from_first_count(rdi, idx_run_first, count, &check_count); - if(check_count == count) + type->byte_size = direct_type_byte_size; + type->flags = flags; + type->arch = arch; + }break; + case RDI_TypeKind_Ptr: + case RDI_TypeKind_LRef: + case RDI_TypeKind_RRef: { type = push_array(arena, E_Type, 1); type->kind = kind; - type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8; - type->owner_type_key = direct_type_key; - type->count = count; - type->param_type_keys = push_array_no_zero(arena, E_TypeKey, type->count); - type->arch = e_base_ctx->modules[rdi_idx].arch; - for(U32 idx = 0; idx < type->count; idx += 1) - { - U32 param_type_idx = idx_run[idx]; - if(param_type_idx < type_node_idx) - { - RDI_TypeNode *param_type_node = rdi_element_from_name_idx(rdi, TypeNodes, param_type_idx); - E_TypeKind param_kind = e_type_kind_from_rdi(param_type_node->kind); - type->param_type_keys[idx] = e_type_key_ext(param_kind, param_type_idx, rdi_idx); - } - else - { - break; - } - } - if(type->count > 0) - { - type->direct_type_key = type->param_type_keys[0]; - type->count -= 1; - type->param_type_keys += 1; - } - } - }break; - case RDI_TypeKind_MemberPtr: - { - // rjf: unpack owner type - E_TypeKey owner_type_key = zero_struct; - if(rdi_type->constructed.owner_type_idx < type_node_idx) + type->direct_type_key = direct_type_key; + type->byte_size = bit_size_from_arch(arch)/8; + type->count = 1; + type->arch = arch; + }break; + + case RDI_TypeKind_Array: { - RDI_TypeNode *owner_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->constructed.owner_type_idx); - E_TypeKind owner_type_kind = e_type_kind_from_rdi(owner_type_node->kind); - owner_type_key = e_type_key_ext(owner_type_kind, rdi_type->constructed.owner_type_idx, rdi_idx); - } - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8; - type->owner_type_key = owner_type_key; - type->direct_type_key = direct_type_key; - type->arch = e_base_ctx->modules[rdi_idx].arch; - }break; + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->direct_type_key = direct_type_key; + type->count = rdi_type->constructed.count; + type->byte_size = direct_type_byte_size * type->count; + type->arch = arch; + }break; + case RDI_TypeKind_Function: + { + U32 count = rdi_type->constructed.count; + U32 idx_run_first = rdi_type->constructed.param_idx_run_first; + U32 check_count = 0; + U32 *idx_run = rdi_idx_run_from_first_count(rdi, idx_run_first, count, &check_count); + if(check_count == count) + { + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->byte_size = bit_size_from_arch(arch)/8; + type->direct_type_key = direct_type_key; + type->count = count; + type->param_type_keys = push_array(arena, E_TypeKey, type->count); + type->arch = arch; + for(U32 idx = 0; idx < type->count; idx += 1) + { + U32 param_type_idx = idx_run[idx]; + if(param_type_idx < type_node_idx) + { + RDI_TypeNode *param_type_node = rdi_element_from_name_idx(rdi, TypeNodes, param_type_idx); + E_TypeKind param_kind = e_type_kind_from_rdi(param_type_node->kind); + type->param_type_keys[idx] = e_type_key_ext(param_kind, param_type_idx, rdi_num); + } + else + { + break; + } + } + } + }break; + case RDI_TypeKind_Method: + { + // NOTE(rjf): for methods, the `direct` type points at the owner type. + // the return type, instead of being encoded via the `direct` type, is + // encoded via the first parameter. + U32 count = rdi_type->constructed.count; + U32 idx_run_first = rdi_type->constructed.param_idx_run_first; + U32 check_count = 0; + U32 *idx_run = rdi_idx_run_from_first_count(rdi, idx_run_first, count, &check_count); + if(check_count == count) + { + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->byte_size = bit_size_from_arch(arch)/8; + type->owner_type_key = direct_type_key; + type->count = count; + type->param_type_keys = push_array_no_zero(arena, E_TypeKey, type->count); + type->arch = arch; + for(U32 idx = 0; idx < type->count; idx += 1) + { + U32 param_type_idx = idx_run[idx]; + if(param_type_idx < type_node_idx) + { + RDI_TypeNode *param_type_node = rdi_element_from_name_idx(rdi, TypeNodes, param_type_idx); + E_TypeKind param_kind = e_type_kind_from_rdi(param_type_node->kind); + type->param_type_keys[idx] = e_type_key_ext(param_kind, param_type_idx, rdi_num); + } + else + { + break; + } + } + if(type->count > 0) + { + type->direct_type_key = type->param_type_keys[0]; + type->count -= 1; + type->param_type_keys += 1; + } + } + }break; + case RDI_TypeKind_MemberPtr: + { + // rjf: unpack owner type + E_TypeKey owner_type_key = zero_struct; + if(rdi_type->constructed.owner_type_idx < type_node_idx) + { + RDI_TypeNode *owner_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->constructed.owner_type_idx); + E_TypeKind owner_type_kind = e_type_kind_from_rdi(owner_type_node->kind); + owner_type_key = e_type_key_ext(owner_type_kind, rdi_type->constructed.owner_type_idx, rdi_num); + } + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->byte_size = bit_size_from_arch(arch)/8; + type->owner_type_key = owner_type_key; + type->direct_type_key = direct_type_key; + type->arch = arch; + }break; + } } - } - - //- rjf: alias types - else if(rdi_type->kind == RDI_TypeKind_Alias) - { - // rjf: unpack name - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); - // rjf: unpack direct type - E_TypeKey direct_type_key = zero_struct; - U64 direct_type_byte_size = 0; - if(rdi_type->user_defined.direct_type_idx < type_node_idx) + //- rjf: alias types + else if(rdi_type->kind == RDI_TypeKind_Alias) { - RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->user_defined.direct_type_idx); - E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); - direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->user_defined.direct_type_idx, rdi_idx); - direct_type_byte_size = direct_type_node->byte_size; + // rjf: unpack name + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); + + // rjf: unpack direct type + E_TypeKey direct_type_key = zero_struct; + U64 direct_type_byte_size = 0; + if(rdi_type->user_defined.direct_type_idx < type_node_idx) + { + RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->user_defined.direct_type_idx); + E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); + direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->user_defined.direct_type_idx, rdi_num); + direct_type_byte_size = direct_type_node->byte_size; + } + + // rjf: produce + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->name = push_str8_copy(arena, name); + type->byte_size = direct_type_byte_size; + type->direct_type_key = direct_type_key; + type->arch = arch; } - // rjf: produce - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->name = push_str8_copy(arena, name); - type->byte_size = direct_type_byte_size; - type->direct_type_key = direct_type_key; - type->arch = e_base_ctx->modules[rdi_idx].arch; - } - - //- rjf: bitfields - else if(RDI_TypeKind_Bitfield == rdi_type->kind) - { - // rjf: unpack direct type - E_TypeKey direct_type_key = zero_struct; - U64 direct_type_byte_size = 0; - if(rdi_type->bitfield.direct_type_idx < type_node_idx) + //- rjf: bitfields + else if(RDI_TypeKind_Bitfield == rdi_type->kind) { - RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->bitfield.direct_type_idx); - E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); - direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->bitfield.direct_type_idx, rdi_idx); - direct_type_byte_size = direct_type_node->byte_size; + // rjf: unpack direct type + E_TypeKey direct_type_key = zero_struct; + U64 direct_type_byte_size = 0; + if(rdi_type->bitfield.direct_type_idx < type_node_idx) + { + RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->bitfield.direct_type_idx); + E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); + direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->bitfield.direct_type_idx, rdi_num); + direct_type_byte_size = direct_type_node->byte_size; + } + + // rjf: produce + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->byte_size = direct_type_byte_size; + type->direct_type_key = direct_type_key; + type->off = (U32)rdi_type->bitfield.off; + type->count = (U64)rdi_type->bitfield.size; + type->arch = arch; } - // rjf: produce - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->byte_size = direct_type_byte_size; - type->direct_type_key = direct_type_key; - type->off = (U32)rdi_type->bitfield.off; - type->count = (U64)rdi_type->bitfield.size; - type->arch = e_base_ctx->modules[rdi_idx].arch; - } - - //- rjf: incomplete types - else if(RDI_TypeKind_FirstIncomplete <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastIncomplete) - { - // rjf: unpack name - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); + //- rjf: incomplete types + else if(RDI_TypeKind_FirstIncomplete <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastIncomplete) + { + // rjf: unpack name + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); + + // rjf: produce + type = push_array(arena, E_Type, 1); + type->kind = kind; + type->name = push_str8_copy(arena, name); + type->arch = arch; + } - // rjf: produce - type = push_array(arena, E_Type, 1); - type->kind = kind; - type->name = push_str8_copy(arena, name); - type->arch = e_base_ctx->modules[rdi_idx].arch; } - } }break; @@ -2653,9 +2661,18 @@ e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U chunk->count += 1; total_count += 1; + //- rjf: record this offset in our hit-offset table + { + U64 hash = u64_hash_from_str8(str8_struct(&off)); + U64 slot_idx = hash%hit_slots_count; + HitOffsetNode *n = push_array(scratch.arena, HitOffsetNode, 1); + n->off = off; + SLLStackPush(hit_slots[slot_idx], n); + } + //- rjf: read next offset, advance 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); + B32 read_good = ctrl_process_memory_read(process, r1u64(off + member_element_off, off + member_element_off + member_size), &read_stale, &next_off, 0); if(read_stale) { retry = 1; diff --git a/src/eval/eval_types.h b/src/eval/eval_types.h index c6f8c66e..94f6908f 100644 --- a/src/eval/eval_types.h +++ b/src/eval/eval_types.h @@ -70,7 +70,7 @@ internal E_EnumValArray e_enum_val_array_from_list(Arena *arena, E_EnumValList * //- rjf: basic key constructors internal E_TypeKey e_type_key_zero(void); internal E_TypeKey e_type_key_basic(E_TypeKind kind); -internal E_TypeKey e_type_key_ext(E_TypeKind kind, U32 type_idx, U32 rdi_idx); +internal E_TypeKey e_type_key_ext(E_TypeKind kind, U32 type_idx, U32 rdi_num); internal E_TypeKey e_type_key_reg(Arch arch, REGS_RegCode code); internal E_TypeKey e_type_key_reg_alias(Arch arch, REGS_AliasCode code); diff --git a/src/eval_visualization/eval_visualization_core.c b/src/eval_visualization/eval_visualization_core.c index 2451b70f..dc2493f4 100644 --- a/src/eval_visualization/eval_visualization_core.c +++ b/src/eval_visualization/eval_visualization_core.c @@ -150,8 +150,14 @@ ev_type_key_is_editable(E_TypeKey type_key) B32 done = 0; for(E_TypeKey t = type_key; !result && !done; t = e_type_key_direct(t)) { - E_TypeKind kind = e_type_kind_from_key(t); - switch(kind) + E_Type *type = e_type_from_key(t); + E_TypeKind kind = type->kind; + if(type->flags & E_TypeFlag_IsNotEditable) + { + result = 0; + done = 1; + } + else switch(kind) { case E_TypeKind_Null: case E_TypeKind_Function: @@ -167,7 +173,6 @@ ev_type_key_is_editable(E_TypeKey type_key) }break; case E_TypeKind_Array: { - E_Type *type = e_type_from_key(t); if(type->flags & E_TypeFlag_IsNotText) { result = 0; @@ -1906,17 +1911,25 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string) { U64 vaddr = ptr_data->value_eval.value.u64; E_Module *module = &e_module_nil; - U32 module_idx = 0; for EachIndex(idx, e_base_ctx->modules_count) { if(contains_1u64(e_base_ctx->modules[idx].vaddr_range, vaddr)) { module = &e_base_ctx->modules[idx]; - module_idx = (U32)idx; break; } } - RDI_Parsed *rdi = module->rdi; + E_DbgInfo *dbg_info = e_dbg_info_from_module(module); + if(dbg_info == &e_dbg_info_nil) + { + dbg_info = e_dbg_info_from_type_key(type_key); + } + U32 dbg_info_num = 0; + if(dbg_info != &e_dbg_info_nil) + { + dbg_info_num = (U32)(dbg_info - e_base_ctx->dbg_infos) + 1; + } + RDI_Parsed *rdi = dbg_info->rdi; U64 voff = vaddr - module->vaddr_range.min; B32 good_symbol_match = 0; @@ -1965,7 +1978,7 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string) if(inline_site != 0) { RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, inline_site->type_idx); - E_TypeKey type = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), inline_site->type_idx, module_idx); + E_TypeKey type = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), inline_site->type_idx, dbg_info_num); String8 name = {0}; name.str = rdi_string_from_idx(rdi, inline_site->name_string_idx, &name.size); if(inline_site->type_idx != 0) @@ -1995,7 +2008,7 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string) U64 proc_idx = scope->proc_idx; RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, proc_idx); RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, procedure->type_idx); - E_TypeKey type = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), procedure->type_idx, module_idx); + E_TypeKey type = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), procedure->type_idx, dbg_info_num); String8 name = {0}; name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); if(procedure->type_idx != 0) diff --git a/src/lib_raddbg_markup/raddbg_markup.h b/src/lib_raddbg_markup/raddbg_markup.h index 97112df0..dab7bdba 100644 --- a/src/lib_raddbg_markup/raddbg_markup.h +++ b/src/lib_raddbg_markup/raddbg_markup.h @@ -170,7 +170,7 @@ raddbg_decode_utf8(char *str, unsigned __int64 max) case 2: if(2 < max) { - char cont_byte = str[1]; + unsigned char cont_byte = str[1]; if(raddbg_utf8_class[cont_byte >> 3] == 0) { result.codepoint = (byte & 0x0000001f) << 6; @@ -181,7 +181,7 @@ raddbg_decode_utf8(char *str, unsigned __int64 max) case 3: if(2 < max) { - char cont_byte[2] = {str[1], str[2]}; + unsigned char cont_byte[2] = {(unsigned char)str[1], (unsigned char)str[2]}; if(raddbg_utf8_class[cont_byte[0] >> 3] == 0 && raddbg_utf8_class[cont_byte[1] >> 3] == 0) { @@ -194,7 +194,7 @@ raddbg_decode_utf8(char *str, unsigned __int64 max) case 4: if(3 < max) { - char cont_byte[3] = {str[1], str[2], str[3]}; + unsigned char cont_byte[3] = {(unsigned char)str[1], (unsigned char)str[2], (unsigned char)str[3]}; if(raddbg_utf8_class[cont_byte[0] >> 3] == 0 && raddbg_utf8_class[cont_byte[1] >> 3] == 0 && raddbg_utf8_class[cont_byte[2] >> 3] == 0) @@ -431,6 +431,9 @@ raddbg_annotate_vaddr_range__impl(void *ptr, unsigned __int64 size, char *fmt, . va_list args; va_start(args, fmt); buffer_size = RADDBG_MARKUP_VSNPRINTF(buffer, sizeof(buffer), fmt, args); + buffer_size = ((buffer_size < 0) ? 0 : + (buffer_size > sizeof(buffer)) ? sizeof(buffer) : + buffer_size); va_end(args); } diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index 44da5f21..7096399b 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -52,6 +52,9 @@ union RDI_SHA1 {RDI_U8 u8[20];}; typedef union RDI_SHA256 RDI_SHA256; union RDI_SHA256 {RDI_U8 u8[32]; RDI_U64 u64[4];}; +typedef union RDI_GUID RDI_GUID; +union RDI_GUID {RDI_U8 u8[16]; RDI_U64 u64[2];}; + //////////////////////////////////////////////////////////////// //~ Overridable Enabling/Disabling Of Table Index Typechecking @@ -64,7 +67,7 @@ union RDI_SHA256 {RDI_U8 u8[32]; RDI_U64 u64[4];}; // "raddbg\0\0" #define RDI_MAGIC_CONSTANT 0x0000676264646172 -#define RDI_ENCODING_VERSION 16 +#define RDI_ENCODING_VERSION 17 //////////////////////////////////////////////////////////////// //~ Format Types & Functions @@ -807,6 +810,7 @@ X(RDI_Arch, arch)\ X(RDI_U32, exe_name_string_idx)\ X(RDI_U64, exe_hash)\ X(RDI_U64, voff_max)\ +X(RDI_GUID, guid)\ X(RDI_U32, producer_name_string_idx)\ #define RDI_BinarySectionFlags_XList \ @@ -1283,6 +1287,7 @@ RDI_Arch arch; RDI_U32 exe_name_string_idx; RDI_U64 exe_hash; RDI_U64 voff_max; +RDI_GUID guid; RDI_U32 producer_name_string_idx; }; diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 8a506373..3a26b89d 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1196,6 +1196,11 @@ rdim_bake_params_concat_in_place(RDIM_BakeParams *dst, RDIM_BakeParams *src) { dst->top_level_info.voff_max = src->top_level_info.voff_max; } + if(dst->top_level_info.guid.u64[0] == 0 && + dst->top_level_info.guid.u64[1] == 0) + { + dst->top_level_info.guid = src->top_level_info.guid; + } if(dst->top_level_info.producer_name.size == 0) { dst->top_level_info.producer_name = src->top_level_info.producer_name; diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 1aea0530..9eb8829d 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -499,6 +499,7 @@ struct RDIM_TopLevelInfo RDIM_String8 exe_name; RDI_U64 exe_hash; RDI_U64 voff_max; + RDI_GUID guid; RDIM_String8 producer_name; }; diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index e0383f61..42204d0e 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -584,6 +584,8 @@ type_coverage_eval_tests(void) SLLNode node1 = {0, &node2, 1}; raddbg_pin(list(node1, the_real_next_ptr)); + node6.next = &node1; + Alias1 a1 = has_enums.kind; Alias2 a2 = has_enums.flags; Alias3 a3 = has_enums; diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index 68ff15a6..53f8edb5 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -548,7 +548,14 @@ os_w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_DPICHANGED: { F32 new_dpi = (F32)(wParam & 0xffff); + RECT suggested_new_rect = *(RECT *)lParam; window->dpi = new_dpi; + SetWindowPos(window->hwnd, 0, + suggested_new_rect.left, + suggested_new_rect.top, + suggested_new_rect.right - suggested_new_rect.left, + suggested_new_rect.bottom - suggested_new_rect.top, + 0); }break; //- rjf: [file drop] @@ -565,7 +572,9 @@ os_w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) U64 name_size = DragQueryFile(drop, idx, 0, 0) + 1; U8 *name_ptr = push_array(os_w32_event_arena, U8, name_size); DragQueryFile(drop, idx, (char *)name_ptr, name_size); - str8_list_push(os_w32_event_arena, &event->strings, str8(name_ptr, name_size - 1)); + String8 path_string = str8(name_ptr, name_size - 1); + String8 path_string__normalized = path_normalized_from_string(os_w32_event_arena, path_string); + str8_list_push(os_w32_event_arena, &event->strings, path_string__normalized); } DragFinish(drop); }break; diff --git a/src/pdb/pdb_parse.c b/src/pdb/pdb_parse.c index af3b52a5..0849fd98 100644 --- a/src/pdb/pdb_parse.c +++ b/src/pdb/pdb_parse.c @@ -1143,9 +1143,11 @@ pdb_has_file_ref(String8 msf_data, String8List file_list, MSF_RawStreamTable *st Temp temp = temp_begin(scratch.arena); String8 path = file_n->string; String8 path_pdbstyle = path_convert_slashes(temp.arena, path, PathStyle_WindowsAbsolute); - U32 off = pdb_strtbl_off_from_string(strtbl, path_pdbstyle); + String8 path_pdbstyle_lower = lower_from_str8(temp.arena, path_pdbstyle); + U32 off1 = pdb_strtbl_off_from_string(strtbl, path_pdbstyle); + U32 off2 = pdb_strtbl_off_from_string(strtbl, path_pdbstyle_lower); temp_end(temp); - if(off != max_U32) + if(off1 != max_U32 || off2 != max_U32) { has_ref = 1; break; diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index c27ab797..9274a100 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -851,7 +851,7 @@ rb_thread_entry_point(void *p) { 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) + if(unique_identifier_string.size == 0) { Temp scratch = scratch_begin(&arena, 1); String8 msf_data = input_files.first->v->data; diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 19bb9e17..f02a7917 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -4,7 +4,7 @@ //- GENERATED CODE C_LINKAGE_BEGIN -String8 rd_tab_fast_path_view_name_table[24] = +String8 rd_tab_fast_path_view_name_table[25] = { str8_lit_comp("watch"), str8_lit_comp("watch"), @@ -23,6 +23,7 @@ str8_lit_comp("watch"), str8_lit_comp("watch"), str8_lit_comp("watch"), str8_lit_comp("watch"), +str8_lit_comp("watch"), str8_lit_comp("text"), str8_lit_comp("text"), str8_lit_comp("disasm"), @@ -32,7 +33,7 @@ str8_lit_comp("color"), str8_lit_comp("geo3d"), }; -String8 rd_tab_fast_path_query_name_table[24] = +String8 rd_tab_fast_path_query_name_table[25] = { str8_lit_comp(""), str8_lit_comp("query:locals"), @@ -45,6 +46,7 @@ str8_lit_comp("query:call_stack"), str8_lit_comp("query:targets"), str8_lit_comp("query:breakpoints"), str8_lit_comp("query:watch_pins"), +str8_lit_comp("query:debug_infos"), str8_lit_comp("query:threads"), str8_lit_comp("query:processes"), str8_lit_comp("query:machines"), @@ -60,11 +62,12 @@ str8_lit_comp(""), str8_lit_comp(""), }; -RD_VocabInfo rd_vocab_info_table[352] = +RD_VocabInfo rd_vocab_info_table[358] = { {str8_lit_comp("type_view"), str8_lit_comp("type_views"), str8_lit_comp("Type View"), str8_lit_comp("Type Views"), RD_IconKind_Binoculars}, {str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline}, {str8_lit_comp("watch_pin"), str8_lit_comp("watch_pins"), str8_lit_comp("Watch Pin"), str8_lit_comp("Watch Pins"), RD_IconKind_Pin}, +{str8_lit_comp("debug_info"), str8_lit_comp("debug_infos"), str8_lit_comp("Debug Info"), str8_lit_comp("Debug Info"), RD_IconKind_Module}, {str8_lit_comp("watch"), str8_lit_comp("watches"), str8_lit_comp("Watch"), str8_lit_comp("Watches"), RD_IconKind_Binoculars}, {str8_lit_comp("view"), str8_lit_comp("views"), str8_lit_comp("View"), str8_lit_comp("Views"), RD_IconKind_Binoculars}, {str8_lit_comp("breakpoint"), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoint"), str8_lit_comp("Breakpoints"), RD_IconKind_CircleFilled}, @@ -170,6 +173,8 @@ RD_VocabInfo rd_vocab_info_table[352] = {str8_lit_comp("row_height"), str8_lit_comp(""), str8_lit_comp("Row Height"), str8_lit_comp(""), RD_IconKind_Null}, {str8_lit_comp("tab_height"), str8_lit_comp(""), str8_lit_comp("Tab Height"), str8_lit_comp(""), RD_IconKind_Null}, {str8_lit_comp("rgba"), str8_lit_comp(""), str8_lit_comp("RGBA"), str8_lit_comp(""), RD_IconKind_Palette}, +{str8_lit_comp("path"), str8_lit_comp(""), str8_lit_comp("Path"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("guid"), str8_lit_comp(""), str8_lit_comp("GUID"), str8_lit_comp(""), RD_IconKind_Null}, {str8_lit_comp("launch_and_run"), str8_lit_comp(""), str8_lit_comp("Launch and Run"), str8_lit_comp(""), RD_IconKind_Play}, {str8_lit_comp("launch_and_step_into"), str8_lit_comp(""), str8_lit_comp("Launch and Step Into"), str8_lit_comp(""), RD_IconKind_PlayStepForward}, {str8_lit_comp("kill"), str8_lit_comp(""), str8_lit_comp("Kill"), str8_lit_comp(""), RD_IconKind_X}, @@ -361,6 +366,8 @@ RD_VocabInfo rd_vocab_info_table[352] = {str8_lit_comp("clear_output"), str8_lit_comp(""), str8_lit_comp("Clear Output"), str8_lit_comp(""), RD_IconKind_Null}, {str8_lit_comp("add_watch_pin"), str8_lit_comp(""), str8_lit_comp("Add Watch Pin"), str8_lit_comp(""), RD_IconKind_Pin}, {str8_lit_comp("toggle_watch_pin"), str8_lit_comp(""), str8_lit_comp("Toggle Watch Pin"), str8_lit_comp(""), RD_IconKind_Pin}, +{str8_lit_comp("load_debug_info"), str8_lit_comp(""), str8_lit_comp("Load Debug Info"), str8_lit_comp(""), RD_IconKind_Module}, +{str8_lit_comp("unload_debug_info"), str8_lit_comp(""), str8_lit_comp("Unload Debug Info"), str8_lit_comp(""), RD_IconKind_Module}, {str8_lit_comp("add_type_view"), str8_lit_comp(""), str8_lit_comp("Add Type View"), str8_lit_comp(""), RD_IconKind_Binoculars}, {str8_lit_comp("add_file_path_map"), str8_lit_comp(""), str8_lit_comp("Add File Path Map"), str8_lit_comp(""), RD_IconKind_FileOutline}, {str8_lit_comp("edit_user_theme"), str8_lit_comp(""), str8_lit_comp("Edit User Theme"), str8_lit_comp(""), RD_IconKind_Palette}, @@ -401,6 +408,7 @@ RD_VocabInfo rd_vocab_info_table[352] = {str8_lit_comp("targets"), str8_lit_comp(""), str8_lit_comp("Targets"), str8_lit_comp(""), RD_IconKind_Target}, {str8_lit_comp("breakpoints"), str8_lit_comp(""), str8_lit_comp("Breakpoints"), str8_lit_comp(""), RD_IconKind_CircleFilled}, {str8_lit_comp("watch_pins"), str8_lit_comp(""), str8_lit_comp("Watch Pins"), str8_lit_comp(""), RD_IconKind_Pin}, +{str8_lit_comp("debug_infos"), str8_lit_comp(""), str8_lit_comp("Debug Info"), str8_lit_comp(""), RD_IconKind_Module}, {str8_lit_comp("threads"), str8_lit_comp(""), str8_lit_comp("Threads"), str8_lit_comp(""), RD_IconKind_Threads}, {str8_lit_comp("processes"), str8_lit_comp(""), str8_lit_comp("Processes"), str8_lit_comp(""), RD_IconKind_Scheduler}, {str8_lit_comp("machines"), str8_lit_comp(""), str8_lit_comp("Machines"), str8_lit_comp(""), RD_IconKind_Machine}, @@ -416,7 +424,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[25] = +RD_NameSchemaInfo rd_name_schema_info_table[26] = { {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")}, @@ -435,6 +443,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[25] = {str8_lit_comp("target"), str8_lit_comp("@row_commands(@cmd_line save_cfg_to_project, enable_cfg, launch_and_run, launch_and_step_into, duplicate_cfg, remove_cfg)\n@collection_commands(add_target)\nx:\n{\n 'label': code_string,\n 'executable': path,\n 'arguments': string,\n 'working_directory': path,\n 'entry_point': expr_string,\n 'stdout_path': @no_relativize path,\n 'stderr_path': @no_relativize path,\n 'stdin_path': @no_relativize path,\n 'environment': query,\n 'debug_subprocesses': bool,\n @no_revert @no_expand @default(0) 'enabled': bool,\n}\n")}, {str8_lit_comp("breakpoint"), str8_lit_comp("@row_commands(enable_cfg, duplicate_cfg, remove_cfg)\n@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint, add_function_breakpoint, clear_breakpoints)\nx:\n{\n 'label': code_string,\n 'condition': expr_string,\n 'source_location': path_pt,\n 'address_location': expr_string,\n 'hit_count': u64,\n 'address_range_size': @or(0, 1, 2, 4, 8) u64,\n 'break_on_write': bool,\n 'break_on_read': bool,\n 'break_on_execute': bool,\n @no_revert @no_expand @default(1) 'enabled': bool,\n}\n")}, {str8_lit_comp("watch_pin"), str8_lit_comp("@row_commands(duplicate_cfg, remove_cfg)\n@collection_commands(add_watch_pin, toggle_watch_pin)\nx:\n{\n 'expression': expr_string,\n 'source_location': path_pt,\n 'address_location': expr_string,\n}\n")}, +{str8_lit_comp("debug_info"), str8_lit_comp("@row_commands(enable_cfg, duplicate_cfg, remove_cfg)\n@collection_commands(load_debug_info)\nx:\n{\n 'path': @no_relativize path,\n @query 'guid': string,\n @no_revert @no_expand @default(1) 'enabled': bool,\n}\n")}, {str8_lit_comp("file_path_map"), str8_lit_comp("@collection_commands(add_file_path_map) @row_commands(remove_cfg) x:{'source': @no_relativize path, 'dest': @no_relativize path}")}, {str8_lit_comp("type_view"), str8_lit_comp("@collection_commands(add_type_view) @row_commands(remove_cfg) x:{'type':expr_string, 'expr':expr_string}")}, {str8_lit_comp("recent_project"), str8_lit_comp("x:{'path':path}")}, @@ -547,7 +556,7 @@ Rng1U64 rd_reg_slot_range_table[47] = {OffsetOf(RD_Regs, os_event), OffsetOf(RD_Regs, os_event) + sizeof(OS_Event *)}, }; -RD_CmdKindInfo rd_cmd_kind_info_table[245] = +RD_CmdKindInfo rd_cmd_kind_info_table[248] = { {0}, { str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), CTRL_EntityKind_Null}}, @@ -741,6 +750,8 @@ RD_CmdKindInfo rd_cmd_kind_info_table[245] = { str8_lit_comp("clear_output"), str8_lit_comp("Clears all output."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("add_watch_pin"), str8_lit_comp("Places a watch pin at a given location (file path and line number or address)."), str8_lit_comp(""), str8_lit_comp("$watch_pins,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("toggle_watch_pin"), str8_lit_comp("Places or removes a watch pin at a given location (file path and line number or address)."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("load_debug_info"), str8_lit_comp("Loads a debug info file."), str8_lit_comp(""), str8_lit_comp("$debug_infos,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("unload_debug_info"), str8_lit_comp("Unloads a debug info file."), str8_lit_comp(""), str8_lit_comp("$debug_infos,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:debug_infos"), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("add_type_view"), str8_lit_comp("Adds a new type view."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_String, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("add_file_path_map"), str8_lit_comp("Adds a new file path map."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("edit_user_theme"), str8_lit_comp("Edits the current user's theme."), str8_lit_comp("color"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_String, str8_lit_comp("query:themes"), str8_lit_comp(""), CTRL_EntityKind_Null}}, @@ -781,6 +792,7 @@ RD_CmdKindInfo rd_cmd_kind_info_table[245] = { str8_lit_comp("targets"), str8_lit_comp("Opens a Targets tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, { str8_lit_comp("breakpoints"), str8_lit_comp("Opens a Breakpoints tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, { str8_lit_comp("watch_pins"), str8_lit_comp("Opens a Watch Pins tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("debug_infos"), str8_lit_comp("Opens a Debug Info tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, { str8_lit_comp("threads"), str8_lit_comp("Opens a Threads tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, { str8_lit_comp("processes"), str8_lit_comp("Opens a Processes tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, { str8_lit_comp("machines"), str8_lit_comp("Opens a Machines tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index 0f048756..411ddb7d 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -252,6 +252,8 @@ RD_CmdKind_ListBreakpoints, RD_CmdKind_ClearOutput, RD_CmdKind_AddWatchPin, RD_CmdKind_ToggleWatchPin, +RD_CmdKind_LoadDebugInfo, +RD_CmdKind_UnloadDebugInfo, RD_CmdKind_AddTypeView, RD_CmdKind_AddFilePathMap, RD_CmdKind_EditUserTheme, @@ -292,6 +294,7 @@ RD_CmdKind_OpenCallStack, RD_CmdKind_OpenTargets, RD_CmdKind_OpenBreakpoints, RD_CmdKind_OpenWatchPins, +RD_CmdKind_OpenDebugInfos, RD_CmdKind_OpenThreads, RD_CmdKind_OpenProcesses, RD_CmdKind_OpenMachines, @@ -525,6 +528,7 @@ X(call_stack) \ X(targets) \ X(breakpoints) \ X(watch_pins) \ +X(debug_infos) \ X(threads) \ X(processes) \ X(machines) \ @@ -589,10 +593,10 @@ Z(getting_started)\ .os_event = rd_regs()->os_event,\ 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[25]; +extern String8 rd_tab_fast_path_view_name_table[25]; +extern String8 rd_tab_fast_path_query_name_table[25]; +extern RD_VocabInfo rd_vocab_info_table[358]; +extern RD_NameSchemaInfo rd_name_schema_info_table[26]; 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 f084b96d..c1023ed2 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -33,6 +33,7 @@ RD_WatchTabFastPathTable: {Targets "Targets" targets 1 Target "Displays, and allows editing of, the list of all targets."} {Breakpoints "Breakpoints" breakpoints 1 CircleFilled "Displays, and allows editing of, the list of all breakpoints."} {WatchPins "Watch Pins" watch_pins 1 Pin "Displays, and allows editing of, the list of all watch pins."} + {DebugInfos "Debug Info" debug_infos 1 Module "Displays, and allows editing of, the list of all debug info files that the debugger has loaded."} {Threads "Threads" threads 1 Threads "Displays the list of all threads in all processes to which the debugger is attached."} {Processes "Processes" processes 1 Scheduler "Displays the list of all processes to which the debugger is attached."} {Machines "Machines" machines 1 Machine "Displays the list of all machines to which the debugger is connected."} @@ -91,6 +92,7 @@ RD_VocabTable: {type_view _ "Type View" _ Binoculars } {file_path_map _ "File Path Map" _ FileOutline } {watch_pin _ "Watch Pin" _ Pin } + {debug_info _ "Debug Info" "Debug Info" Module } {watch watches "Watch" "Watches" Binoculars } {view _ "View" _ Binoculars } {breakpoint _ "Breakpoint" _ CircleFilled } @@ -196,6 +198,8 @@ RD_VocabTable: {row_height "" "Row Height" "" Null } {tab_height "" "Tab Height" "" Null } {rgba "" "RGBA" "" Palette } + {path "" "Path" "" FileOutline } + {guid "" "GUID" "" Null } } @struct RD_VocabInfo: @@ -657,6 +661,21 @@ RD_VocabTable: ```, } + //- rjf: debug infos + { + debug_info, + ``` + @row_commands(enable_cfg, duplicate_cfg, remove_cfg) + @collection_commands(load_debug_info) + x: + { + 'path': @no_relativize path, + @query 'guid': string, + @no_revert @no_expand @default(1) 'enabled': bool, + } + ```, + } + //- rjf: file path maps { file_path_map, @@ -1044,6 +1063,10 @@ RD_CmdTable: // | | | | {AddWatchPin 1 1 0 0 "" Expr null Nil Null 0 0 0 0 1 1 1 Pin "add_watch_pin" "Add Watch Pin" "Places a watch pin at a given location (file path and line number or address)." "" "$watch_pins," } {ToggleWatchPin 1 0 0 0 "" Expr null Nil Null 0 0 0 0 1 1 1 Pin "toggle_watch_pin" "Toggle Watch Pin" "Places or removes a watch pin at a given location (file path and line number or address)." "" "" } + //- rjf: debug infos + {LoadDebugInfo 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 Module "load_debug_info" "Load Debug Info" "Loads a debug info file." "" "$debug_infos," } + {UnloadDebugInfo 1 1 0 0 "query:debug_infos" Cfg null Nil Null 0 0 0 0 1 1 1 Module "unload_debug_info" "Unload Debug Info" "Unloads a debug info file." "" "$debug_infos," } + //- rjf: type views {AddTypeView 0 0 0 0 "" String null Nil Null 0 0 0 0 0 0 0 Binoculars "add_type_view" "Add Type View" "Adds a new type view." "" "" } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 32deec8f..171689c4 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -789,7 +789,7 @@ rd_eval_space_read(E_Space space, void *out, Rng1U64 range) //- rjf: meta-config reads case RD_EvalSpaceKind_MetaCfg: { - // rjf: unpack cfg + //- rjf: unpack cfg CFG_Node *root_cfg = rd_cfg_from_eval_space(space); String8 child_key = e_string_from_id(space.u64s[1]); CFG_Node *cfg = root_cfg; @@ -798,54 +798,85 @@ rd_eval_space_read(E_Space space, void *out, Rng1U64 range) cfg = cfg_node_child_from_string(root_cfg, child_key); } - // rjf: determine data to read from, depending on child type in schema + //- rjf: determine data to read from, depending on child type in schema String8 read_data = {0}; if(child_key.size != 0) { - 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; + // rjf: get schemas for the accessed child MD_Node *child_schema = &md_nil_node; - for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) + MD_Node *expr_child_schema = &md_nil_node; { - child_schema = md_child_from_string(n->v, child_key, 0); - if(child_schema != &md_nil_node) + MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, root_cfg->string); + for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) { - expr_child_schema = md_child_from_string(n->v, str8_lit("expression"), 0); + child_schema = md_child_from_string(n->v, child_key, 0); + if(child_schema != &md_nil_node) + { + expr_child_schema = md_child_from_string(n->v, str8_lit("expression"), 0); + } } } String8 child_type_name = child_schema->first->string; + + // rjf: get value string (or default fallback) + String8 value_string = cfg->first->string; + if(value_string.size == 0) + { + value_string = md_tag_from_string(child_schema, str8_lit("default"), 0)->first->string; + } + + // rjf: if this is an override child to a parent, fall back on defaults from parents + if(value_string.size == 0 && !md_node_is_nil(md_tag_from_string(child_schema, str8_lit("override"), 0))) + { + for(CFG_Node *parent = root_cfg->parent; parent != &cfg_nil_node; parent = parent->parent) + { + 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; + } + value_string = rd_default_setting_from_names(parent->string, child_key); + if(value_string.size != 0) + { + break; + } + } + } + + // rjf: if this is a query -> compute the value string based on query path + if(md_node_has_tag(child_schema, str8_lit("query"), 0)) + { + // TODO(rjf): this needs to be replaced by hooks + if(str8_match(child_schema->string, str8_lit("guid"), 0)) + { + Access *access = access_open(); + String8 path = rd_path_from_cfg(root_cfg); + U64 timestamp = 0; + try_u64_from_str8_c_rules(cfg_node_child_from_string(root_cfg, str8_lit("timestamp"))->first->string, ×tamp); + DI_Key key = di_key_from_path_timestamp(path, timestamp); + RDI_Parsed *rdi = di_rdi_from_key(access, key, 0, 0); + RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); + Guid guid = {0}; + MemoryCopy(&guid, &tli->guid, Min(sizeof guid, sizeof tli->guid)); + value_string = string_from_guid(scratch.arena, guid); + access_close(access); + } + } + + // rjf: textual data if(str8_match(child_type_name, str8_lit("path"), 0) || str8_match(child_type_name, str8_lit("path_pt"), 0) || str8_match(child_type_name, str8_lit("code_string"), 0) || str8_match(child_type_name, str8_lit("expr_string"), 0) || str8_match(child_type_name, str8_lit("string"), 0)) { - read_data = cfg->first->string; + read_data = value_string; } + + // rjf: non-textual data else { - String8 value_string = cfg->first->string; - if(value_string.size == 0) - { - value_string = md_tag_from_string(child_schema, str8_lit("default"), 0)->first->string; - } - if(value_string.size == 0 && !md_node_is_nil(md_tag_from_string(child_schema, str8_lit("override"), 0))) - { - for(CFG_Node *parent = root_cfg->parent; parent != &cfg_nil_node; parent = parent->parent) - { - 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; - } - value_string = rd_default_setting_from_names(parent->string, child_key); - if(value_string.size != 0) - { - break; - } - } - } E_Key parent_key = {0}; if(expr_child_schema != &md_nil_node && child_schema != expr_child_schema) { @@ -2224,11 +2255,22 @@ rd_view_ui(Rng2F32 rect) { default: { - 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); - U64 voff = ctrl_voff_from_vaddr(module, vaddr); + U64 voff = 0; + DI_Key dbgi_key = {0}; + if(eval.space.kind == CTRL_EvalSpaceKind_Entity) + { + 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); + dbgi_key = ctrl_dbgi_key_from_module(module); + voff = ctrl_voff_from_vaddr(module, vaddr); + } + else + { + voff = eval.value.u64; + E_DbgInfo *dbg_info = e_dbg_info_from_type_key(eval.irtree.type_key); + dbgi_key = dbg_info->dbgi_key; + } { Access *access = access_open(); RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); @@ -3998,7 +4040,9 @@ rd_view_ui(Rng2F32 rect) // rjf: apply type note if(!(cell_info.flags & RD_WatchCellFlag_NoEval) && - cell->eval.space.kind == CTRL_EvalSpaceKind_Entity && + e_type_kind_from_key(cell->eval.irtree.type_key) != E_TypeKind_Null && + (cell->eval.space.kind == E_SpaceKind_Null || + 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) @@ -5176,6 +5220,19 @@ rd_window_frame(void) cfg_node_release(rd_state->cfg, cfg_node_child_from_string(window, str8_lit("maximized"))); } + //- rjf: DPI changes -> xform font size / window size + F32 dpi = os_dpi_from_window(ws->os); + if(dpi != ws->last_dpi) + { + fnt_reset(); + F32 current_font_size = rd_font_size(); + F32 new_font_size = current_font_size * (dpi / ws->last_dpi); + new_font_size = Clamp(6.f, new_font_size, 72.f); + CFG_Node *font_size_cfg = cfg_node_child_from_string_or_alloc(rd_state->cfg, window, str8_lit("font_size")); + cfg_node_new_replacef(rd_state->cfg, font_size_cfg, "%I64u", (U64)new_font_size); + ws->last_dpi = dpi; + } + //- rjf: commit position Rng2F32 window_rect = os_rect_from_window(ws->os); if(!is_fullscreen && !is_maximized && !is_minimized) @@ -5690,75 +5747,73 @@ rd_window_frame(void) //////////////////////////// //- rjf: @window_ui_part drop-completion context menu // - if(ws->drop_completion_paths.node_count != 0) + if(ws->top_drop_completion_task != 0) { + RD_DropCompletionTask *task = ws->top_drop_completion_task; + B32 done = 0; UI_CtxMenu(rd_state->drop_completion_key) UI_PrefWidth(ui_em(40.f, 1.f)) UI_TagF("implicit") { - UI_TagF("weak") - for(String8Node *n = ws->drop_completion_paths.first; n != 0; n = n->next) + // rjf: file names + UI_TagF("weak") UI_Row UI_Padding(ui_em(1.25f, 1.f)) { - UI_Row UI_Padding(ui_em(1.f, 1.f)) + String8List strings = {0}; + U64 idx = 0; + for(String8Node *n = task->paths.first; n != 0 && idx < 20; n = n->next, idx += 1) { - UI_PrefWidth(ui_em(2.f, 1.f)) RD_Font(RD_FontSlot_Icons) ui_label(rd_icon_kind_text_table[RD_IconKind_FileOutline]); - UI_PrefWidth(ui_text_dim(10, 1)) ui_label(n->string); + str8_list_push(scratch.arena, &strings, str8_skip_last_slash(n->string)); + if(idx+1 == 20) + { + str8_list_push(scratch.arena, &strings, str8_lit("...")); + } } + StringJoin join = {.sep = str8_lit(", ")}; + String8 string = str8_list_join(scratch.arena, &strings, &join); + UI_PrefWidth(ui_pct(1, 0)) ui_label(string); } - ui_divider(ui_em(1.f, 1.f)); - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Target, 0, "Add File%s As Target%s", - (ws->drop_completion_paths.node_count > 1) ? "s" : "", - (ws->drop_completion_paths.node_count > 1) ? "s" : ""))) + + // rjf: option to add EXEs as targets + if(task->exe) { - for(String8Node *n = ws->drop_completion_paths.first; n != 0; n = n->next) + if(ui_clicked(rd_icon_buttonf(RD_IconKind_Target, 0, "Add as target%s", (task->paths.node_count > 1) ? "s" : ""))) { - rd_cmd(RD_CmdKind_AddTarget, .file_path = n->string); - } - ui_ctx_menu_close(); - } - if(ws->drop_completion_paths.node_count == 1) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Play, 0, "Add File%s As Target%s And Run", - (ws->drop_completion_paths.node_count > 1) ? "s" : "", - (ws->drop_completion_paths.node_count > 1) ? "s" : ""))) - { - for(String8Node *n = ws->drop_completion_paths.first; n != 0; n = n->next) + for(String8Node *n = task->paths.first; n != 0; n = n->next) { rd_cmd(RD_CmdKind_AddTarget, .file_path = n->string); } - CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); - if(processes.count != 0) - { - rd_cmd(RD_CmdKind_KillAll); - } - rd_cmd(RD_CmdKind_Run); - ui_ctx_menu_close(); + done = 1; } } - if(ws->drop_completion_paths.node_count == 1) + + // rjf: option to load files as debug info + if(task->dbg) { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_StepInto, 0, "Add File%s As Target%s And Step Into", - (ws->drop_completion_paths.node_count > 1) ? "s" : "", - (ws->drop_completion_paths.node_count > 1) ? "s" : ""))) + if(ui_clicked(rd_icon_buttonf(RD_IconKind_Module, 0, "Load as debug info"))) { - for(String8Node *n = ws->drop_completion_paths.first; n != 0; n = n->next) + for(String8Node *n = task->paths.first; n != 0; n = n->next) { - rd_cmd(RD_CmdKind_AddTarget, .file_path = n->string); + rd_cmd(RD_CmdKind_LoadDebugInfo, .file_path = n->string); } - CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); - if(processes.count != 0) - { - rd_cmd(RD_CmdKind_KillAll); - } - rd_cmd(RD_CmdKind_StepInto); - ui_ctx_menu_close(); + done = 1; } } - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Target, 0, "View File%s", - (ws->drop_completion_paths.node_count > 1) ? "s" : ""))) + + // rjf: option to just open & view the file contents + if(ui_clicked(rd_icon_buttonf(RD_IconKind_FileOutline, 0, "View file%s contents", (task->paths.node_count > 1) ? "s'" : ""))) { - for(String8Node *n = ws->drop_completion_paths.first; n != 0; n = n->next) + for(String8Node *n = task->paths.first; n != 0; n = n->next) { rd_cmd(RD_CmdKind_Open, .file_path = n->string); } + done = 1; + } + } + + // rjf: pop task, close context menu if needed, when done + if(done) + { + SLLStackPop(ws->top_drop_completion_task); + if(ws->top_drop_completion_task == 0) + { ui_ctx_menu_close(); } } @@ -8292,23 +8347,45 @@ rd_window_frame(void) { B32 need_drop_completion = 0; arena_clear(ws->drop_completion_arena); - MemoryZeroStruct(&ws->drop_completion_paths); + ws->top_drop_completion_task = 0; + ws->drop_completion_panel = panel->cfg->id; + String8List exe_paths = {0}; + String8List dbg_paths = {0}; for(String8Node *n = evt->paths.first; n != 0; n = n->next) { Temp scratch = scratch_begin(0, 0); String8 path = n->string; - if(str8_match(str8_skip_last_dot(path), str8_lit("exe"), StringMatchFlag_CaseInsensitive)) + String8 ext = str8_skip_last_dot(path); + if(str8_match(ext, str8_lit("exe"), StringMatchFlag_CaseInsensitive)) { - str8_list_push(ws->drop_completion_arena, &ws->drop_completion_paths, push_str8_copy(ws->drop_completion_arena, path)); - need_drop_completion = 1; + str8_list_push(ws->drop_completion_arena, &exe_paths, str8_copy(ws->drop_completion_arena, path)); + } + else if(str8_match(ext, str8_lit("pdb"), StringMatchFlag_CaseInsensitive) || + str8_match(ext, str8_lit("rdi"), StringMatchFlag_CaseInsensitive)) + { + str8_list_push(ws->drop_completion_arena, &dbg_paths, str8_copy(ws->drop_completion_arena, path)); } else { - rd_cmd(RD_CmdKind_Open, .file_path = path); + rd_cmd(RD_CmdKind_Open, .file_path = path, .panel = panel->cfg->id); } scratch_end(scratch); } - if(need_drop_completion) + if(dbg_paths.node_count != 0) + { + RD_DropCompletionTask *t = push_array(ws->drop_completion_arena, RD_DropCompletionTask, 1); + SLLStackPush(ws->top_drop_completion_task, t); + t->dbg = 1; + t->paths = dbg_paths; + } + if(exe_paths.node_count != 0) + { + RD_DropCompletionTask *t = push_array(ws->drop_completion_arena, RD_DropCompletionTask, 1); + SLLStackPush(ws->top_drop_completion_task, t); + t->exe = 1; + t->paths = exe_paths; + } + if(ws->top_drop_completion_task != 0) { ui_ctx_menu_open(rd_state->drop_completion_key, ui_key_zero(), evt->pos); } @@ -8547,7 +8624,7 @@ rd_window_frame(void) } // rjf: soft circle around mouse - if(box->hot_t > 0.01f) DR_ClipScope(box->rect) + if(box->hot_t > 0.01f) DR_ClipScope(intersect_2f32(box->rect, dr_top_clip())) { Vec4F32 color = hover_color; color.w *= 0.02f; @@ -9297,7 +9374,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, e_base_ctx->primary_module->dbgi_key, 0); + DI_Match match = di_match_from_string(string, 0, di_key_zero(), 0); RDI_SectionKind section_kind = match.section_kind; mapped = 1; switch(section_kind) @@ -9935,6 +10012,12 @@ rd_init(CmdLine *cmdln) cfg_node_new(rd_state->cfg, cfg_node_root(), str8_lit("transient")); } + // rjf: set up loaded debug info cache + { + rd_state->loaded_dbg_info_slots_count = 4096; + rd_state->loaded_dbg_info_slots = push_array(arena, RD_LoadedDbgInfoSlot, rd_state->loaded_dbg_info_slots_count); + } + // rjf: set up window cache { rd_state->window_state_slots_count = 64; @@ -10028,7 +10111,14 @@ rd_init(CmdLine *cmdln) String8List passthrough_args_list = {0}; for(String8Node *n = target_args.first->next; n != 0; n = n->next) { - str8_list_push(scratch.arena, &passthrough_args_list, n->string); + if(str8_find_needle(n->string, 0, str8_lit(" "), 0) < n->string.size) + { + str8_list_pushf(scratch.arena, &passthrough_args_list, "\"%S\"", n->string); + } + else + { + str8_list_push(scratch.arena, &passthrough_args_list, n->string); + } } StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; arguments_string = str8_list_join(scratch.arena, &passthrough_args_list, &join); @@ -10290,6 +10380,76 @@ rd_frame(void) scratch_end(scratch); } + ////////////////////////////// + //- rjf: apply debug info config trees -> loaded debug info cache + // + { + U64 current_update_tick_idx = update_tick_idx(); + + //- rjf: for each debug info config, reflect in cache - open if needed + CFG_NodePtrList dbg_infos = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("debug_info")); + for EachNode(n, CFG_NodePtrNode, dbg_infos.first) + { + // rjf: unpack debug info config + CFG_Node *di = n->v; + String8 path = rd_path_from_cfg(di); + CFG_Node *di_timestamp = cfg_node_child_from_string(di, str8_lit("timestamp")); + U64 timestamp = 0; + try_u64_from_str8_c_rules(di_timestamp->first->string, ×tamp); + DI_Key key = di_key_from_path_timestamp(path, timestamp); + + // rjf: touch in cache + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%rd_state->loaded_dbg_info_slots_count; + RD_LoadedDbgInfoSlot *slot = &rd_state->loaded_dbg_info_slots[slot_idx]; + RD_LoadedDbgInfoNode *node = 0; + for(RD_LoadedDbgInfoNode *n = slot->first; n != 0; n = n->hash_next) + { + if(di_key_match(key, n->key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = rd_state->free_loaded_dbg_info_node; + if(node) + { + SLLStackPop_N(rd_state->free_loaded_dbg_info_node, hash_next); + } + else + { + node = push_array(rd_state->arena, RD_LoadedDbgInfoNode, 1); + } + DLLPushBack_NP(slot->first, slot->last, node, hash_next, hash_prev); + node->key = key; + di_open(key); + } + node->last_tick_idx_touched = current_update_tick_idx; + DLLRemove_NP(rd_state->loaded_dbg_info_lru_first, rd_state->loaded_dbg_info_lru_last, node, lru_next, lru_prev); + DLLPushBack_NP(rd_state->loaded_dbg_info_lru_first, rd_state->loaded_dbg_info_lru_last, node, lru_next, lru_prev); + } + + //- rjf: iterate least-recently-used loaded debug infos - if any have not been updated this tick, + // then evict + for(RD_LoadedDbgInfoNode *n = rd_state->loaded_dbg_info_lru_first, *next = 0; n != 0; n = next) + { + next = n->lru_next; + if(n->last_tick_idx_touched >= current_update_tick_idx) + { + break; + } + U64 hash = u64_hash_from_str8(str8_struct(&n->key)); + U64 slot_idx = hash%rd_state->loaded_dbg_info_slots_count; + RD_LoadedDbgInfoSlot *slot = &rd_state->loaded_dbg_info_slots[slot_idx]; + DLLRemove_NP(rd_state->loaded_dbg_info_lru_first, rd_state->loaded_dbg_info_lru_last, n, lru_next, lru_prev); + DLLRemove_NP(slot->first, slot->last, n, hash_next, hash_prev); + SLLStackPush_N(rd_state->free_loaded_dbg_info_node, n, hash_next); + di_close(n->key, 0); + } + } + ////////////////////////////// //- rjf: garbage collect untouched immediate cfg trees // @@ -10756,7 +10916,56 @@ rd_frame(void) ProfScope("loop - consume events in core, tick engine, and repeat") for(U64 cmd_process_loop_idx = 0; cmd_process_loop_idx < 3; cmd_process_loop_idx += 1) { //////////////////////////// - //- rjf: unpack eval-dependent info + //- rjf: gather all unique debug info keys, build map + // + typedef struct DbgInfoNode DbgInfoNode; + struct DbgInfoNode + { + DbgInfoNode *hash_next; + DbgInfoNode *order_next; + DI_Key key; + U64 idx; + }; + U64 dbg_info_slots_count = 4096; + DbgInfoNode **dbg_info_slots = push_array(scratch.arena, DbgInfoNode *, dbg_info_slots_count); + DbgInfoNode *first_dbg_info = 0; + DbgInfoNode *last_dbg_info = 0; + U64 dbg_infos_count = 0; + { + CFG_NodePtrList dbg_infos = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("debug_info")); + for EachNode(n, CFG_NodePtrNode, dbg_infos.first) + { + CFG_Node *di = n->v; + String8 path = rd_path_from_cfg(di); + CFG_Node *timestamp_node = cfg_node_child_from_string(di, str8_lit("timestamp")); + U64 timestamp = 0; + try_u64_from_str8_c_rules(timestamp_node->first->string, ×tamp); + DI_Key key = di_key_from_path_timestamp(path, timestamp); + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%dbg_info_slots_count; + DbgInfoNode *node = 0; + for(DbgInfoNode *n = dbg_info_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(di_key_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(scratch.arena, DbgInfoNode, 1); + SLLStackPush_N(dbg_info_slots[slot_idx], node, hash_next); + SLLQueuePush_N(first_dbg_info, last_dbg_info, node, order_next); + node->key = key; + node->idx = dbg_infos_count; + dbg_infos_count += 1; + } + } + } + + //////////////////////////// + //- rjf: unpack basic evaluation context // ProfBegin("unpack eval-dependent info"); CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process); @@ -10767,32 +10976,67 @@ rd_frame(void) CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); U64 tls_root_vaddr = ctrl_tls_root_vaddr_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); + ProfEnd(); + + //////////////////////////// + //- rjf: produce all debug infos + // + U64 eval_dbg_infos_count = Max(1, dbg_infos_count); + E_DbgInfo *eval_dbg_infos = push_array(scratch.arena, E_DbgInfo, eval_dbg_infos_count); + E_DbgInfo *eval_dbg_infos_primary = &eval_dbg_infos[0]; + MemoryCopyStruct(eval_dbg_infos_primary, &e_dbg_info_nil); + { + U64 idx = 0; + for(DbgInfoNode *n = first_dbg_info; n != 0; n = n->order_next) + { + eval_dbg_infos[idx].dbgi_key = n->key; + eval_dbg_infos[idx].rdi = di_rdi_from_key(rd_state->frame_access, n->key, 0, 0); + idx += 1; + } + } + + //////////////////////////// + //- rjf: produce all eval modules + // CTRL_EntityArray all_modules = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Module); U64 eval_modules_count = Max(1, all_modules.count); E_Module *eval_modules = push_array(scratch.arena, E_Module, eval_modules_count); 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}; 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); - 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), CTRL_EvalSpaceKind_Entity); + + // rjf: dbgi key -> eval dbg info num + U32 dbg_info_num = 0; + { + U64 hash = u64_hash_from_str8(str8_struct(&dbgi_key)); + U64 slot_idx = hash%dbg_info_slots_count; + for(DbgInfoNode *n = dbg_info_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(di_key_match(n->key, dbgi_key)) + { + dbg_info_num = n->idx+1; + break; + } + } + } + + // rjf: fill + eval_modules[eval_module_idx].vaddr_range = m->vaddr_range; + eval_modules[eval_module_idx].arch = m->arch; + eval_modules[eval_module_idx].dbg_info_num = dbg_info_num; + 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]; - primary_dbgi_key = dbgi_key; + eval_dbg_infos_primary = (0 < dbg_info_num && dbg_info_num <= eval_dbg_infos_count) ? &eval_dbg_infos[dbg_info_num-1] : &e_dbg_info_nil; } } } - ProfEnd(); //////////////////////////// //- rjf: begin evaluation @@ -10813,6 +11057,11 @@ rd_frame(void) ctx->thread_arch = thread->arch; ctx->thread_unwind_count = unwind_count; + //- rjf: fill debug infos + ctx->dbg_infos = eval_dbg_infos; + ctx->dbg_infos_count = eval_dbg_infos_count; + ctx->primary_dbg_info = eval_dbg_infos_primary; + //- rjf: fill modules ctx->modules = eval_modules; ctx->modules_count = eval_modules_count; @@ -10939,6 +11188,7 @@ rd_frame(void) str8_lit("breakpoint"), str8_lit("watch_pin"), str8_lit("target"), + str8_lit("debug_info"), str8_lit("file_path_map"), str8_lit("type_view"), str8_lit("recent_project"), @@ -11281,6 +11531,18 @@ rd_frame(void) .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(cfgs_slice), .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(cfgs_slice), })); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("environment"), + e_type_key_cons(.kind = E_TypeKind_Set, + .name = str8_lit("environment"), + .irext = E_TYPE_IREXT_FUNCTION_NAME(environment), + .access = E_TYPE_ACCESS_FUNCTION_NAME(environment), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(environment), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(environment), + .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment), + .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(environment), + })); } //- rjf: add macro for collections with specific lookup rules (but no unique id rules) @@ -11588,8 +11850,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(eval_base_ctx->primary_dbg_info->dbgi_key, rip_voff); + ctx->member_map = d_query_cached_member_map_from_dbgi_key_voff(eval_base_ctx->primary_dbg_info->dbgi_key, rip_voff); ctx->macro_map = macro_map; ctx->auto_hook_map = auto_hook_map; } @@ -11611,7 +11873,7 @@ rd_frame(void) ctx->tls_base = push_array(scratch.arena, U64, 1); ctx->tls_base[0] = d_query_cached_tls_base_vaddr_from_process_root_rip(process, tls_root_vaddr, rip_vaddr); } - e_select_interpret_ctx(interpret_ctx, eval_modules_primary->rdi, rip_voff); + e_select_interpret_ctx(interpret_ctx, eval_dbg_infos_primary->rdi, rip_voff); //////////////////////////// //- rjf: evaluate unpacked settings (must be used earlier than this point in the frame, @@ -13663,7 +13925,15 @@ rd_frame(void) DI_Key voff_dbgi_key = {0}; if(!name_resolved) { - DI_Match match = di_match_from_string(name, 0, e_base_ctx->primary_module->dbgi_key, 0); + DI_Match match = {0}; + if(match.idx == 0) + { + match = di_match_from_string(name, 0, e_base_ctx->primary_dbg_info->dbgi_key, rd_state->frame_eval_memread_endt_us); + } + if(match.idx == 0) + { + match = di_match_from_string(name, 0, di_key_zero(), rd_state->frame_eval_memread_endt_us); + } if(match.section_kind == RDI_SectionKind_Procedures) { Access *access = access_open(); @@ -14792,6 +15062,21 @@ rd_frame(void) } }break; + //- rjf: debug infos + case RD_CmdKind_LoadDebugInfo: + { + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); + CFG_Node *di = cfg_node_new(rd_state->cfg, project, str8_lit("debug_info")); + CFG_Node *path = cfg_node_new(rd_state->cfg, di, str8_lit("path")); + cfg_node_new(rd_state->cfg, path, rd_regs()->file_path); + }break; + case RD_CmdKind_UnloadDebugInfo: + { + CFG_Node *di = cfg_node_from_id(rd_regs()->cfg); + CFG_Node *path = cfg_node_child_from_string(di, str8_lit("path")); + cfg_node_release(rd_state->cfg, di); + }break; + //- rjf: type views case RD_CmdKind_AddTypeView: { @@ -15877,6 +16162,43 @@ rd_frame(void) switch(evt->kind) { default:{}break; + case D_EventKind_ModuleLoad: + { + CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, evt->module); + CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + String8 new_path = debug_info_path->string; + if(new_path.size != 0 && os_file_path_exists(new_path)) + { + CFG_NodePtrList dbg_infos = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("debug_info")); + B32 path_found = 0; + CFG_Node *found_di = &cfg_nil_node; + for EachNode(n, CFG_NodePtrNode, dbg_infos.first) + { + CFG_Node *di = n->v; + String8 path = rd_path_from_cfg(di); + if(str8_match(path, new_path, 0)) + { + path_found = 1; + found_di = di; + break; + } + } + if(!path_found) + { + CFG_Node *project = cfg_node_child_from_string(cfg_node_root(), str8_lit("project")); + CFG_Node *di = cfg_node_new(rd_state->cfg, project, str8_lit("debug_info")); + CFG_Node *path_root = cfg_node_new(rd_state->cfg, di, str8_lit("path")); + CFG_Node *timestamp_root = cfg_node_new(rd_state->cfg, di, str8_lit("timestamp")); + cfg_node_new(rd_state->cfg, path_root, new_path); + cfg_node_newf(rd_state->cfg, timestamp_root, "%I64u", debug_info_path->timestamp); + } + else + { + CFG_Node *timestamp_root = cfg_node_child_from_string_or_alloc(rd_state->cfg, found_di, str8_lit("timestamp")); + cfg_node_new_replacef(rd_state->cfg, timestamp_root, "%I64u", debug_info_path->timestamp); + } + } + }break; case D_EventKind_ProcessEnd: if(rd_state->quit_after_success) { @@ -16251,6 +16573,19 @@ rd_frame(void) U64 frame_time_us = end_time_us-begin_time_us; rd_state->frame_time_us_history[rd_state->frame_index%ArrayCount(rd_state->frame_time_us_history)] = frame_time_us; + ////////////////////////////// + //- rjf: [windows] clear pages from working set shortly after startup, many of which will not be needed + // +#if OS_WINDOWS + if(di_load_count() < 50) + { + if(rd_state->frame_index == 15) ProfScope("SetProcessWorkingSetSize") + { + SetProcessWorkingSetSize(GetCurrentProcess(), max_U64, max_U64); + } + } +#endif + ////////////////////////////// //- rjf: bump frame time counters // @@ -16287,16 +16622,6 @@ rd_frame(void) } } - ////////////////////////////// - //- rjf: [windows] clear pages from working set shortly after startup, many of which will not be needed - // -#if OS_WINDOWS - if(rd_state->frame_index == 10) - { - SetProcessWorkingSetSize(GetCurrentProcess(), max_U64, max_U64); - } -#endif - rd_state->frame_depth -= 1; scratch_end(scratch); ProfEnd(); diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index c18d216d..56f5b803 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -258,6 +258,16 @@ RD_FontSlot; //////////////////////////////// //~ rjf: Per-Window State +typedef struct RD_DropCompletionTask RD_DropCompletionTask; +struct RD_DropCompletionTask +{ + RD_DropCompletionTask *next; + B32 exe; + B32 dbg; + B32 cfg; + String8List paths; +}; + typedef struct RD_WindowState RD_WindowState; struct RD_WindowState { @@ -298,7 +308,8 @@ struct RD_WindowState // rjf: drop-completion state Arena *drop_completion_arena; - String8List drop_completion_paths; + CFG_ID drop_completion_panel; + RD_DropCompletionTask *top_drop_completion_task; // rjf: query state B32 query_is_active; @@ -343,6 +354,24 @@ struct RD_WindowStateSlot //////////////////////////////// //~ rjf: Main Per-Process Graphical State +typedef struct RD_LoadedDbgInfoNode RD_LoadedDbgInfoNode; +struct RD_LoadedDbgInfoNode +{ + RD_LoadedDbgInfoNode *hash_next; + RD_LoadedDbgInfoNode *hash_prev; + RD_LoadedDbgInfoNode *lru_next; + RD_LoadedDbgInfoNode *lru_prev; + DI_Key key; + U64 last_tick_idx_touched; +}; + +typedef struct RD_LoadedDbgInfoSlot RD_LoadedDbgInfoSlot; +struct RD_LoadedDbgInfoSlot +{ + RD_LoadedDbgInfoNode *first; + RD_LoadedDbgInfoNode *last; +}; + typedef struct RD_AmbiguousPathNode RD_AmbiguousPathNode; struct RD_AmbiguousPathNode { @@ -480,6 +509,13 @@ struct RD_State CFG_State *cfg; CFG_SchemaTable *cfg_schema_table; + // rjf: loaded debug info cache + U64 loaded_dbg_info_slots_count; + RD_LoadedDbgInfoSlot *loaded_dbg_info_slots; + RD_LoadedDbgInfoNode *loaded_dbg_info_lru_first; + RD_LoadedDbgInfoNode *loaded_dbg_info_lru_last; + RD_LoadedDbgInfoNode *free_loaded_dbg_info_node; + // rjf: window state cache U64 window_state_slots_count; RD_WindowStateSlot *window_state_slots; diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index f060d482..7d8237b0 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -294,38 +294,40 @@ E_TYPE_ACCESS_FUNCTION_DEF(schema) 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; + B32 is_query_child = md_node_has_tag(child_schema, str8_lit("query"), 0); + E_TypeFlags type_flags = (!!is_query_child * E_TypeFlag_IsNotEditable); if(0){} //- rjf: ctrl entity members else if(entity != &ctrl_entity_nil && str8_match(child_schema->string, str8_lit("label"), 0)) { - child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), entity->string.size, E_TypeFlag_IsCodeText); + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), entity->string.size, type_flags|E_TypeFlag_IsCodeText); } else if(entity != &ctrl_entity_nil && str8_match(child_schema->string, str8_lit("exe"), 0)) { - child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), entity->string.size, E_TypeFlag_IsPathText); + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), entity->string.size, type_flags|E_TypeFlag_IsPathText); } else if(entity != &ctrl_entity_nil && str8_match(child_schema->string, str8_lit("dbg"), 0)) { CTRL_Entity *dbg = ctrl_entity_child_from_kind(entity, CTRL_EntityKind_DebugInfoPath); - child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), dbg->string.size, E_TypeFlag_IsPathText); + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), dbg->string.size, type_flags|E_TypeFlag_IsPathText); } //- rjf: cfg members else if(str8_match(child_schema->first->string, str8_lit("code_string"), 0) || str8_match(child_schema->first->string, str8_lit("expr_string"), 0)) { - child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, E_TypeFlag_IsCodeText); + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, type_flags|E_TypeFlag_IsCodeText); } else if(str8_match(child_schema->first->string, str8_lit("path"), 0) || str8_match(child_schema->first->string, str8_lit("path_pt"), 0)) { - child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, E_TypeFlag_IsPathText); + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, type_flags|E_TypeFlag_IsPathText); } else if(str8_match(child_schema->first->string, str8_lit("string"), 0)) { - child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, E_TypeFlag_IsPlainText); + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, type_flags|E_TypeFlag_IsPlainText); } //- rjf: catchall cases diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 956241f1..f633614c 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -14,20 +14,19 @@ // [ ] list of all tabs in palette // [ ] u64 + (ptr - ptr) seems to produce unexpected results - double check with C rules? // +//- flow notes +// [ ] "skip breakpoint, run to source", when stopped at a non-source location +// [ ] adjust menu bar rendering when not focused +// [ ] treat int 0x29 similarly to int3 +// [ ] auto_step, launching terminal, terminal steals focus from debugger... +// //- memory view -// [ ] have smaller visible range than entire memory -// space, within some bounds (e.g. 64KB) -// [ ] dynamically expand memory space, based on -// scrolling +// [ ] have smaller visible range than entire memory space, within some bounds (e.g. 64KB) +// [ ] dynamically expand memory space, based on scrolling // [ ] fix clicking through occluded panels etc. // [ ] disambiguate . character in ASCII columns // [ ] fix type intepretations of cursor in bottom pane // -//- bug fixes -// [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? -// //- watch improvements // [ ] *ALL* expressions in watch windows need to be editable. // @@ -113,7 +112,6 @@ // [ ] 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 @@ -149,13 +147,6 @@ // //- late-conversion performance improvements // [ ] live++ investigations - ctrl+alt+f11 in UE? -// [x] investigate wide-conversion performance -// [x] oversubscribing cores? -// [x] conversion crashes? -// -//- memory usage improvements -// [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 // [ ] search-in-all-files @@ -183,20 +174,6 @@ // [ ] font cache eviction (both for font tags, closing fp handles, and // rasterizations) -//////////////////////////////// -//~ rjf: Recently Completed Task Log -// -// [x] if a breakpoint matches the entry point's starting address, its hit count -// is not correctly incremented. -// [x] output: add option for scroll-to-bottom - ensure this shows up in universal ctx menu -// [x] auto-annotations for non-locals -// [x] []string being sized by [0], due to `.` applying to first ^string -// [x] process memory cache sometimes is not correctly updating - best repro -// case so far is (for some reason?) only hover evaluation - only spotted -// on laptop in debug builds. g0 ctrl_bindings.bindings initialization. -// [x] evaluate `foo.bar` symbol names without escape hatch? -// [x] fastpath lookup to determine debug info relevance? - //////////////////////////////// //~ rjf: Build Options diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index b4af8506..4d039d03 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -1251,9 +1251,6 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe CTRL_Entity *selected_thread_process = ctrl_entity_ancestor_from_kind(selected_thread, CTRL_EntityKind_Process); U64 selected_thread_rip_unwind_vaddr = d_query_cached_rip_from_thread_unwind(selected_thread, rd_regs()->unwind_count); CTRL_Entity *selected_thread_module = ctrl_module_from_process_vaddr(selected_thread_process, selected_thread_rip_unwind_vaddr); - F32 selected_thread_alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "###selected_thread_alive_t_%p", selected_thread), 1.f); - F32 selected_thread_module_alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "###selected_thread_module_alive_t_%p", selected_thread_module), 1.f); - F32 selected_thread_arch_alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "###selected_thread_arch_alive_t_%i", selected_thread->arch), 1.f); CTRL_Event stop_event = d_ctrl_last_stop_event(); CTRL_Entity *stopper_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, stop_event.entity); B32 is_focused = ui_is_focus_active(); @@ -1552,9 +1549,9 @@ 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) { - CTRL_EntityList line_ips = params->line_ips[line_idx]; - CFG_NodePtrList line_bps = params->line_bps[line_idx]; - CFG_NodePtrList line_pins = params->line_pins[line_idx]; + CTRL_EntityList line_ips = params->line_ips[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); diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index f68f611d..db7ca4be 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -62,6 +62,9 @@ "typedef union RDI_SHA256 RDI_SHA256;"; "union RDI_SHA256 {RDI_U8 u8[32]; RDI_U64 u64[4];};"; ""; + "typedef union RDI_GUID RDI_GUID;"; + "union RDI_GUID {RDI_U8 u8[16]; RDI_U64 u64[2];};"; + ""; "////////////////////////////////////////////////////////////////"; "//~ Overridable Enabling/Disabling Of Table Index Typechecking"; ""; @@ -74,7 +77,7 @@ ""; "// \"raddbg\\0\\0\""; "#define RDI_MAGIC_CONSTANT 0x0000676264646172"; - "#define RDI_ENCODING_VERSION 16"; + "#define RDI_ENCODING_VERSION 17"; ""; "////////////////////////////////////////////////////////////////"; "//~ Format Types & Functions"; @@ -495,6 +498,7 @@ RDI_TopLevelInfoMemberTable: {exe_name_string_idx RDI_U32 ""} {exe_hash RDI_U64 ""} {voff_max RDI_U64 ""} + {guid RDI_GUID ""} {producer_name_string_idx RDI_U32 ""} } diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index 0d91e869..5d46eccd 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -4,6 +4,22 @@ #include "lib_rdi/rdi.c" #include "lib_rdi/rdi_parse.c" +//////////////////////////////// +//~ rjf: RDI Enum <=> Base Enum + +internal Arch +arch_from_rdi_arch(RDI_Arch arch) +{ + Arch result = Arch_Null; + switch((RDI_ArchEnum)arch) + { + case RDI_Arch_NULL:{}break; + case RDI_Arch_X86:{result = Arch_x86;}break; + case RDI_Arch_X64:{result = Arch_x64;}break; + } + return result; +} + //////////////////////////////// //~ rjf: Lookup Helpers @@ -571,11 +587,14 @@ lane_sync(); if(flags & RDI_DumpSubsetFlag_##name) ProfScope(#name) { RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); Temp scratch = scratch_begin(&arena, 1); + Guid guid = {0}; + MemoryCopy(&guid, &tli->guid, Min(sizeof guid, sizeof tli->guid)); dumpf("\n"); dumpf(" arch: %S\n", rdi_string_from_arch(scratch.arena, tli->arch)); dumpf(" exe_name: '%S'\n", str8_from_rdi_string_idx(rdi, tli->exe_name_string_idx)); dumpf(" voff_max: %#08llx\n", tli->voff_max); dumpf(" producer_name: '%S'\n", str8_from_rdi_string_idx(rdi, tli->producer_name_string_idx)); + dumpf(" guid: %S\n", string_from_guid(scratch.arena, guid)); scratch_end(scratch); } } diff --git a/src/rdi/rdi_local.h b/src/rdi/rdi_local.h index 9b35144e..ea69cc8b 100644 --- a/src/rdi/rdi_local.h +++ b/src/rdi/rdi_local.h @@ -64,6 +64,11 @@ read_only global String8 rdi_name_title_from_dump_subset_table[] = #undef X }; +//////////////////////////////// +//~ rjf: RDI Enum <=> Base Enum + +internal Arch arch_from_rdi_arch(RDI_Arch arch); + //////////////////////////////// //~ rjf: Lookup Helpers diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 455e4e52..9c3fc512 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -1002,30 +1002,30 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) checksum_value.size = Min(checksum->len, checksum_value.size); } - // rjf: file name -> normalized file path - String8 file_path = seq_file_name; - String8 file_path_normalized = lower_from_str8(scratch2.arena, str8_skip_chop_whitespace(file_path)); + // rjf: file name -> sanitized file path + String8 file_path = seq_file_name; + String8 file_path_sanitized = str8_copy(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(scratch2.arena, file_path_normalized); - if(file_path_normalized_style == PathStyle_Relative) + PathStyle file_path_sanitized_style = path_style_from_str8(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(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_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_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); + str8_path_list_resolve_dots_in_place(&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: normalized file path -> source file node - U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); - U64 hit_path_slot = file_path_normalized_hash%hit_path_slots_count; + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; String8Node *hit_path_node = 0; for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) { - if(str8_match(n->string, file_path_normalized, 0)) + if(str8_match(n->string, file_path_sanitized, 0)) { hit_path_node = n; break; @@ -1035,11 +1035,11 @@ 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_normalized; - P2R_SrcFileStubNode *stub_n = push_array(scratch.arena, P2R_SrcFileStubNode, 1); + hit_path_node->string = file_path_sanitized; + 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_normalized); + stub_n->v.file_path = str8_copy(scratch.arena, file_path_sanitized); stub_n->v.checksum_kind = checksum_kind; stub_n->v.checksum = str8_copy(scratch.arena, checksum_value); } @@ -1801,7 +1801,6 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) for EachInRange(idx, range) { CV_TypeId itype = (CV_TypeId)idx; - if(itype < itype_first) { continue; } //- rjf: push initial itype - should be final-visited-itype for this itype { @@ -4396,6 +4395,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) top_level_info.voff_max = exe_voff_max; if(!params->deterministic) { + MemoryCopy(&top_level_info.guid.u8[0], &pdb_info->auth_guid.v[0], Min(sizeof top_level_info.guid.u8, sizeof pdb_info->auth_guid.v)); top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); } } diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index c9b307d8..7d5ad140 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -2994,6 +2994,7 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params) rdim_shared->baked_top_level_info.top_level_info.exe_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.exe_name); rdim_shared->baked_top_level_info.top_level_info.exe_hash = params->top_level_info.exe_hash; rdim_shared->baked_top_level_info.top_level_info.voff_max = params->top_level_info.voff_max; + rdim_shared->baked_top_level_info.top_level_info.guid = params->top_level_info.guid; rdim_shared->baked_top_level_info.top_level_info.producer_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.producer_name); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") diff --git a/src/third_party/martins_hash/md5.h b/src/third_party/martins_hash/md5.h index 54632d0e..da477d80 100644 --- a/src/third_party/martins_hash/md5.h +++ b/src/third_party/martins_hash/md5.h @@ -46,9 +46,9 @@ static inline void md5_finish(md5_ctx* ctx, uint8_t digest[MD5_DIGEST_SIZE]); #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) +# 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) \ ( \ @@ -431,5 +431,5 @@ void md5_finish(md5_ctx* ctx, uint8_t digest[MD5_DIGEST_SIZE]) } #if defined(__clang__) -#pragma clang diagnostic pop +# pragma clang diagnostic pop #endif diff --git a/src/third_party/martins_hash/sha1.h b/src/third_party/martins_hash/sha1.h index 043ac986..5fd59362 100644 --- a/src/third_party/martins_hash/sha1.h +++ b/src/third_party/martins_hash/sha1.h @@ -50,9 +50,9 @@ static inline void sha1_finish(sha1_ctx* ctx, uint8_t digest[SHA1_DIGEST_SIZE]); #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) +# 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) \ ( \ @@ -137,36 +137,86 @@ static inline int sha1_cpuid(void) 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; + // in SHA1 each round has two parts: + // 1) calculate message schedule dwords in w[i] + // 2) do round functions to update a/b/c/d/e state values using w[i] - // 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); + // w[i] in first 16 rounds is just loaded from block bytes, as 32-bit big-endian load + + // for next rounds it is done as: + // w[i] = ROL(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) + // where ROL(x) = 32-bit rotate left by 1 + + // this means it is possible to keep just the last 16 of w's in circular buffer + // and every new w calculated will need to update 1 to 3 previous w's + + // unrolling round calculations by 4 we get: + // w[i+0] = ROL(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) + // w[i+1] = ROL(w[i-2] ^ w[i-7] ^ w[i-13] ^ w[i-15]) + // w[i+2] = ROL(w[i-1] ^ w[i-6] ^ w[i-12] ^ w[i-14]) + // w[i+3] = ROL(w[i+0] ^ w[i-5] ^ w[i-11] ^ w[i-13]) + + // now if you store 4 w[..] values in 128-bit SSE register, then + // W(i) = ROL( r0 ^ r1 ^ r2 ^ r3 ) + // with caveat that r0 lane 3 depends on W(i) lane 0 + + // [3] [2] [1] [0] // lanes + // r0 = [ special, w[i-1], w[i-2], w[i-3] ] + // r1 = [ w[i-5], w[i-6], w[i-7], w[i-8] ] + // r2 = [ w[i-11], w[i-12], w[i-13], w[i-14] ] + // r3 = [ w[i-13], w[i-14], w[i-15], w[i-16] ] + + // in each 4-round i'th step it is possible to incrementally update new W(..) value when + // keeping W(i) values in 4 xmm element circular buffer + + // rounds i>0: W(i-1) = r2 ^ r3 = _mm_sha1msg1_epu32(W(i-1), W(i)) + // rounds i>1: W(i-2) = W(i-2) ^ r1 = _mm_xor_si128 (W(i-2), W(i)) + // rounds i>2: W(i-3) = ROL(W(i-3) ^ r0) = _mm_sha1msg2_epu32(W(i-3), W(i)) + // then the new W(i) can be used in round function calculations + // _mm_sha1msg2_epu32 correctly handles r0 lane 3 dependency on W(i) lane 0 + + // to perform round functions on two SIMD registers with state as: + // abcd = [a,b,c,d] + // e0 = [e,0,0,0] + // use the following code to get next abcd/e0 state 4 rounds at a time: + + // tmp = _mm_sha1nexte_epu32(e0, W(i)) // rotates e0 and adds message dwords + // abcd_next = _mm_sha1rnds4_epu32(abcd, tmp, Fn) // with Fn = 0..3 round function selection + // e0_next = abcd + + // sha1nexte is not needed on first round, just regular add32(e0, W(i)) should be used + // after last round need to do extra rotation, which sha1nexte takes care when adding to last_e0 #define W(i) w[(i)%4] // 4 wide round calculations #define QROUND(i) do { \ - /* first four rounds loads input message */ \ + /* first 4 rounds load input block */ \ if (i < 4) W(i) = _mm_shuffle_epi8(_mm_loadu_si128(&buffer[i]), bswap); \ - /* update previous message dwords for next rounds */ \ + /* update message schedule */ \ 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 > 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)); \ + /* calculate E plus message schedule */ \ + if (i == 0) tmp = _mm_add_epi32 (e0, W(i)); \ if (i != 0) tmp = _mm_sha1nexte_epu32(e0, W(i)); \ - /* round function */ \ + /* 4 round functions */ \ e0 = abcd; \ - abcd = _mm_sha1rnds4_epu32(abcd, tmp, (i/5)%4); \ + abcd = _mm_sha1rnds4_epu32(abcd, tmp, i/5); \ } while(0) + 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 sha1 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); + // 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 + // flip dword order, to what sha1 instructions use 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 @@ -183,16 +233,19 @@ static void sha1_process_shani(uint32_t* state, const uint8_t* block, size_t cou 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); @@ -221,6 +274,159 @@ static void sha1_process_shani(uint32_t* state, const uint8_t* block, size_t cou #endif // defined(__x86_64__) || defined(_M_AMD64) + +#if defined(__aarch64__) || defined(_M_ARM64) + +#if defined(__clang__) +# define SHA1_TARGET __attribute__((target("sha2"))) +#elif defined(__GNUC__) +# define SHA1_TARGET __attribute__((target("+sha2"))) +#elif defined(_MSC_VER) +# define SHA1_TARGET +#endif + +#include + +#if defined(_WIN32) +# include +#elif defined(__linux__) +# include +# include +#elif defined(__APPLE__) +# include +#endif + +#define SHA1_CPUID_INIT (1 << 0) +#define SHA1_CPUID_ARM64 (1 << 1) + +static inline int sha1_cpuid(void) +{ +#if defined(__ARM_FEATURE_CRYPTO) || defined(__ARM_FEATURE_SHA2) + int result = SHA1_CPUID_ARM64; +#else + static int cpuid; + + int result = cpuid; + if (result == 0) + { +#if defined(_WIN32) + int has_arm64 = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); +#elif defined(__linux__) + unsigned long hwcap = getauxval(AT_HWCAP); + int has_arm64 = hwcap & HWCAP_SHA1; +#elif defined(__APPLE__) + int value = 0; + size_t valuelen = sizeof(value); + int has_arm64 = sysctlbyname("hw.optional.arm.FEAT_SHA1", &value, &valuelen, NULL, 0) == 0 && value != 0; +#else +#error unknown platform +#endif + result |= SHA1_CPUID_INIT; + if (has_arm64) + { + result |= SHA1_CPUID_ARM64; + } + + cpuid = result; + } +#endif + +#if defined(SHA1_CPUID_MASK) + result &= SHA1_CPUID_MASK; +#endif + + return result; +} + +SHA1_TARGET +static void sha1_process_arm64(uint32_t* state, const uint8_t* block, size_t count) +{ + // code here is similar to x64 shani implementation + + // message array is 16 element circular buffer + // each iteration updates 4 rounds at the same time + + #define W(i) w[(i)%4] + + #define QROUND(i,F,k) do { \ + /* update message schedule */ \ + if (i >= 4) W(i) = vsha1su0q_u32(W(i), W(i-3), W(i-2)); \ + if (i >= 4) W(i) = vsha1su1q_u32(W(i), W(i-1)); \ + /* add round constant */ \ + uint32x4_t tmp = vaddq_u32(W(i), k); \ + /* 4 round functions */ \ + uint32_t x = e0; \ + e0 = vsha1h_u32(vgetq_lane_u32(abcd, 0)); \ + abcd = F(abcd, x, tmp); \ + } while (0) + + const uint32x4_t k0 = vdupq_n_u32(0x5a827999); + const uint32x4_t k1 = vdupq_n_u32(0x6ed9eba1); + const uint32x4_t k2 = vdupq_n_u32(0x8f1bbcdc); + const uint32x4_t k3 = vdupq_n_u32(0xca62c1d6); + + // load state - a,b,c,d,e + uint32x4_t abcd = vld1q_u32(state); + uint32_t e0 = state[4]; + + do + { + // remember current state + uint32x4_t last_abcd = abcd; + uint32_t last_e0 = e0; + + // load 64-byte block and advance pointer to next block + uint8x16x4_t msg = vld1q_u8_x4(block); + block += SHA1_BLOCK_SIZE; + + uint32x4_t w[4]; + + // for first 16 w's reverse the byte order in each 32-bit lane + W(0) = vreinterpretq_u32_u8(vrev32q_u8(msg.val[0])); + W(1) = vreinterpretq_u32_u8(vrev32q_u8(msg.val[1])); + W(2) = vreinterpretq_u32_u8(vrev32q_u8(msg.val[2])); + W(3) = vreinterpretq_u32_u8(vrev32q_u8(msg.val[3])); + + QROUND( 0, vsha1cq_u32, k0); + QROUND( 1, vsha1cq_u32, k0); + QROUND( 2, vsha1cq_u32, k0); + QROUND( 3, vsha1cq_u32, k0); + QROUND( 4, vsha1cq_u32, k0); + + QROUND( 5, vsha1pq_u32, k1); + QROUND( 6, vsha1pq_u32, k1); + QROUND( 7, vsha1pq_u32, k1); + QROUND( 8, vsha1pq_u32, k1); + QROUND( 9, vsha1pq_u32, k1); + + QROUND(10, vsha1mq_u32, k2); + QROUND(11, vsha1mq_u32, k2); + QROUND(12, vsha1mq_u32, k2); + QROUND(13, vsha1mq_u32, k2); + QROUND(14, vsha1mq_u32, k2); + + QROUND(15, vsha1pq_u32, k3); + QROUND(16, vsha1pq_u32, k3); + QROUND(17, vsha1pq_u32, k3); + QROUND(18, vsha1pq_u32, k3); + QROUND(19, vsha1pq_u32, k3); + + // update next state + abcd = vaddq_u32(abcd, last_abcd); + e0 += last_e0; + } + while (--count); + + // save state + vst1q_u32(state, abcd); + state[4] = e0; + + #undef QROUND + #undef W +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) + static void sha1_process(uint32_t* state, const uint8_t* block, size_t count) { #if defined(__x86_64__) || defined(_M_AMD64) @@ -232,12 +438,21 @@ static void sha1_process(uint32_t* state, const uint8_t* block, size_t count) } #endif +#if defined(__aarch64__) || defined(_M_ARM64) + int cpuid = sha1_cpuid(); + if (cpuid & SHA1_CPUID_ARM64) + { + sha1_process_arm64(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 W(i) w[(i)%16] #define ROUND(i,a,b,c,d,e,F) do \ { \ diff --git a/src/third_party/martins_hash/sha256.h b/src/third_party/martins_hash/sha256.h index 72a0fad6..b70a72a0 100644 --- a/src/third_party/martins_hash/sha256.h +++ b/src/third_party/martins_hash/sha256.h @@ -58,9 +58,9 @@ static inline void sha224_finish(sha224_ctx* ctx, uint8_t digest[SHA224_DIGEST_S #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) +# 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) \ ( \ @@ -91,6 +91,26 @@ static inline void sha224_finish(sha224_ctx* ctx, uint8_t digest[SHA224_DIGEST_S while (0) #endif +static const uint32_t SHA256_K[64] = +{ + 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, +}; + #if defined(__x86_64__) || defined(_M_AMD64) #include // SSSE3 @@ -145,47 +165,64 @@ static inline int sha256_cpuid(void) 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; + // similar way how sha1 works in with shani - // 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); + // first 16 rounds loads message schedule dwords as 32-bit big endian values - 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 }, - }; + // for next rounds message schedule is prepared as: + // w[i] = SSig1(w[i-2]) + w[i-7] + SSig0(w[i-15]) + w[i-16] + + // unrolled by 4: + // w[i+0] = SSig1(w[i-2]) + w[i-7] + SSig0(w[i-15]) + w[i-16] + // w[i+1] = SSig1(w[i-1]) + w[i-6] + SSig0(w[i-14]) + w[i-15] + // w[i+2] = SSig1(w[i+0]) + w[i-5] + SSig0(w[i-13]) + w[i-14] + // w[i+3] = SSig1(w[i+1]) + w[i-4] + SSig0(w[i-12]) + w[i-13] + + // there is tricky dependency for lanes 2 and 3 on result of lanes 0 and 1, but sha256msg2 op takes care of that + + // by storing W[i] word in 128-bit simd register, the message schedule becomes: + // W(i) = SSig1(r0) + r1 + SSig0(r2) + r3 + // where + is 32-bit lane addition + + // [3] [2] [1] [0] // lanes + // r0 = [ special, special, w[i-1], w[i-2] ] + // r1 = [ w[i-4], w[i-5], w[i-6], w[i-7] ] + // r2 = [ w[i-12], w[i-13], w[i-14], w[i-15] ] + // r3 = [ w[i-13], w[i-14], w[i-15], w[i-16] ] + + // rN's can be calculated from previous W(..) values: + // r0 from W(i) + // r1 from _mm_alignr_epi8(W(i), W(i-1), 4) + // r2 from W(i-1) and W(i) + // r3 from W(i-1) + + // rounds i>2: W(i-3) = _mm_sha256msg2_epu32(_mm_add_epi32( W(i-3), _mm_alignr_epi8(W(i), W(i-1), 4) ), W(i)) + // rounds i>0: W(i-1) = _mm_sha256msg1_epu32(W(i-1), W(i)) + + // round functions are done with _mm_sha256rnds2_epu32 which performs it for 2 rounds + // thus repeat it two times, as input use W(i) + K(i) - message schedule added with sha256 constants #define W(i) w[(i)%4] // 4 wide round calculations #define QROUND(i) do { \ - /* first four rounds loads input message */ \ + /* first 4 rounds load input block */ \ 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 */ \ + /* update message schedule */ \ 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 */ \ + /* add round constants */ \ + __m128i tmp = _mm_add_epi32(W(i), _mm_loadu_si128((const __m128i*)&SHA256_K[4*i])); \ + /* 4 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) - + + 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); + // 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] @@ -200,18 +237,18 @@ static void sha256_process_shani(uint32_t* state, const uint8_t* block, size_t c __m128i last0 = state0; __m128i last1 = state1; - __m128i tmp, w[4]; + __m128i w[4]; - QROUND(0); - QROUND(1); - QROUND(2); - QROUND(3); - QROUND(4); - QROUND(5); - QROUND(6); - QROUND(7); - QROUND(8); - QROUND(9); + 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); @@ -241,6 +278,140 @@ static void sha256_process_shani(uint32_t* state, const uint8_t* block, size_t c #endif // defined(__x86_64__) || defined(_M_AMD64) +#if defined(__aarch64__) || defined(_M_ARM64) + +#if defined(__clang__) +# define SHA256_TARGET __attribute__((target("sha2"))) +#elif defined(__GNUC__) +# define SHA256_TARGET __attribute__((target("+sha2"))) +#elif defined(_MSC_VER) +# define SHA256_TARGET +#endif + +#include + +#if defined(_WIN32) +# include +#elif defined(__linux__) +# include +# include +#elif defined(__APPLE__) +# include +#endif + +#define SHA256_CPUID_INIT (1 << 0) +#define SHA256_CPUID_ARM64 (1 << 1) + +static inline int sha256_cpuid(void) +{ +#if defined(__ARM_FEATURE_CRYPTO) || defined(__ARM_FEATURE_SHA2) + int result = SHA256_CPUID_ARM64; +#else + static int cpuid; + + int result = cpuid; + if (result == 0) + { +#if defined(_WIN32) + int has_arm64 = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); +#elif defined(__linux__) + unsigned long hwcap = getauxval(AT_HWCAP); + int has_arm64 = hwcap & HWCAP_SHA2; +#elif defined(__APPLE__) + int value = 0; + size_t valuelen = sizeof(value); + int has_arm64 = sysctlbyname("hw.optional.arm.FEAT_SHA256", &value, &valuelen, NULL, 0) == 0 && value != 0; +#else +#error unknown platform +#endif + result |= SHA256_CPUID_INIT; + if (has_arm64) + { + result |= SHA256_CPUID_ARM64; + } + + cpuid = result; + } +#endif + +#if defined(SHA256_CPUID_MASK) + result &= SHA256_CPUID_MASK; +#endif + + return result; +} + +SHA256_TARGET +static void sha256_process_arm64(uint32_t* state, const uint8_t* block, size_t count) +{ + // code here is similar to x64 shani implementation + + #define W(i) w[(i)%4] + + #define QROUND(i) do { \ + /* load 16 round constants */ \ + if ((i % 4) == 0) rk = vld1q_u32_x4(&SHA256_K[4*i]); \ + /* first 4 rounds reverse byte order in each 32-bit lane of input block */ \ + if (i < 4) W(i) = vreinterpretq_u32_u8(vrev32q_u8(msg.val[i])); \ + /* update message schedule */ \ + if (i >= 4) W(i) = vsha256su0q_u32(W(i), W(i-3)); \ + if (i >= 4) W(i) = vsha256su1q_u32(W(i), W(i-2), W(i-1)); \ + /* add round constants */ \ + uint32x4_t tmp = vaddq_u32(W(i), rk.val[i%4]); \ + /* 4 round functions */ \ + uint32x4_t x = vstate.val[0]; \ + vstate.val[0] = vsha256hq_u32(vstate.val[0], vstate.val[1], tmp); \ + vstate.val[1] = vsha256h2q_u32(vstate.val[1], x, tmp); \ + } while (0) + + // load initial state + uint32x4x2_t vstate = vld1q_u32_x2(state); + + do + { + // remember current state + uint32x4x2_t vlast = vstate; + + // load 64-byte block + uint8x16x4_t msg = vld1q_u8_x4(block); + + uint32x4x4_t rk; + uint32x4_t 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 + vstate.val[0] = vaddq_u32(vstate.val[0], vlast.val[0]); + vstate.val[1] = vaddq_u32(vstate.val[1], vlast.val[1]); + + block += SHA256_BLOCK_SIZE; + } + while (--count); + + // save the new state + vst1q_u32_x2(state, vstate); + + #undef QROUND + #undef W +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) + static void sha256_process(uint32_t* state, const uint8_t* block, size_t count) { #if defined(__x86_64__) || defined(_M_AMD64) @@ -252,6 +423,15 @@ static void sha256_process(uint32_t* state, const uint8_t* block, size_t count) } #endif +#if defined(__aarch64__) || defined(_M_ARM64) + int cpuid = sha256_cpuid(); + if (cpuid & SHA256_CPUID_ARM64) + { + sha256_process_arm64(state, block, count); + return; + } +#endif + #define Ch(x,y,z) ((x & (y ^ z)) ^ z) #define Maj(x,y,z) ((x & y) | (z & (x | y))) @@ -262,13 +442,13 @@ static void sha256_process(uint32_t* state, const uint8_t* block, size_t count) #define W(i) w[(i+16)%16] - #define ROUND(i,a,b,c,d,e,f,g,h,K) do \ + #define ROUND(i,a,b,c,d,e,f,g,h) 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 t1 = h + BSig1(e) + Ch(e,f,g) + SHA256_K[i] + w0; \ uint32_t t2 = BSig0(a) + Maj(a,b,c); \ d += t1; \ h = t1 + t2; \ @@ -287,70 +467,70 @@ static void sha256_process(uint32_t* state, const uint8_t* block, size_t count) 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); + ROUND( 0, a, b, c, d, e, f, g, h); + ROUND( 1, h, a, b, c, d, e, f, g); + ROUND( 2, g, h, a, b, c, d, e, f); + ROUND( 3, f, g, h, a, b, c, d, e); + ROUND( 4, e, f, g, h, a, b, c, d); + ROUND( 5, d, e, f, g, h, a, b, c); + ROUND( 6, c, d, e, f, g, h, a, b); + ROUND( 7, b, c, d, e, f, g, h, a); + ROUND( 8, a, b, c, d, e, f, g, h); + ROUND( 9, h, a, b, c, d, e, f, g); + ROUND(10, g, h, a, b, c, d, e, f); + ROUND(11, f, g, h, a, b, c, d, e); + ROUND(12, e, f, g, h, a, b, c, d); + ROUND(13, d, e, f, g, h, a, b, c); + ROUND(14, c, d, e, f, g, h, a, b); + ROUND(15, b, c, d, e, f, g, h, a); + ROUND(16, a, b, c, d, e, f, g, h); + ROUND(17, h, a, b, c, d, e, f, g); + ROUND(18, g, h, a, b, c, d, e, f); + ROUND(19, f, g, h, a, b, c, d, e); + ROUND(20, e, f, g, h, a, b, c, d); + ROUND(21, d, e, f, g, h, a, b, c); + ROUND(22, c, d, e, f, g, h, a, b); + ROUND(23, b, c, d, e, f, g, h, a); + ROUND(24, a, b, c, d, e, f, g, h); + ROUND(25, h, a, b, c, d, e, f, g); + ROUND(26, g, h, a, b, c, d, e, f); + ROUND(27, f, g, h, a, b, c, d, e); + ROUND(28, e, f, g, h, a, b, c, d); + ROUND(29, d, e, f, g, h, a, b, c); + ROUND(30, c, d, e, f, g, h, a, b); + ROUND(31, b, c, d, e, f, g, h, a); + ROUND(32, a, b, c, d, e, f, g, h); + ROUND(33, h, a, b, c, d, e, f, g); + ROUND(34, g, h, a, b, c, d, e, f); + ROUND(35, f, g, h, a, b, c, d, e); + ROUND(36, e, f, g, h, a, b, c, d); + ROUND(37, d, e, f, g, h, a, b, c); + ROUND(38, c, d, e, f, g, h, a, b); + ROUND(39, b, c, d, e, f, g, h, a); + ROUND(40, a, b, c, d, e, f, g, h); + ROUND(41, h, a, b, c, d, e, f, g); + ROUND(42, g, h, a, b, c, d, e, f); + ROUND(43, f, g, h, a, b, c, d, e); + ROUND(44, e, f, g, h, a, b, c, d); + ROUND(45, d, e, f, g, h, a, b, c); + ROUND(46, c, d, e, f, g, h, a, b); + ROUND(47, b, c, d, e, f, g, h, a); + ROUND(48, a, b, c, d, e, f, g, h); + ROUND(49, h, a, b, c, d, e, f, g); + ROUND(50, g, h, a, b, c, d, e, f); + ROUND(51, f, g, h, a, b, c, d, e); + ROUND(52, e, f, g, h, a, b, c, d); + ROUND(53, d, e, f, g, h, a, b, c); + ROUND(54, c, d, e, f, g, h, a, b); + ROUND(55, b, c, d, e, f, g, h, a); + ROUND(56, a, b, c, d, e, f, g, h); + ROUND(57, h, a, b, c, d, e, f, g); + ROUND(58, g, h, a, b, c, d, e, f); + ROUND(59, f, g, h, a, b, c, d, e); + ROUND(60, e, f, g, h, a, b, c, d); + ROUND(61, d, e, f, g, h, a, b, c); + ROUND(62, c, d, e, f, g, h, a, b); + ROUND(63, b, c, d, e, f, g, h, a); state[0] += a; state[1] += b; diff --git a/src/third_party/martins_hash/sha512.h b/src/third_party/martins_hash/sha512.h index 2a7dad07..4a48c6f1 100644 --- a/src/third_party/martins_hash/sha512.h +++ b/src/third_party/martins_hash/sha512.h @@ -15,9 +15,9 @@ #define SHA512_BLOCK_SIZE 128 typedef struct { - uint8_t buffer[SHA512_BLOCK_SIZE]; - uint64_t count[2]; - uint64_t state[8]; + uint8_t buffer[SHA512_BLOCK_SIZE]; + uint64_t count[2]; + uint64_t state[8]; } sha512_ctx; typedef sha512_ctx sha384_ctx; @@ -58,37 +58,61 @@ static inline void sha384_finish(sha384_ctx* ctx, uint8_t digest[SHA384_DIGEST_S #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) +# 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) \ - ) +( \ +((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) +{ \ +(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 +static const uint64_t SHA512_K[80] = +{ + 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, +}; + #if defined(__x86_64__) || defined(_M_AMD64) -#include +#include // AVX2 + SHA512 #if defined(__clang__) || defined(__GNUC__) # include @@ -110,395 +134,568 @@ static inline void sha384_finish(sha384_ctx* ctx, uint8_t digest[SHA384_DIGEST_S SHA512_TARGET("xsave") static inline int sha512_cpuid(void) { - static int cpuid; - - int result = cpuid; - if (result == 0) + static int cpuid; + + int result = cpuid; + if (result == 0) + { + int info[4]; + + SHA512_CPUID(1, info); + int has_xsave = info[2] & (1 << 26); + + int has_ymm = 0; + if (has_xsave) { - 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; + uint64_t xcr0 = SHA512_XGETBV(0); + has_ymm = xcr0 & (1 << 2); } - + + SHA512_CPUID_EX(7, 0, info); + int has_avx2 = info[1] & (1 << 5); + + SHA512_CPUID_EX(7, 1, info); + int has_sha512 = info[0] & (1 << 0); + + result |= SHA512_CPUID_INIT; + if (has_ymm && has_avx2 && has_sha512) + { + result |= SHA512_CPUID_VSHA512; + } + + cpuid = result; + } + #if defined(SHA512_CPUID_MASK) - result &= SHA512_CPUID_MASK; + result &= SHA512_CPUID_MASK; #endif - - return result; + + 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 + // pretty much same way how sha256 works, only with avx2 registers and 64-bit additions + // state is kept as two 256-bit ymm registers (8 qwords) + + // message qwords are loaded as 64-bit big-endian values + +#define W(i) w[(i)%4] + + // 4 wide round calculations +#define QROUND(i) do { \ +/* first 4 rounds load input block */ \ +if (i < 4) W(i) = _mm256_shuffle_epi8(_mm256_loadu_si256(&buffer[i]), bswap); \ +/* update message schedule */ \ +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))); \ +/* add round constants */ \ +__m256i tmp = _mm256_add_epi64(W(i), _mm256_loadu_si256((const __m256i*)&SHA512_K[4*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) + + 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)); + + // 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 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) +#if defined(__aarch64__) || defined(_M_ARM64) + +#if defined(__clang__) +# define SHA512_TARGET __attribute__((target("sha3"))) +#elif defined(__GNUC__) +# define SHA512_TARGET __attribute__((target("+sha3"))) +#elif defined(_MSC_VER) +# define SHA512_TARGET +#endif + +#include + +#if defined(_WIN32) +# include +# pragma comment (lib, "advapi32") +#elif defined(__linux__) +# include +# include +#elif defined(__APPLE__) +# include +#endif + +#define SHA512_CPUID_INIT (1 << 0) +#define SHA512_CPUID_ARM64 (1 << 1) + +#if defined(_WIN32) + +#endif + +static inline int sha512_cpuid(void) +{ +#if defined(__ARM_FEATURE_SHA512) + int result = SHA512_CPUID_ARM64; +#else + static int cpuid; + + int result = cpuid; + if (result == 0) + { +#if defined(_WIN32) + // no sha512 bit in IsProcessorFeaturePresent function :( + uint64_t bits; + DWORD bitsize = sizeof(bits); + RegGetValueA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "CP 4030", RRF_RT_QWORD | RRF_ZEROONFAILURE, NULL, &bits, &bitsize); + // bits from ID_AA64ISAR0_EL1 + int has_arm64 = ((bits >> 12) & 0xf) == 0x2; +#elif defined(__linux__) + unsigned long hwcap = getauxval(AT_HWCAP); + int has_arm64 = hwcap & HWCAP_SHA512; +#elif defined(__APPLE__) + int value = 0; + size_t valuelen = sizeof(value); + int has_arm64 = sysctlbyname("hw.optional.arm.FEAT_SHA512", &value, &valuelen, NULL, 0) == 0 && value != 0; +#else +#error unknown platform +#endif + result |= SHA512_CPUID_INIT; + if (has_arm64) + { + result |= SHA512_CPUID_ARM64; + } + + cpuid = result; + } +#endif + +#if defined(SHA512_CPUID_MASK) + result &= SHA512_CPUID_MASK; +#endif + + return result; +} + +SHA512_TARGET +static void sha512_process_arm64(uint64_t* state, const uint8_t* block, size_t count) +{ +#define W(i) w[(i)%8] +#define S(i) vstate.val[3-(i)%4] + +#define DROUND(i) do { \ +/* load 8 round constants */ \ +if ((i % 4) == 0) rk = vld1q_u64_x4(&SHA512_K[2*i]); \ +/* first 8 rounds reverse byte order in each 64-bit lane of input block */ \ +if (i < 8) W(i) = vreinterpretq_u64_u8(vrev64q_u8(msg[(i/4)%2].val[i%4])); \ +/* update message schedule for next rounds */ \ +if (i >= 8) W(i) = vsha512su1q_u64(vsha512su0q_u64(W(i), W(i-7)), W(i-1), vextq_u64(W(i-4), W(i-3), 1)); \ +/* add round constants */ \ +uint64x2_t tmp = vaddq_u64(W(i), rk.val[i%4]); \ +/* 2 round functions */ \ +uint64x2_t x0 = vaddq_u64(vextq_u64(tmp, tmp, 1), S(i+0)); \ +uint64x2_t x1 = vsha512hq_u64(x0, vextq_u64(S(i+1), S(i+0), 1), vextq_u64(S(i+2), S(i+1), 1)); \ +S(i+0) = vsha512h2q_u64(x1, S(i+2), S(i+3)); \ +S(i+2) = vaddq_u64(S(i+2), x1); \ +} while (0) + + // load initial state + uint64x2x4_t vstate = vld1q_u64_x4(state); + + do + { + // remember current state + uint64x2x4_t vlast = vstate; + + // load 128-byte block + uint8x16x4_t msg[2] = + { + vld1q_u8_x4(block + 0 * 16), + vld1q_u8_x4(block + 4 * 16), + }; + + uint64x2x4_t rk; + uint64x2_t w[8]; + + DROUND( 0); + DROUND( 1); + DROUND( 2); + DROUND( 3); + + DROUND( 4); + DROUND( 5); + DROUND( 6); + DROUND( 7); + + DROUND( 8); + DROUND( 9); + DROUND(10); + DROUND(11); + + DROUND(12); + DROUND(13); + DROUND(14); + DROUND(15); + + DROUND(16); + DROUND(17); + DROUND(18); + DROUND(19); + + DROUND(20); + DROUND(21); + DROUND(22); + DROUND(23); + + DROUND(24); + DROUND(25); + DROUND(26); + DROUND(27); + + DROUND(28); + DROUND(29); + DROUND(30); + DROUND(31); + + DROUND(32); + DROUND(33); + DROUND(34); + DROUND(35); + + DROUND(36); + DROUND(37); + DROUND(38); + DROUND(39); + + // update next state + vstate.val[0] = vaddq_u64(vstate.val[0], vlast.val[0]); + vstate.val[1] = vaddq_u64(vstate.val[1], vlast.val[1]); + vstate.val[2] = vaddq_u64(vstate.val[2], vlast.val[2]); + vstate.val[3] = vaddq_u64(vstate.val[3], vlast.val[3]); + + block += SHA512_BLOCK_SIZE; + } + while (--count); + + // save the new state + vst1q_u64_x4(state, vstate); + +#undef DROUND +#undef S +#undef W +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) + 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; - } + 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 + +#if defined(__aarch64__) || defined(_M_ARM64) + int cpuid = sha512_cpuid(); + if (cpuid & SHA512_CPUID_ARM64) + { + sha512_process_arm64(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) 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) + SHA512_K[i] + 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); + ROUND( 1, h, a, b, c, d, e, f, g); + ROUND( 2, g, h, a, b, c, d, e, f); + ROUND( 3, f, g, h, a, b, c, d, e); + ROUND( 4, e, f, g, h, a, b, c, d); + ROUND( 5, d, e, f, g, h, a, b, c); + ROUND( 6, c, d, e, f, g, h, a, b); + ROUND( 7, b, c, d, e, f, g, h, a); + ROUND( 8, a, b, c, d, e, f, g, h); + ROUND( 9, h, a, b, c, d, e, f, g); + ROUND(10, g, h, a, b, c, d, e, f); + ROUND(11, f, g, h, a, b, c, d, e); + ROUND(12, e, f, g, h, a, b, c, d); + ROUND(13, d, e, f, g, h, a, b, c); + ROUND(14, c, d, e, f, g, h, a, b); + ROUND(15, b, c, d, e, f, g, h, a); + ROUND(16, a, b, c, d, e, f, g, h); + ROUND(17, h, a, b, c, d, e, f, g); + ROUND(18, g, h, a, b, c, d, e, f); + ROUND(19, f, g, h, a, b, c, d, e); + ROUND(20, e, f, g, h, a, b, c, d); + ROUND(21, d, e, f, g, h, a, b, c); + ROUND(22, c, d, e, f, g, h, a, b); + ROUND(23, b, c, d, e, f, g, h, a); + ROUND(24, a, b, c, d, e, f, g, h); + ROUND(25, h, a, b, c, d, e, f, g); + ROUND(26, g, h, a, b, c, d, e, f); + ROUND(27, f, g, h, a, b, c, d, e); + ROUND(28, e, f, g, h, a, b, c, d); + ROUND(29, d, e, f, g, h, a, b, c); + ROUND(30, c, d, e, f, g, h, a, b); + ROUND(31, b, c, d, e, f, g, h, a); + ROUND(32, a, b, c, d, e, f, g, h); + ROUND(33, h, a, b, c, d, e, f, g); + ROUND(34, g, h, a, b, c, d, e, f); + ROUND(35, f, g, h, a, b, c, d, e); + ROUND(36, e, f, g, h, a, b, c, d); + ROUND(37, d, e, f, g, h, a, b, c); + ROUND(38, c, d, e, f, g, h, a, b); + ROUND(39, b, c, d, e, f, g, h, a); + ROUND(40, a, b, c, d, e, f, g, h); + ROUND(41, h, a, b, c, d, e, f, g); + ROUND(42, g, h, a, b, c, d, e, f); + ROUND(43, f, g, h, a, b, c, d, e); + ROUND(44, e, f, g, h, a, b, c, d); + ROUND(45, d, e, f, g, h, a, b, c); + ROUND(46, c, d, e, f, g, h, a, b); + ROUND(47, b, c, d, e, f, g, h, a); + ROUND(48, a, b, c, d, e, f, g, h); + ROUND(49, h, a, b, c, d, e, f, g); + ROUND(50, g, h, a, b, c, d, e, f); + ROUND(51, f, g, h, a, b, c, d, e); + ROUND(52, e, f, g, h, a, b, c, d); + ROUND(53, d, e, f, g, h, a, b, c); + ROUND(54, c, d, e, f, g, h, a, b); + ROUND(55, b, c, d, e, f, g, h, a); + ROUND(56, a, b, c, d, e, f, g, h); + ROUND(57, h, a, b, c, d, e, f, g); + ROUND(58, g, h, a, b, c, d, e, f); + ROUND(59, f, g, h, a, b, c, d, e); + ROUND(60, e, f, g, h, a, b, c, d); + ROUND(61, d, e, f, g, h, a, b, c); + ROUND(62, c, d, e, f, g, h, a, b); + ROUND(63, b, c, d, e, f, g, h, a); + ROUND(64, a, b, c, d, e, f, g, h); + ROUND(65, h, a, b, c, d, e, f, g); + ROUND(66, g, h, a, b, c, d, e, f); + ROUND(67, f, g, h, a, b, c, d, e); + ROUND(68, e, f, g, h, a, b, c, d); + ROUND(69, d, e, f, g, h, a, b, c); + ROUND(70, c, d, e, f, g, h, a, b); + ROUND(71, b, c, d, e, f, g, h, a); + ROUND(72, a, b, c, d, e, f, g, h); + ROUND(73, h, a, b, c, d, e, f, g); + ROUND(74, g, h, a, b, c, d, e, f); + ROUND(75, f, g, h, a, b, c, d, e); + ROUND(76, e, f, g, h, a, b, c, d); + ROUND(77, d, e, f, g, h, a, b, c); + ROUND(78, c, d, e, f, g, h, a, b); + ROUND(79, b, c, d, e, f, g, h, a); + + 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; + 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); + 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]); - } + 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; + 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); + 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); + uint8_t temp[SHA512_DIGEST_SIZE]; + sha512_finish(ctx, temp); + + memcpy(digest, temp, SHA384_DIGEST_SIZE); } #if defined(__clang__)