From: Brendan Hansen Date: Tue, 5 Oct 2021 01:02:31 +0000 (-0500) Subject: feature dump X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=8983dc25e1e2ca7a402d7522650fdd7da3f8cbdf;p=onyx-wasm-analyzer.git feature dump --- diff --git a/site/js/decompiler.js b/site/js/decompiler.js index 169dbd3..bc51697 100644 --- a/site/js/decompiler.js +++ b/site/js/decompiler.js @@ -35,5 +35,35 @@ window.ONYX_MODULES.push({ const str = decoder.decode(data); document.getElementById("main_canvas").style.cursor = str; + }, + + local_storage_store: function(keyptr, keylen, valueptr, valuelen) { + const decoder = new TextDecoder(); + + const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen)); + const value = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, valueptr, valuelen)); + + localStorage[key] = value; + }, + + local_storage_value_length: function(keyptr, keylen) { + const decoder = new TextDecoder(); + const encoder = new TextEncoder(); + + const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen)); + + return encoder.encode(localStorage[key]).length; + }, + + local_storage_load: function(keyptr, keylen, bufferptr, bufferlen) { + const decoder = new TextDecoder(); + const encoder = new TextEncoder(); + + const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen)); + + const value_data = encoder.encode(localStorage[key]); + + let WASM_U8 = new Uint8Array(window.ONYX_MEMORY.buffer); + WASM_U8.set(value_data, bufferptr); } }); diff --git a/src/app/app.onyx b/src/app/app.onyx index 41fd065..d1acebb 100644 --- a/src/app/app.onyx +++ b/src/app/app.onyx @@ -1,7 +1,5 @@ package app -use package core - #private_file { events :: package js_events gl :: package gl @@ -10,10 +8,12 @@ use package core config :: package config wasm :: package wasm_utils debug :: package debug -} -use package debug { init as debug_init, debug_log, draw_debug_log } -use package core.intrinsics.onyx { __initialize } + use package core + + use package debug { init as debug_init, debug_log, draw_debug_log } + use package core.intrinsics.onyx { __initialize } +} @Relocate search_buffer: string.String_Buffer; on_file_load_callbacks : Map(u32, (file_event: ^events.Event) -> void); @@ -30,7 +30,7 @@ Tool :: struct { state : Application_State; Application_State :: struct { - colorscheme: Colorscheme; + settings := Application_Settings.{}; has_active_file := false; file := Active_File.{}; @@ -64,7 +64,7 @@ init :: () { __initialize(^state); window_buffer := memory.make_slice(Application_Window, MAXIMUM_WINDOWS); state.windows_store = alloc.pool.make(window_buffer); - map.init(^state.windows_map, hash_count=16); + map.init(^state.windows_map); array.init(^state.windows_sorted); state.window_switcher_state->init(); @@ -77,17 +77,18 @@ init :: () { array.init(^registered_tools); map.init(^on_file_load_callbacks); - colorscheme_switch(.Dark); - load_background_tile_texture(); load_fonts(); + settings_load(^state.settings); + colorscheme_switch(state.settings.colorscheme); + search_buffer = string.buffer_make(memory.make_slice(u8, 256)); gl.enable(gl.BLEND); gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - registered_tools << Tool.{ + registered_tools << .{ id = "load_file_info", name = "File Info", open = () { @@ -235,6 +236,7 @@ handle_event :: (event: ^events.Event) { if event.keyboard->get_name() == "F7" { debug.debug_log_toggle(); + settings_save(^state.settings); break; } @@ -282,6 +284,8 @@ handle_event :: (event: ^events.Event) { state.has_active_file = true; state.file.name = name; state.file.data = data; + + invoke_feature_function("file_loaded"); } } } @@ -311,22 +315,12 @@ draw :: () { ui.workspace_start(main_area, state=^state.workspace_state); draw_background_lines(~~window_width, ~~window_height, line_color=config.Colors.background); - // Used for detecting when a window is completely off-screen and shouldn't be rendered. - transformed_window_rect := window_rectangle; - { - trans := gfx.global_renderer->get_transform(); - transformed_window_rect.x0 -= trans.translation.x / trans.scale.x; - transformed_window_rect.y0 -= trans.translation.y / trans.scale.y; - transformed_window_rect.x1 = transformed_window_rect.x0 + (~~window_width / trans.scale.x); - transformed_window_rect.y1 = transformed_window_rect.y0 + (~~window_height / trans.scale.y); - } - i := 0; new_top: ^Application_Window = null; for window: state.windows_sorted { defer i += 1; - if !(window.window_state->get_rectangle() |> ui.Rectangle.intersects(transformed_window_rect)) do continue; + if !(window.window_state->get_transformed_rectangle() |> ui.Rectangle.intersects(window_rectangle)) do continue; if ui.window_start(^window.window_state, increment=hash.to_u32(window.id)) { new_top = window; diff --git a/src/app/colors.onyx b/src/app/colors.onyx index a0cb148..64c57bb 100644 --- a/src/app/colors.onyx +++ b/src/app/colors.onyx @@ -22,12 +22,10 @@ Colorscheme :: enum { } colorscheme_switch :: (new_scheme: Colorscheme) { - if state.colorscheme == new_scheme do return; - - state.colorscheme = new_scheme; + state.settings.colorscheme = new_scheme; colors_scheme_file: str; - switch state.colorscheme { + switch state.settings.colorscheme { case .Dark do colors_scheme_file = config.dark_color_scheme_file; case .Light do colors_scheme_file = config.light_color_scheme_file; case #default do assert(false, "Bad colorscheme setting."); @@ -80,7 +78,7 @@ load_colors :: (event: ^events.Event) { }; } - debug_log(.Info, "Successfully loaded colorscheme '{}'.", state.colorscheme); + debug_log(.Info, "Successfully loaded colorscheme '{}'.", state.settings.colorscheme); } update_ui_colors :: () { diff --git a/src/app/debug_log.onyx b/src/app/debug_log.onyx index a1b5ebc..fcaba79 100644 --- a/src/app/debug_log.onyx +++ b/src/app/debug_log.onyx @@ -121,20 +121,6 @@ draw_debug_log :: (window_rectangle: ui.Rectangle, site := #callsite) { if ui.button(clear_button_rect, "Clear log") { debug_log_clear(); } - - app :: package app - colorscheme := app.state.colorscheme; - - clear_button_rect.x0 += 220; - clear_button_rect.x1 += 220; - switched := ui.radio(clear_button_rect, ^colorscheme, .Dark, "Dark mode"); - clear_button_rect.x0 += 200; - clear_button_rect.x1 += 200; - switched = switched || ui.radio(clear_button_rect, ^colorscheme, .Light, "Light mode"); - - if switched { - app.colorscheme_switch(colorscheme); - } } #private_file log_buffer : struct { diff --git a/src/app/settings.onyx b/src/app/settings.onyx new file mode 100644 index 0000000..b9b9d34 --- /dev/null +++ b/src/app/settings.onyx @@ -0,0 +1,45 @@ +package app + +#private_file { + json :: package json + __initialize :: (package core.intrinsics.onyx).__initialize + init :: (package core.intrinsics.onyx).init + + use package core + + Settings_Key :: "debugger_settings" +} + +Application_Settings :: struct { + colorscheme := Colorscheme.Undefined; +} + +settings_save :: (settings: ^Application_Settings) { + use type_info; + + root := init(json.Value_Object); + array.init(^root.object_, allocator=context.allocator); + defer json.free(^root, context.allocator); + + json.set(^root, "colorscheme", enum_name(settings.colorscheme), true, true); + + store_value, _ := json.encode_string(^root); + defer string.free(store_value); + + storage.store(Settings_Key, store_value); +} + +settings_load :: (settings: ^Application_Settings) { + use type_info; + + value := storage.load(Settings_Key); + if value.data == null do value = "{}"; + defer if value != "{}" do string.free(value); + + root := json.decode(value); + defer json.free(root); + + colorscheme := enum_value(Colorscheme, root.root["colorscheme"]->as_str()); + if colorscheme != .Undefined do settings.colorscheme = colorscheme; + else do settings.colorscheme = .Dark; +} diff --git a/src/app/storage.onyx b/src/app/storage.onyx new file mode 100644 index 0000000..baa670c --- /dev/null +++ b/src/app/storage.onyx @@ -0,0 +1,27 @@ +// Simple local-storage wrapper + +package app.storage + +#private_file { + memory :: package core.memory +} + +store :: (key: str, value: [] u8) { + __local_storage_store(key, value); +} + +load :: (key: str, allocator := context.allocator) -> str { + buffer_length := __local_storage_value_length(key); + + buffer := memory.make_slice(u8, buffer_length, allocator=allocator); + __local_storage_load(key, buffer); + + return buffer; +} + +#private_file { + __local_storage_store :: (key: str, value: str) -> void #foreign "decompiler" "local_storage_store" --- + __local_storage_value_length :: (key: str) -> i32 #foreign "decompiler" "local_storage_value_length" --- + __local_storage_load :: (key: str, buffer: str) -> void #foreign "decompiler" "local_storage_load" --- +} + diff --git a/src/build.onyx b/src/build.onyx index 96d302b..dbe2d2d 100644 --- a/src/build.onyx +++ b/src/build.onyx @@ -21,6 +21,8 @@ #load "src/app/window_switcher" #load "src/app/window_management" #load "src/app/colors" + #load "src/app/storage" + #load "src/app/settings" #load "src/features/load_features" diff --git a/src/features/hex_editor/hex_viewer.onyx b/src/features/hex_editor/hex_viewer.onyx index 62ced36..b8aacb8 100644 --- a/src/features/hex_editor/hex_viewer.onyx +++ b/src/features/hex_editor/hex_viewer.onyx @@ -156,7 +156,7 @@ open_window :: () { setup :: () { debug_log(.Debug, "Initializing hex viewer...", 0); - app.registered_tools << app.Tool.{ + app.registered_tools << .{ id = window_id, name = window_name, open = open_window, diff --git a/src/features/text_editor/text_editor.onyx b/src/features/text_editor/text_editor.onyx index 5c3e48d..31e1ae6 100644 --- a/src/features/text_editor/text_editor.onyx +++ b/src/features/text_editor/text_editor.onyx @@ -31,9 +31,9 @@ open_text_editor :: () { setup :: () { debug_log(.Debug, "Initializing text editor...", 0); - array.push(^app.registered_tools, .{ + app.registered_tools << .{ id = window_id, name = window_name, open = open_text_editor, - }); + }; } diff --git a/src/features/wasm/feature.onyx b/src/features/wasm/feature.onyx index cf47133..cd52edf 100644 --- a/src/features/wasm/feature.onyx +++ b/src/features/wasm/feature.onyx @@ -4,4 +4,5 @@ package feature.wasm Feature_Wasm_Loader :: struct { setup := setup; -} \ No newline at end of file + file_loaded := file_loaded; +} diff --git a/src/features/wasm/wasm.onyx b/src/features/wasm/wasm.onyx index 5f1657a..fbb79cd 100644 --- a/src/features/wasm/wasm.onyx +++ b/src/features/wasm/wasm.onyx @@ -1,21 +1,118 @@ package feature.wasm #private_file { - app :: package app - ui :: package ui - config :: package config + app :: package app + ui :: package ui + config :: package config + + wasm_utils :: package wasm_utils + WasmBinary :: wasm_utils.WasmBinary + WasmSections :: wasm_utils.WasmSections use package core use package debug { debug_log } - - use package wasm_utils } #private { wasm_state : WasmBinary; wasm_sections : WasmSections; + + wasm_analyzed := false; } setup :: () { debug_log(.Info, "Wasm Loader Loaded from {}", #file); + + app.registered_tools << .{ + id = "wasm_info", + name = "WASM info", + open = () { + app.open_window("wasm_info", "WASM info", .{ 0, 0 }, info_window_draw, .{ 1300, 650 }); + app.move_window_to_top("wasm_info"); + app.focus_window("wasm_info"); + } + }; +} + +if_visible :: macro (r: ui.Rectangle, w: ui.Rectangle, draw: Code) { + if ui.Rectangle.intersects(w, r) { + #insert draw; + } +} + +info_window_draw :: (_, win) => { + if !wasm_analyzed do return; + + rect := ui.Rectangle.{ 0, 0, win.window_state.size.x, win.window_state.size.y }; + + #persist scrollable_region := ui.Scrollable_Region_State.{}; + ui.scrollable_region_start(rect, state=^scrollable_region); + defer ui.scrollable_region_stop(); + + text_theme := ui.default_text_theme; + text_theme.font = config.Fonts.FiraCode.index; + + win_rect := rect; + v := 0x7F7FFFFF; + rect.y1 = *cast(^f32)^v; + rect.x1 = *cast(^f32)^v; + text_rect : ui.Rectangle; + msg_buffer: [512] u8; + + { + text_rect, rect = ui.Flow.split_horizontal(rect, top_height=40); + if_visible(text_rect, win_rect, + #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "Imports: {}", wasm_sections.import_section.count), theme=^text_theme))); + } + + for ^import: wasm_sections.import_section { + text_rect, rect = ui.Flow.split_horizontal(rect, top_height=32); + if_visible(text_rect, win_rect, + #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "{*}", import), theme=^text_theme))); + } + + { + text_rect, rect = ui.Flow.split_horizontal(rect, top_height=40); + if_visible(text_rect, win_rect, + #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "Exports: {}", wasm_sections.export_section.count), theme=^text_theme))); + } + + { + text_rect, rect = ui.Flow.split_horizontal(rect, top_height=40); + if_visible(text_rect, win_rect, + #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "Functions: {}", wasm_sections.code_section.count), theme=^text_theme))); + } + + for ^code: wasm_sections.code_section { + text_rect, rect = ui.Flow.split_horizontal(rect, top_height=32); + if_visible(text_rect, win_rect, + #(ui.draw_text(text_rect, conv.str_format(msg_buffer, "{*}", code), theme=^text_theme))); + } +} + +file_loaded :: () { + if wasm_analyzed { + wasm_utils.free(^wasm_state); + wasm_utils.free_sections(^wasm_sections); + } + + wasm_analyzed = false; + + file_data := app.state.file.data; + debug_log(.Info, "Wasm feature noticed file dropped with size {}", file_data.count); + + if !string.starts_with(file_data, u8.[ 0, #char "a", #char "s", #char "m" ]) do return; + + debug_log(.Info, "THIS IS PROBABLY A WASM BINARY. ANALYZING!!!"); + + wasm_state = wasm_utils.load(file_data, context.allocator); + wasm_sections = wasm_utils.parse_sections(^wasm_state, context.allocator); + + debug_log(.Info, "There are {} functions in this binary.", wasm_sections.code_section.count); + + for ^import: wasm_sections.import_section { + debug_log(.Info, "Import: {*}", import); + } + + wasm_analyzed = true; } diff --git a/src/ui/window.onyx b/src/ui/window.onyx index 2dc486d..5b11afe 100644 --- a/src/ui/window.onyx +++ b/src/ui/window.onyx @@ -2,6 +2,7 @@ package ui #private_file { map :: package core.map + // gfx :: package immediate_mode } // This will be stored by the end user's library. @@ -17,7 +18,7 @@ Window_State :: struct { border_color := gfx.Color4.{ 1, 0, 0 }; background_color := gfx.Color4.{ 0.2, 0.2, 0.2 }; - bar_height := 34.0f; + bar_height := 28.0f; draggable := true; resizable := true; @@ -33,6 +34,36 @@ Window_State :: struct { return .{ position.x - bw, position.y - bw - bar_height, position.x + size.x + bw, position.y + size.y + bw }; } + + get_transformed_rectangle :: (use w: ^Window_State) -> Rectangle { + bw := border_width; + if dragging do bw *= 5; + + r := Rectangle.{ + position.x - bw, position.y - bw - bar_height, + position.x + size.x + bw, position.y + size.y + bw }; + + + trans := gfx.global_renderer->get_transform(); + r.x0 *= trans.scale.x; + r.y0 *= trans.scale.y; + r.x0 += trans.translation.x; + r.y0 += trans.translation.y; + r.x1 *= trans.scale.x; + r.y1 *= trans.scale.y; + r.x1 += trans.translation.x; + r.y1 += trans.translation.y; + + return r; + } + + get_origin_rectangle :: (use w: ^Window_State) -> Rectangle { + bw := border_width; + if dragging do bw *= 5; + + return .{ bw, bw - bar_height, + size.x + bw, size.y + bw }; + } } window_start :: (use state: ^Window_State, site := #callsite, increment := 0) -> bool { @@ -99,11 +130,13 @@ window_start :: (use state: ^Window_State, site := #callsite, increment := 0) -> draw_rect(x, y, w, h, color=state.background_color); title_theme := default_text_theme; - title_theme.font_size = 1.0f; + title_theme.font_size = bar_height / 32.0f; title_theme.text_color = .{ 1, 1, 1 }; @ThemeConfiguration draw_text(.{ x, y - bar_height, x + w, y }, state.title, theme=^title_theme); - if button(.{ x + w - 48, y - bar_height - border_width, x + w + border_width, y }, "X", increment=increment + hash) { + close_theme := default_button_theme; + close_theme.border_width = 0; + if button(.{ x + w - 48, y - bar_height - border_width, x + w + border_width, y }, "X", theme=^close_theme, increment=increment + hash) { state.should_close = true; }