Merge tag 'v0.9.24-alpha'

This commit is contained in:
2025-10-23 23:36:21 -04:00
44 changed files with 2526 additions and 1170 deletions
+32
View File
@@ -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
+79 -3
View File
@@ -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;
}
}
}
}
}
}
}
}
}
+9 -6
View File
@@ -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
+1 -1
View File
@@ -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)
+6 -1
View File
@@ -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);
+24 -9
View File
@@ -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;
}
////////////////////////////////
+1 -1
View File
@@ -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))
+34 -14
View File
@@ -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);
}
+10
View File
@@ -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:
+2
View File
@@ -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;
+156 -84
View File
@@ -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];
+1 -1
View File
@@ -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
+31 -3
View File
@@ -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
+32 -10
View File
@@ -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
//
+50 -33
View File
@@ -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;
}
+5 -5
View File
@@ -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;
}
}
+307 -290
View File
@@ -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;
+1 -1
View File
@@ -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);
@@ -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)
+6 -3
View File
@@ -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);
}
+6 -1
View File
@@ -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;
};
+5
View File
@@ -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;
+1
View File
@@ -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;
};
+2
View File
@@ -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;
+10 -1
View File
@@ -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;
+4 -2
View File
@@ -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;
+1 -1
View File
@@ -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;
File diff suppressed because one or more lines are too long
+8 -4
View File
@@ -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];
+23
View File
@@ -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." "" "" }
+440 -115
View File
@@ -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, &timestamp);
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, &timestamp);
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, &timestamp);
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();
+37 -1
View File
@@ -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;
+8 -6
View File
@@ -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
+8 -31
View File
@@ -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
+3 -6
View File
@@ -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);
+5 -1
View File
@@ -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 ""}
}
+19
View File
@@ -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);
}
}
+5
View File
@@ -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
+19 -19
View File
@@ -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);
}
}
+1
View File
@@ -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")
+4 -4
View File
@@ -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
+232 -17
View File
@@ -50,9 +50,9 @@ static inline void sha1_finish(sha1_ctx* ctx, uint8_t digest[SHA1_DIGEST_SIZE]);
#if defined(_MSC_VER)
# include <stdlib.h>
# 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 <arm_neon.h>
#if defined(_WIN32)
# include <windows.h>
#elif defined(__linux__)
# include <sys/auxv.h>
# include <asm/hwcap.h>
#elif defined(__APPLE__)
# include <sys/sysctl.h>
#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 \
{ \
+288 -108
View File
@@ -58,9 +58,9 @@ static inline void sha224_finish(sha224_ctx* ctx, uint8_t digest[SHA224_DIGEST_S
#if defined(_MSC_VER)
# include <stdlib.h>
# 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 <tmmintrin.h> // 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 <arm_neon.h>
#if defined(_WIN32)
# include <windows.h>
#elif defined(__linux__)
# include <sys/auxv.h>
# include <asm/hwcap.h>
#elif defined(__APPLE__)
# include <sys/sysctl.h>
#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;
+572 -375
View File
File diff suppressed because it is too large Load Diff