From 6a6b944cd0aa410c601dc70634cea7cb4eb0969b Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sun, 12 Apr 2020 13:51:56 -0500 Subject: [PATCH] Actually finished the expr generation and started implementing function context menus --- app.lua | 2 +- src/ui.lua | 4 + src/ui/components.lua | 77 ++++++++++++- src/wasm/exprs.lua | 256 +++++++++--------------------------------- testing.lua | 2 +- 5 files changed, 134 insertions(+), 207 deletions(-) diff --git a/app.lua b/app.lua index c735a30..fc319fb 100644 --- a/app.lua +++ b/app.lua @@ -24,7 +24,7 @@ function init() rect = Rectangle(0, 0, 1200, 900); background_color = COLORS.background; line_color = COLORS.dark_background; - layer = 10; + layer = 100; } ui.insert_child(globals.ui.root, globals.ui.scrolling_area) diff --git a/src/ui.lua b/src/ui.lua index d3f48a6..8ed6a5c 100644 --- a/src/ui.lua +++ b/src/ui.lua @@ -72,6 +72,10 @@ end function ui.insert_child(parent, child) child.parent = parent table.insert(parent.children, child) + + local inserted_func = component_lookup(child.type, "inserted") + if inserted_func then inserted_func(child) end + ui.sort_children(parent) end diff --git a/src/ui/components.lua b/src/ui/components.lua index 4de52b6..37d65c3 100644 --- a/src/ui/components.lua +++ b/src/ui/components.lua @@ -4,6 +4,7 @@ import { Rectangle = "src.utils:Rectangle"; wasm_text = "src.wasm.text"; + wasm_exprs = "src.wasm.exprs"; globals = "src.globals"; COLORS = "conf:COLOR_SCHEME"; @@ -76,6 +77,41 @@ function drag_rect:mousemoved(x, y, dx, dy) end end +local button = { extends = "rect" } +function button:init(text) + self.text = text + self.color = COLORS.primary_dark + self.hovered_color = COLORS.secondary + self.text_color = COLORS.primary_text + self.click = function() print "Button clicked" end + self.hovered = false +end + +function button:mousemoved(x, y, dx, dy) + self.hovered = self.rect:contains_trans(x, y) +end + +function button:mousereleased(button, x, y) + if ui.focused == self and button == 1 and self.rect:contains_trans(x, y) then + self:click(button, x, y) + elseif ui.focused == self and button == 1 then + ui.focus(nil) + end +end + +function button:predraw() + if self.hovered then + love.graphics.setColor(self.hovered_color) + else + love.graphics.setColor(self.color) + end + love.graphics.rectangle("fill", self.rect.x, self.rect.y, self.rect.w, self.rect.h) + love.graphics.setColor(self.text_color) + love.graphics.printf(self.text, self.rect.x, self.rect.y, self.rect.w, "center") +end + +function button:postdraw() end + local function_block = { extends = "drag_rect" } function function_block:init(wasm_function) self.func = wasm_function @@ -118,10 +154,7 @@ function function_block:mousereleased(button, x, y) if ui.focused == self and button == 2 then self.resize_down = false end if ui.focused == self and button == 3 then - ui.insert_child(self, with(ui.make_element "deletable_rect") { - rect = Rectangle(x, y, 80, 60); - color = { 1, 0, 0 }; - }) + ui.insert_child(self, ui.make_element("function_context_menu", x, y)) end end @@ -216,6 +249,40 @@ function function_block:postdraw() love.graphics.pop() end +local function_context_menu = { extends = "rect" } +function function_context_menu:init(x, y) + self.rect = Rectangle(x, y, 200, 100) + self.color = COLORS.primary + + ui.insert_child(self, with(ui.make_element("button", "View decompiled")) { + click = function_context_menu.btn_view_decompiled; + rect = Rectangle(0, 0, 200, 40) + }) + + ui.focus(self) +end + +function function_context_menu:inserted() + assert(self.parent.type == "function_block", "function context menu only exists on function blocks") + ui.focus(self) +end + +function function_context_menu:mousepressed(button, x, y) + if not self.rect:contains_trans(x, y) then + self.remove = true + return + end + + return rect.mousepressed(self, button, x, y) +end + +function function_context_menu:btn_view_decompiled(button, x, y) + local wasm_func = self.parent.parent.func + print(wasm_func.name .. " ------------------------------------------------") + local lines = wasm_exprs.build_expr(wasm_func, globals.wasm_module) + for _, r in ipairs(lines) do print(r) end +end + local scrolling_area = {} function scrolling_area:init() self.offset = { x = 0; y = 0 } @@ -352,7 +419,9 @@ end ui.register_component "rect" (rect) ui.register_component "drag_rect" (drag_rect) +ui.register_component "button" (button) ui.register_component "function_block" (function_block) +ui.register_component "function_context_menu" (function_context_menu) ui.register_component "scrolling_area" (scrolling_area) return module { diff --git a/src/wasm/exprs.lua b/src/wasm/exprs.lua index 5f957ae..85c0b6d 100644 --- a/src/wasm/exprs.lua +++ b/src/wasm/exprs.lua @@ -26,190 +26,6 @@ This should be quick, just need to look up all the instructions --]] --- TODO: Maybe add type checking at some point? -local stack_opts = { --- Name Inputs, Outputs - ["unreachable"] = { 0, 0 }; - ["nop"] = { 0, 0 }; - - --block is dynamic - --loop is dynamic - --if and else are dynamic - - ["br"] = { 0, 0 }; - ["br_if"] = { 1, 0 }; - ["br_table"] = { 1, 0 }; - ["return"] = { 0, 0 }; - --call is dynamic - --call_indirect is dynamic - - ["drop"] = { 1, 0 }; - ["select"] = { 3, 1 }; - - ["local.get"] = { 0, 1 }; - ["local.set"] = { 1, 0 }; - ["local.tee"] = { 1, 1 }; - ["global.get"] = { 0, 1 }; - ["global.set"] = { 1, 0 }; - - ["i32.load"] = { 1, 1 }; - ["i64.load"] = { 1, 1 }; - ["f32.load"] = { 1, 1 }; - ["f64.load"] = { 1, 1 }; - ["i32.load8_s"] = { 1, 1 }; - ["i32.load8_u"] = { 1, 1 }; - ["i32.load16_s"] = { 1, 1 }; - ["i32.load16_u"] = { 1, 1 }; - ["i64.load8_s"] = { 1, 1 }; - ["i64.load8_u"] = { 1, 1 }; - ["i64.load16_s"] = { 1, 1 }; - ["i64.load16_u"] = { 1, 1 }; - ["i64.load32_s"] = { 1, 1 }; - ["i64.load32_u"] = { 1, 1 }; - ["i32.store"] = { 2, 0 }; - ["i64.store"] = { 2, 0 }; - ["f32.store"] = { 2, 0 }; - ["f64.store"] = { 2, 0 }; - ["i32.store8"] = { 2, 0 }; - ["i32.store16"] = { 2, 0 }; - ["i64.store8"] = { 2, 0 }; - ["i64.store16"] = { 2, 0 }; - ["i64.store32"] = { 2, 0 }; - - ["memory.size"] = { 0, 1 }; - ["memory.grow"] = { 1, 1 }; - - ["i32.const"] = { 0, 1 }; - ["i64.const"] = { 0, 1 }; - ["f32.const"] = { 0, 1 }; - ["f64.const"] = { 0, 1 }; - - ["i32.eqz"] = { 1, 1 }; - ["i32.eq"] = { 2, 1 }; - ["i32.ne"] = { 2, 1 }; - ["i32.lt_s"] = { 2, 1 }; - ["i32.lt_u"] = { 2, 1 }; - ["i32.gt_s"] = { 2, 1 }; - ["i32.gt_u"] = { 2, 1 }; - ["i32.le_s"] = { 2, 1 }; - ["i32.le_u"] = { 2, 1 }; - ["i32.ge_s"] = { 2, 1 }; - ["i32.ge_u"] = { 2, 1 }; - ["i64.eqz"] = { 1, 1 }; - ["i64.eq"] = { 2, 1 }; - ["i64.ne"] = { 2, 1 }; - ["i64.lt_s"] = { 2, 1 }; - ["i64.lt_u"] = { 2, 1 }; - ["i64.gt_s"] = { 2, 1 }; - ["i64.gt_u"] = { 2, 1 }; - ["i64.le_s"] = { 2, 1 }; - ["i64.le_u"] = { 2, 1 }; - ["i64.ge_s"] = { 2, 1 }; - ["i64.ge_u"] = { 2, 1 }; - ["f32.eq"] = { 2, 1 }; - ["f32.ne"] = { 2, 1 }; - ["f32.lt"] = { 2, 1 }; - ["f32.gt"] = { 2, 1 }; - ["f32.le"] = { 2, 1 }; - ["f32.ge"] = { 2, 1 }; - ["f64.eq"] = { 2, 1 }; - ["f64.ne"] = { 2, 1 }; - ["f64.lt"] = { 2, 1 }; - ["f64.gt"] = { 2, 1 }; - ["f64.le"] = { 2, 1 }; - ["f64.ge"] = { 2, 1 }; - ["i32.clz"] = { 1, 1 }; - ["i32.ctz"] = { 1, 1 }; - ["i32.popcnt"] = { 1, 1 }; - ["i32.add"] = { 2, 1 }; - ["i32.sub"] = { 2, 1 }; - ["i32.mul"] = { 2, 1 }; - ["i32.div_s"] = { 2, 1 }; - ["i32.div_u"] = { 2, 1 }; - ["i32.rem_s"] = { 2, 1 }; - ["i32.rem_u"] = { 2, 1 }; - ["i32.and"] = { 2, 1 }; - ["i32.or"] = { 2, 1 }; - ["i32.xor"] = { 2, 1 }; - ["i32.shl"] = { 2, 1 }; - ["i32.shr_s"] = { 2, 1 }; - ["i32.shr_u"] = { 2, 1 }; - ["i32.rotl"] = { 2, 1 }; - ["i32.rotr"] = { 2, 1 }; - ["i64.clz"] = { 1, 1 }; - ["i64.ctz"] = { 1, 1 }; - ["i64.popcnt"] = { 1, 1 }; - ["i64.add"] = { 2, 1 }; - ["i64.sub"] = { 2, 1 }; - ["i64.mul"] = { 2, 1 }; - ["i64.div_s"] = { 2, 1 }; - ["i64.div_u"] = { 2, 1 }; - ["i64.rem_s"] = { 2, 1 }; - ["i64.rem_u"] = { 2, 1 }; - ["i64.and"] = { 2, 1 }; - ["i64.or"] = { 2, 1 }; - ["i64.xor"] = { 2, 1 }; - ["i64.shl"] = { 2, 1 }; - ["i64.shr_s"] = { 2, 1 }; - ["i64.shr_u"] = { 2, 1 }; - ["i64.rotl"] = { 2, 1 }; - ["i64.rotr"] = { 2, 1 }; - ["f32.abs"] = { 1, 1 }; - ["f32.neg"] = { 1, 1 }; - ["f32.ceil"] = { 1, 1 }; - ["f32.floor"] = { 1, 1 }; - ["f32.trunc"] = { 1, 1 }; - ["f32.nearest"] = { 1, 1 }; - ["f32.sqrt"] = { 1, 1 }; - ["f32.add"] = { 2, 1 }; - ["f32.sub"] = { 2, 1 }; - ["f32.mul"] = { 2, 1 }; - ["f32.div"] = { 2, 1 }; - ["f32.min"] = { 2, 1 }; - ["f32.max"] = { 2, 1 }; - ["f32.copysign"] = { 2, 1 }; - ["f64.abs"] = { 1, 1 }; - ["f64.neg"] = { 1, 1 }; - ["f64.ceil"] = { 1, 1 }; - ["f64.floor"] = { 1, 1 }; - ["f64.trunc"] = { 1, 1 }; - ["f64.nearest"] = { 1, 1 }; - ["f64.sqrt"] = { 1, 1 }; - ["f64.add"] = { 2, 1 }; - ["f64.sub"] = { 2, 1 }; - ["f64.mul"] = { 2, 1 }; - ["f64.div"] = { 2, 1 }; - ["f64.min"] = { 2, 1 }; - ["f64.max"] = { 2, 1 }; - ["f64.copysign"] = { 2, 1 }; - - ["i32.wrap_i64"] = { 1, 1 }; - ["i32.trunc_f32_s"] = { 1, 1 }; - ["i32.trunc_f32_u"] = { 1, 1 }; - ["i32.trunc_f64_s"] = { 1, 1 }; - ["i32.trunc_f64_u"] = { 1, 1 }; - ["i64.extend_i32_s"] = { 1, 1 }; - ["i64.extend_i32_u"] = { 1, 1 }; - ["i64.trunc_f32_s"] = { 1, 1 }; - ["i64.trunc_f32_u"] = { 1, 1 }; - ["i64.trunc_f64_s"] = { 1, 1 }; - ["i64.trunc_f64_u"] = { 1, 1 }; - ["f32.convert_i32_s"] = { 1, 1 }; - ["f32.convert_i32_u"] = { 1, 1 }; - ["f32.convert_i64_s"] = { 1, 1 }; - ["f32.convert_i64_u"] = { 1, 1 }; - ["f32.demote_f64"] = { 1, 1 }; - ["f64.convert_i32_s"] = { 1, 1 }; - ["f64.convert_i32_u"] = { 1, 1 }; - ["f64.convert_i64_s"] = { 1, 1 }; - ["f64.convert_i64_u"] = { 1, 1 }; - ["f64.promote_f32"] = { 1, 1 }; - ["i32.reinterpret_f32"] = { 1, 1 }; - ["i64.reinterpret_f64"] = { 1, 1 }; - ["f32.reinterpret_i32"] = { 1, 1 }; - ["f64.reinterpret_i64"] = { 1, 1 }; -} - local build_instr_list function binop(op) @@ -227,8 +43,9 @@ function cast(to) end end -function func_call(name, nparams) - nparams = nparams or 1 +function func_call(name, nparams, nreturns) + if nparams == nil then nparams = 1 end + if nreturns == nil then nreturns = 1 end return function(stack, instr) local str = name .. "(" local args = "" @@ -237,7 +54,11 @@ function func_call(name, nparams) args = ", " .. val .. args end str = str .. args:sub(3) .. ")" - stack:push(str) + if nreturns == 0 then + return str + else + stack:push(str) + end end end @@ -264,7 +85,18 @@ function expr_br_if(stack, instr) end function expr_br_table(stack, instr) - error "Cannot handle br_table" + local lines = {} + table.insert(lines, "br_table (" .. stack:pop() .. ") {") + local mappings = {} + for i, lab in ipairs(instr.labels) do + table.insert(mappings, tostring(i - 1) .. " => <" .. lab.block.label .. ">") + end + table.insert(mappings, "default => <" .. instr.labeln.block.label .. ">") + for _, line in ipairs(indent(mappings, " ")) do + table.insert(lines, line) + end + table.insert(lines, "}") + return lines end function expr_drop(stack, instr) @@ -325,7 +157,11 @@ function expr_block(stack, instr, func, mod) ) table.insert(lines, 1, "block <" .. instr.label .. "> {") table.insert(lines, "}") - return lines + if #instr.rt == 0 then + return lines + else + stack:push(table.concat(lines, "\n")) + end end function expr_loop(stack, instr, func, mod) @@ -335,7 +171,11 @@ function expr_loop(stack, instr, func, mod) ) table.insert(lines, 1, "loop <" .. instr.label .. "> {") table.insert(lines, "}") - return lines + if #instr.rt == 0 then + return lines + else + stack:push(table.concat(lines, "\n")) + end end function expr_if(stack, instr, func, mod) @@ -355,7 +195,11 @@ function expr_if(stack, instr, func, mod) end end table.insert(lines, "}") - return lines + if #instr.rt == 0 then + return lines + else + stack:push(table.concat(lines, "\n")) + end end function expr_call(stack, instr, func, mod) @@ -363,7 +207,7 @@ function expr_call(stack, instr, func, mod) local nreturns = #mod.funcs[instr.x].type_.result_types local name = mod.funcs[instr.x].name - local res = func_call(name, nparams)(stack, instr, func, mod) + local res = func_call(name, nparams, nreturns)(stack, instr, func, mod) if nreturns >= 1 then stack:push(res) else @@ -371,14 +215,26 @@ function expr_call(stack, instr, func, mod) end end -function call_indirect(stack, instr) - error "Cannot handle call indirect" +function expr_call_indirect(stack, instr, func, mod) + local type_ = mod.types.contents[instr.x + 1] + local nparams = #type_.param_types + local nreturns = #type_.result_types + local addr = stack:pop() + local res = func_call("[" .. addr .. "]", nparams, nreturns)(stack, instr, func, mod) + if nreturns >= 1 then + stack:push(res) + else + return res + end end +function expr_nop() return "nop" end +function expr_unreachable() return "unreachable" end + local expr_generators = { -- Name Inputs, Outputs - ["unreachable"] = { 0, 0 }; - ["nop"] = { 0, 0 }; + ["unreachable"] = expr_unreachable; + ["nop"] = expr_nop; ["block"] = expr_block; ["loop"] = expr_loop; @@ -389,7 +245,7 @@ local expr_generators = { ["br_table"] = expr_br_table; ["return"] = expr_return; ["call"] = expr_call; - --call_indirect is dynamic + ["call_indirect"] = expr_call_indirect; ["drop"] = expr_drop; ["select"] = expr_select; @@ -503,7 +359,7 @@ local expr_generators = { ["i64.rotl"] = binop "rotl"; ["i64.rotr"] = binop "rotr"; ["f32.abs"] = func_call "abs"; - ["f32.neg"] = func_call "neg"; -- TODO: make this better + ["f32.neg"] = func_call "-"; ["f32.ceil"] = func_call "ceil"; ["f32.floor"] = func_call "floor"; ["f32.trunc"] = func_call "trunc"; @@ -517,7 +373,7 @@ local expr_generators = { ["f32.max"] = func_call("max", 2); ["f32.copysign"] = func_call("copysign", 2); ["f64.abs"] = func_call "abs"; - ["f64.neg"] = func_call "neg"; + ["f64.neg"] = func_call "-"; ["f64.ceil"] = func_call "ceil"; ["f64.floor"] = func_call "floor"; ["f64.trunc"] = func_call "trunc"; @@ -558,8 +414,6 @@ local expr_generators = { ["f64.reinterpret_i64"] = cast "f64"; } - --- This works... ish but we should use proper symbols (+-*/) and other things function build_instr_list(instrs, func, mod) local lines = {} local stack = Stack() diff --git a/testing.lua b/testing.lua index 10362d8..9415924 100644 --- a/testing.lua +++ b/testing.lua @@ -12,7 +12,7 @@ local mod = decompile(arg[1]) mod = analyze(mod) -- pprint(mod) -for i, func in ipairs(mod.funcs) do +for i, func in pairs(mod.funcs) do if func.body then print(func.name .. " -----------------------------------") local res = build_expr(func, mod) -- 2.25.1