summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-08-17 14:32:04 +0400
committerAlexander Gavrilov2012-08-17 15:07:48 +0400
commitbcc41c081a43a68042c4757a6569cb690098d9b8 (patch)
tree583f40741778c0e0634fd50610cf6c6f4d979a05 /library
parent509d9570908e1befa537d10285942006d148b3a3 (diff)
downloaddfhack-bcc41c081a43a68042c4757a6569cb690098d9b8.tar.gz
dfhack-bcc41c081a43a68042c4757a6569cb690098d9b8.tar.bz2
dfhack-bcc41c081a43a68042c4757a6569cb690098d9b8.tar.xz
Add a utility function for patching read-only memory.
Diffstat (limited to 'library')
-rw-r--r--library/Core.cpp50
-rw-r--r--library/LuaApi.cpp12
-rw-r--r--library/include/MemAccess.h3
3 files changed, 65 insertions, 0 deletions
diff --git a/library/Core.cpp b/library/Core.cpp
index 826576b7..f129d952 100644
--- a/library/Core.cpp
+++ b/library/Core.cpp
@@ -1548,6 +1548,56 @@ void ClassNameCheck::getKnownClassNames(std::vector<std::string> &names)
names.push_back(*it);
}
+bool Process::patchMemory(void *target, const void* src, size_t count)
+{
+ uint8_t *sptr = (uint8_t*)target;
+ uint8_t *eptr = sptr + count;
+
+ // Find the valid memory ranges
+ std::vector<t_memrange> ranges;
+ getMemRanges(ranges);
+
+ unsigned start = 0;
+ while (start < ranges.size() && ranges[start].end <= sptr)
+ start++;
+ if (start >= ranges.size() || ranges[start].start > sptr)
+ return false;
+
+ unsigned end = start+1;
+ while (end < ranges.size() && ranges[end].start < eptr)
+ {
+ if (ranges[end].start != ranges[end-1].end)
+ return false;
+ end++;
+ }
+ if (ranges[end-1].end < eptr)
+ return false;
+
+ // Verify current permissions
+ for (unsigned i = start; i < end; i++)
+ if (!ranges[i].valid || !(ranges[i].read || ranges[i].execute) || ranges[i].shared)
+ return false;
+
+ // Apply writable permissions & update
+ bool ok = true;
+
+ for (unsigned i = start; i < end && ok; i++)
+ {
+ t_memrange perms = ranges[i];
+ perms.write = perms.read = true;
+ if (!setPermisions(perms, perms))
+ ok = false;
+ }
+
+ if (ok)
+ memmove(target, src, count);
+
+ for (unsigned i = start; i < end && ok; i++)
+ setPermisions(ranges[i], ranges[i]);
+
+ return ok;
+}
+
/*******************************************************************************
M O D U L E S
*******************************************************************************/
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index b0a085ec..108dba88 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -1124,6 +1124,17 @@ static int internal_getMemRanges(lua_State *L)
return 1;
}
+static int internal_patchMemory(lua_State *L)
+{
+ void *dest = checkaddr(L, 1);
+ void *src = checkaddr(L, 2);
+ int size = luaL_checkint(L, 3);
+ if (size < 0) luaL_argerror(L, 1, "negative size");
+ bool ok = Core::getInstance().p->patchMemory(dest, src, size);
+ lua_pushboolean(L, ok);
+ return 1;
+}
+
static int internal_memmove(lua_State *L)
{
void *dest = checkaddr(L, 1);
@@ -1214,6 +1225,7 @@ static const luaL_Reg dfhack_internal_funcs[] = {
{ "setAddress", internal_setAddress },
{ "getVTable", internal_getVTable },
{ "getMemRanges", internal_getMemRanges },
+ { "patchMemory", internal_patchMemory },
{ "memmove", internal_memmove },
{ "memcmp", internal_memcmp },
{ "memscan", internal_memscan },
diff --git a/library/include/MemAccess.h b/library/include/MemAccess.h
index c51df3c6..0e5f618e 100644
--- a/library/include/MemAccess.h
+++ b/library/include/MemAccess.h
@@ -283,6 +283,9 @@ namespace DFHack
/// modify permisions of memory range
bool setPermisions(const t_memrange & range,const t_memrange &trgrange);
+
+ /// write a possibly read-only memory area
+ bool patchMemory(void *target, const void* src, size_t count);
private:
VersionInfo * my_descriptor;
PlatformSpecific *d;