From 6ce470ad57fe198fca15644d17e6749ea07fa592 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 24 Aug 2016 16:20:30 -0400 Subject: [PATCH] Add basic lua expression support to memview Currently just supports basic field accesses (world.x, screen.y.z). No support for world.x - 4, etc. Closes #976 --- library/lua/utils.lua | 21 +++++++++++ plugins/devel/CMakeLists.txt | 2 +- plugins/devel/memutils.cpp | 71 ++++++++++++++++++++++++++++++++++++ plugins/devel/memutils.h | 3 ++ plugins/devel/memview.cpp | 16 +++++++- 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 plugins/devel/memutils.cpp create mode 100644 plugins/devel/memutils.h diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 24c24c074..408ceaba8 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -652,4 +652,25 @@ function df_shortcut_env() return env end +df_env = df_shortcut_env() + +function df_expr_to_ref(expr) + expr = expr:gsub('%["(.-)"%]', function(field) return '.' .. field end) + :gsub('%[\'(.-)\'%]', function(field) return '.' .. field end) + local parts = split_string(expr, '%.') + local obj = df_env[parts[1]] + for i = 2, #parts do + if i == #parts and type(obj[parts[i]]) ~= 'userdata' then + obj = obj:_field(parts[i]) + else + obj = obj[parts[i]] + end + end + return obj +end + +function addressof(obj) + return select(2, obj:sizeof()) +end + return _ENV diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index e5001fff7..4fb4b5cf5 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -10,7 +10,7 @@ DFHACK_PLUGIN(dumpmats dumpmats.cpp) DFHACK_PLUGIN(eventExample eventExample.cpp) DFHACK_PLUGIN(frozen frozen.cpp) DFHACK_PLUGIN(kittens kittens.cpp) -DFHACK_PLUGIN(memview memview.cpp) +DFHACK_PLUGIN(memview memview.cpp memutils.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(nestboxes nestboxes.cpp) DFHACK_PLUGIN(notes notes.cpp) DFHACK_PLUGIN(onceExample onceExample.cpp) diff --git a/plugins/devel/memutils.cpp b/plugins/devel/memutils.cpp new file mode 100644 index 000000000..5674f2c9c --- /dev/null +++ b/plugins/devel/memutils.cpp @@ -0,0 +1,71 @@ +#include + +#include "Core.h" +#include "LuaTools.h" +#include "LuaWrapper.h" + +using namespace DFHack; +using namespace DFHack::LuaWrapper; +using namespace std; + +namespace memutils { + static lua_State *state; + static color_ostream_proxy *out; + + struct initializer { + Lua::StackUnwinder *unwinder; + initializer() + { + if (!out) + out = new color_ostream_proxy(Core::getInstance().getConsole()); + if (!state) + state = Lua::Open(*out); + unwinder = new Lua::StackUnwinder(state); + } + ~initializer() + { + delete unwinder; + } + }; + + struct cleaner { + ~cleaner() + { + if (state) + { + lua_close(state); + state = NULL; + } + if (out) + { + delete out; + out = NULL; + } + } + }; + + static cleaner g_cleaner; + + void *lua_expr_to_addr(const char *expr) + { + initializer init; + Lua::PushModulePublic(*out, state, "utils", "df_expr_to_ref"); + lua_pushstring(state, expr); + if (!Lua::SafeCall(*out, state, 1, 1)) + { + out->printerr("Failed to evaluate %s\n", expr); + return NULL; + } + + Lua::PushModulePublic(*out, state, "utils", "addressof"); + lua_swap(state); + if (!Lua::SafeCall(*out, state, 1, 1) || !lua_isinteger(state, -1)) + { + out->printerr("Failed to get address: %s\n", expr); + return NULL; + } + + auto addr = uintptr_t(lua_tointeger(state, -1)); + return (void*)addr; + } +} diff --git a/plugins/devel/memutils.h b/plugins/devel/memutils.h new file mode 100644 index 000000000..b94d02a9a --- /dev/null +++ b/plugins/devel/memutils.h @@ -0,0 +1,3 @@ +namespace memutils { + void *lua_expr_to_addr(const char *expr); +} diff --git a/plugins/devel/memview.cpp b/plugins/devel/memview.cpp index 53ee86755..27dc72861 100644 --- a/plugins/devel/memview.cpp +++ b/plugins/devel/memview.cpp @@ -8,6 +8,8 @@ #include #include +#include "memutils.h" + using std::vector; using std::string; using namespace DFHack; @@ -138,7 +140,19 @@ command_result memview (color_ostream &out, vector & parameters) { mymutex->lock(); Core::getInstance().p->getMemRanges(memdata.ranges); - memdata.addr=(void *)convert(parameters[0],true); + if (parameters.empty()) + { + memdata.addr = 0; + } + else if (toLower(parameters[0].substr(0, 2)) == "0x") + { + memdata.addr = (void *)convert(parameters[0],true); + } + else + { + memdata.addr = memutils::lua_expr_to_addr(parameters[0].c_str()); + } + if(memdata.addr==0) { Deinit();