diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 6aadffd7..caecb1b1 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -1,6 +1,18 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Third Party Includes + +#include "third_party/udis86/config.h" +#include "third_party/udis86/udis86.h" +#include "third_party/udis86/libudis86/decode.c" +#include "third_party/udis86/libudis86/itab.c" +#include "third_party/udis86/libudis86/syn-att.c" +#include "third_party/udis86/libudis86/syn-intel.c" +#include "third_party/udis86/libudis86/syn.c" +#include "third_party/udis86/libudis86/udis86.c" + //////////////////////////////// //~ rjf: Instruction Type Functions @@ -62,84 +74,6 @@ dasm_inst_array_code_off_from_idx(DASM_InstArray *array, U64 idx) return off; } -//////////////////////////////// -//~ rjf: Disassembly Decoding Function - -#include "third_party/udis86/config.h" -#include "third_party/udis86/udis86.h" -#include "third_party/udis86/libudis86/decode.c" -#include "third_party/udis86/libudis86/itab.c" -#include "third_party/udis86/libudis86/syn-att.c" -#include "third_party/udis86/libudis86/syn-intel.c" -#include "third_party/udis86/libudis86/syn.c" -#include "third_party/udis86/libudis86/udis86.c" - -internal DASM_Info -dasm_info_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data) -{ - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: decode - DASM_InstChunkList inst_list = {0}; - String8List inst_strings = {0}; - switch(arch) - { - default:{}break; - - //- rjf: x86/x64 decoding - case Architecture_x64: - case Architecture_x86: - { - // rjf: grab context - struct ud udc; - ud_init(&udc); - ud_set_mode(&udc, bit_size_from_arch(arch)); - ud_set_pc(&udc, addr); - ud_set_input_buffer(&udc, data.str, data.size); - ud_set_vendor(&udc, UD_VENDOR_ANY); - ud_set_syntax(&udc, UD_SYN_INTEL); - - // rjf: disassemble - U64 byte_process_start_off = 0; - for(U64 off = 0; off < data.size;) - { - // rjf: disassemble one instruction - U64 size = ud_disassemble(&udc); - if(size == 0) - { - break; - } - - // rjf: analyze - struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(&udc, 0); - U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(&udc, first_op) : 0; - - // rjf: push - String8 string = push_str8f(scratch.arena, "%s\n", udc.asm_buf); - DASM_Inst inst = {off, rel_voff, r1u64(inst_strings.total_size, inst_strings.total_size+string.size-1)}; - dasm_inst_chunk_list_push(scratch.arena, &inst_list, 1024, &inst); - str8_list_push(scratch.arena, &inst_strings, string); - - // rjf: increment - off += size; - if(bytes_processed_counter != 0 && (off-byte_process_start_off >= 1000)) - { - ins_atomic_u64_add_eval(bytes_processed_counter, (off-byte_process_start_off)); - byte_process_start_off = off; - } - } - }break; - } - - //- rjf: fill result - DASM_Info info = {0}; - info.text = str8_list_join(arena, &inst_strings, 0); - info.insts = dasm_inst_array_from_chunk_list(arena, &inst_list); - - scratch_end(scratch); - return info; -} - //////////////////////////////// //~ rjf: Main Layer Initialization @@ -406,6 +340,8 @@ dasm_parse_thread__entry_point(void *p) ThreadNameF("[dasm] parse thread #%I64u", (U64)p); for(;;) { + Temp scratch = scratch_begin(0, 0); + //- rjf: get next request U128 hash = {0}; U64 addr = 0; @@ -440,13 +376,89 @@ dasm_parse_thread__entry_point(void *p) data = hs_data_from_hash(hs_scope, hash); } - //- rjf: data -> disassembly info + //- rjf: data * arch * addr -> decode artifacts + DASM_InstChunkList inst_list = {0}; + String8List inst_strings = {0}; + if(got_task) + { + switch(arch) + { + default:{}break; + + //- rjf: x86/x64 decoding + case Architecture_x64: + case Architecture_x86: + { + // rjf: grab context + struct ud udc; + ud_init(&udc); + ud_set_mode(&udc, bit_size_from_arch(arch)); + ud_set_pc(&udc, addr); + ud_set_input_buffer(&udc, data.str, data.size); + ud_set_vendor(&udc, UD_VENDOR_ANY); + ud_set_syntax(&udc, UD_SYN_INTEL); + + // rjf: disassemble + U64 byte_process_start_off = 0; + for(U64 off = 0; off < data.size;) + { + // rjf: disassemble one instruction + U64 size = ud_disassemble(&udc); + if(size == 0) + { + break; + } + + // rjf: analyze + struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(&udc, 0); + U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(&udc, first_op) : 0; + + // rjf: push + String8 string = push_str8f(scratch.arena, "%s", udc.asm_buf); + DASM_Inst inst = {off, rel_voff, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + string.size)}; + dasm_inst_chunk_list_push(scratch.arena, &inst_list, 1024, &inst); + str8_list_push(scratch.arena, &inst_strings, string); + + // rjf: increment + off += size; + } + }break; + } + } + + //- rjf: artifacts -> value bundle Arena *info_arena = 0; DASM_Info info = {0}; - if(got_task && data.size != 0) + if(got_task) { + //- rjf: produce joined text + Arena *text_arena = arena_alloc(); + StringJoin text_join = {0}; + text_join.sep = str8_lit("\n"); + String8 text = str8_list_join(text_arena, &inst_strings, &text_join); + + //- rjf: produce unique key for this disassembly's text + U128 text_key = {0}; + { + U64 hash_data[] = + { + hash.u64[0], + hash.u64[1], + addr, + (U64)arch, + 0x4d534144, + }; + text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data))); + } + + //- rjf: submit text data to hash store + U128 text_hash = hs_submit_data(text_key, &text_arena, text); + + //- rjf: produce value bundle info_arena = arena_alloc(); - info = dasm_info_from_arch_addr_data(info_arena, 0, arch, addr, data); + info.text_key = text_key; + info.insts = dasm_inst_array_from_chunk_list(info_arena, &inst_list); } //- rjf: commit results to cache @@ -466,6 +478,7 @@ dasm_parse_thread__entry_point(void *p) } hs_scope_close(hs_scope); + scratch_end(scratch); } } diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 77657c25..beb71088 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -46,7 +46,7 @@ struct DASM_InstArray typedef struct DASM_Info DASM_Info; struct DASM_Info { - String8 text; + U128 text_key; DASM_InstArray insts; }; @@ -170,11 +170,6 @@ internal DASM_InstArray dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstC internal U64 dasm_inst_array_idx_from_code_off__linear_scan(DASM_InstArray *array, U64 off); internal U64 dasm_inst_array_code_off_from_idx(DASM_InstArray *array, U64 idx); -//////////////////////////////// -//~ rjf: Disassembly Decoding Function - -internal DASM_Info dasm_info_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data); - //////////////////////////////// //~ rjf: Main Layer Initialization @@ -198,6 +193,7 @@ internal void dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_No internal DASM_Info dasm_info_from_hash_addr_arch(DASM_Scope *scope, U128 hash, U64 addr, Architecture arch); internal DASM_Info dasm_info_from_key_addr_arch(DASM_Scope *scope, U128 key, U64 addr, Architecture arch, U128 *hash_out); + //////////////////////////////// //~ rjf: Parse Threads diff --git a/src/df/gfx/df_view_rule_hooks.c b/src/df/gfx/df_view_rule_hooks.c index 1e443aa9..079517bd 100644 --- a/src/df/gfx/df_view_rule_hooks.c +++ b/src/df/gfx/df_view_rule_hooks.c @@ -314,6 +314,36 @@ df_view_rule_hooks__txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ct return result; } +internal DF_DisasmTopologyInfo +df_view_rule_hooks__disasm_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +{ + Temp scratch = scratch_begin(0, 0); + DF_DisasmTopologyInfo result = zero_struct; + { + StringJoin join = {0}; + join.sep = str8_lit(" "); + DF_CfgNode *size_cfg = df_cfg_node_child_from_string(cfg, str8_lit("size"), 0); + DF_CfgNode *arch_cfg = df_cfg_node_child_from_string(cfg, str8_lit("arch"), 0); + String8List size_expr_strs = {0}; + String8 arch_string = {0}; + for(DF_CfgNode *child = size_cfg->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &size_expr_strs, child->string); + } + arch_string = arch_cfg->first->string; + String8 size_expr = str8_list_join(scratch.arena, &size_expr_strs, &join); + DF_Eval size_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, macro_map, size_expr); + DF_Eval size_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, size_eval); + if(str8_match(arch_string, str8_lit("x64"), StringMatchFlag_CaseInsensitive)) + { + result.arch = Architecture_x64; + } + result.size_cap = size_val_eval.imm_u64; + } + scratch_end(scratch); + return result; +} + //////////////////////////////// //~ rjf: "array" @@ -736,6 +766,17 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text) //////////////////////////////// //~ rjf: "disasm" +typedef struct DF_ViewRuleHooks_DisasmState DF_ViewRuleHooks_DisasmState; +struct DF_ViewRuleHooks_DisasmState +{ + B32 initialized; + TxtPt cursor; + TxtPt mark; + S64 preferred_column; + U64 last_open_frame_idx; + F32 loaded_t; +}; + DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(disasm) { DF_EvalVizBlock *vb = df_eval_viz_block_begin(arena, DF_EvalVizBlockKind_Canvas, key, df_expand_key_make(df_hash_from_expand_key(key), 1), depth); @@ -748,7 +789,92 @@ DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(disasm) DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm) { - + Temp scratch = scratch_begin(0, 0); + HS_Scope *hs_scope = hs_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); + DASM_Scope *dasm_scope = dasm_scope_open(); + DF_ViewRuleHooks_DisasmState *state = df_view_rule_block_user_state(key, DF_ViewRuleHooks_DisasmState); + if(!state->initialized) + { + state->initialized = 1; + state->cursor = state->mark = txt_pt(1, 1); + } + if(state->last_open_frame_idx+1 < df_frame_index()) + { + state->loaded_t = 0; + } + state->last_open_frame_idx = df_frame_index(); + { + //- rjf: unpack params + DF_DisasmTopologyInfo top = df_view_rule_hooks__disasm_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + + //- rjf: resolve to address value & range + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); + U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; + Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr + (top.size_cap ? top.size_cap : 2048)); + + //- rjf: unpack thread/process of eval + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + + //- rjf: unpack key for this region in memory + U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0); + + //- rjf: key -> parsed text info + U128 data_hash = {0}; + DASM_Info dasm_info = dasm_info_from_key_addr_arch(dasm_scope, dasm_key, vaddr_range.min, top.arch, &data_hash); + String8 dasm_text_data = {0}; + TXT_TextInfo dasm_text_info = {0}; + for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) + { + U128 dasm_text_hash = hs_hash_from_key(dasm_info.text_key, rewind_idx); + dasm_text_data = hs_data_from_hash(hs_scope, dasm_text_hash); + dasm_text_info = txt_text_info_from_hash_lang(txt_scope, dasm_text_hash, TXT_LangKind_Null); + if(dasm_text_info.lines_count != 0) + { + break; + } + } + TXT_LineTokensSlice line_tokens_slice = txt_line_tokens_slice_from_info_data_line_range(scratch.arena, &dasm_text_info, dasm_text_data, r1s64(1, dasm_info.insts.count)); + + //- rjf: info -> code slice info + DF_CodeSliceParams code_slice_params = {0}; + { + code_slice_params.flags = DF_CodeSliceFlag_LineNums; + code_slice_params.line_num_range = r1s64(1, dasm_text_info.lines_count); + code_slice_params.line_text = push_array(scratch.arena, String8, dasm_text_info.lines_count); + code_slice_params.line_ranges = push_array(scratch.arena, Rng1U64, dasm_text_info.lines_count); + code_slice_params.line_tokens = push_array(scratch.arena, TXT_TokenArray, dasm_text_info.lines_count); + code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, dasm_text_info.lines_count); + code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, dasm_text_info.lines_count); + code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, dasm_text_info.lines_count); + code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, dasm_text_info.lines_count); + code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, dasm_text_info.lines_count); + for(U64 line_idx = 0; line_idx < dasm_text_info.lines_count; line_idx += 1) + { + code_slice_params.line_text[line_idx] = str8_substr(dasm_text_data, dasm_info.insts.v[line_idx].text_range); + code_slice_params.line_ranges[line_idx] = dasm_info.insts.v[line_idx].text_range; + code_slice_params.line_tokens[line_idx] = line_tokens_slice.line_tokens[line_idx]; + } + code_slice_params.font = df_font_from_slot(DF_FontSlot_Code); + code_slice_params.font_size = ui_top_font_size(); + code_slice_params.line_height_px = ui_top_font_size()*1.5f; + code_slice_params.margin_width_px = 0; + code_slice_params.line_num_width_px = ui_top_font_size()*5.f; + code_slice_params.line_text_max_width_px = ui_top_font_size()*2.f*dasm_text_info.lines_max_size; + } + + //- rjf: build code slice + if(dasm_info.insts.count != 0 && dasm_text_info.lines_count != 0) + UI_Padding(ui_pct(1, 0)) UI_PrefWidth(ui_px(dasm_text_info.lines_max_size*ui_top_font_size()*1.2f, 1.f)) UI_Column UI_Padding(ui_pct(1, 0)) + { + DF_CodeSliceSignal sig = df_code_slice(ws, ctrl_ctx, parse_ctx, &code_slice_params, &state->cursor, &state->mark, &state->preferred_column, str8_lit("###code_slice")); + } + } + dasm_scope_close(dasm_scope); + txt_scope_close(txt_scope); + hs_scope_close(hs_scope); + scratch_end(scratch); } //////////////////////////////// diff --git a/src/df/gfx/df_view_rule_hooks.h b/src/df/gfx/df_view_rule_hooks.h index c57d9ca4..4ac8729e 100644 --- a/src/df/gfx/df_view_rule_hooks.h +++ b/src/df/gfx/df_view_rule_hooks.h @@ -29,6 +29,13 @@ struct DF_TxtTopologyInfo U64 size_cap; }; +typedef struct DF_DisasmTopologyInfo DF_DisasmTopologyInfo; +struct DF_DisasmTopologyInfo +{ + Architecture arch; + U64 size_cap; +}; + //////////////////////////////// //~ rjf: Helpers @@ -37,5 +44,6 @@ internal void df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph internal DF_BitmapTopologyInfo df_view_rule_hooks__bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); internal DF_GeoTopologyInfo df_view_rule_hooks__geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); internal DF_TxtTopologyInfo df_view_rule_hooks__txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_DisasmTopologyInfo df_view_rule_hooks__disasm_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); #endif //DF_VIEW_RULE_HOOKS_H