Add a lua api function for patching multiple individual bytes.

develop
Alexander Gavrilov 2012-10-28 11:50:28 +04:00
parent fdaa2a35a1
commit 4aa1999347
5 changed files with 102 additions and 5 deletions

@ -1714,6 +1714,15 @@ global environment, persistent between calls to the script.</p>
If destination overlaps a completely invalid memory region, or another error
occurs, returns false.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.internal.patchBytes(write_table[, verify_table])</tt></p>
<p>The first argument must be a lua table, which is interpreted as a mapping from
memory addresses to byte values that should be stored there. The second argument
may be a similar table of values that need to be checked before writing anything.</p>
<p>The function takes care to either apply all of <tt class="docutils literal">write_table</tt>, or none of it.
An empty <tt class="docutils literal">write_table</tt> with a nonempty <tt class="docutils literal">verify_table</tt> can be used to reasonably
safely check if the memory contains certain values.</p>
<p>Returns <em>true</em> if successful, or <em>nil, error_msg, address</em> if not.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.internal.memmove(dest,src,count)</tt></p>
<p>Wraps the standard memmove function. Accepts both numbers and refs as pointers.</p>
</li>

@ -1581,6 +1581,18 @@ and are only documented here for completeness:
If destination overlaps a completely invalid memory region, or another error
occurs, returns false.
* ``dfhack.internal.patchBytes(write_table[, verify_table])``
The first argument must be a lua table, which is interpreted as a mapping from
memory addresses to byte values that should be stored there. The second argument
may be a similar table of values that need to be checked before writing anything.
The function takes care to either apply all of ``write_table``, or none of it.
An empty ``write_table`` with a nonempty ``verify_table`` can be used to reasonably
safely check if the memory contains certain values.
Returns *true* if successful, or *nil, error_msg, address* if not.
* ``dfhack.internal.memmove(dest,src,count)``
Wraps the standard memmove function. Accepts both numbers and refs as pointers.

@ -1657,14 +1657,11 @@ bool MemoryPatcher::verifyAccess(void *target, size_t count, bool write)
if (!ranges[i].valid || !(ranges[i].read || ranges[i].execute) || ranges[i].shared)
return false;
if (!write)
return true;
// Apply writable permissions & update
for (unsigned i = start; i < end; i++)
{
auto &perms = ranges[i];
if (perms.write && perms.read)
if ((perms.write || !write) && perms.read)
continue;
save.push_back(perms);

@ -1535,6 +1535,81 @@ static int internal_patchMemory(lua_State *L)
return 1;
}
static int internal_patchBytes(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 2);
MemoryPatcher patcher;
if (!lua_isnil(L, 2))
{
luaL_checktype(L, 2, LUA_TTABLE);
lua_pushnil(L);
while (lua_next(L, 2))
{
uint8_t *addr = (uint8_t*)checkaddr(L, -2, true);
int isnum;
uint8_t value = (uint8_t)lua_tounsignedx(L, -1, &isnum);
if (!isnum)
luaL_error(L, "invalid value in verify table");
lua_pop(L, 1);
if (!patcher.verifyAccess(addr, 1, false))
{
lua_pushnil(L);
lua_pushstring(L, "invalid verify address");
lua_pushvalue(L, -3);
return 3;
}
if (*addr != value)
{
lua_pushnil(L);
lua_pushstring(L, "wrong verify value");
lua_pushvalue(L, -3);
return 3;
}
}
}
lua_pushnil(L);
while (lua_next(L, 1))
{
uint8_t *addr = (uint8_t*)checkaddr(L, -2, true);
int isnum;
uint8_t value = (uint8_t)lua_tounsignedx(L, -1, &isnum);
if (!isnum)
luaL_error(L, "invalid value in write table");
lua_pop(L, 1);
if (!patcher.verifyAccess(addr, 1, true))
{
lua_pushnil(L);
lua_pushstring(L, "invalid write address");
lua_pushvalue(L, -3);
return 3;
}
}
lua_pushnil(L);
while (lua_next(L, 1))
{
uint8_t *addr = (uint8_t*)checkaddr(L, -2, true);
uint8_t value = (uint8_t)lua_tounsigned(L, -1);
lua_pop(L, 1);
*addr = value;
}
lua_pushboolean(L, true);
return 1;
}
static int internal_memmove(lua_State *L)
{
void *dest = checkaddr(L, 1);
@ -1626,6 +1701,7 @@ static const luaL_Reg dfhack_internal_funcs[] = {
{ "getVTable", internal_getVTable },
{ "getMemRanges", internal_getMemRanges },
{ "patchMemory", internal_patchMemory },
{ "patchBytes", internal_patchBytes },
{ "memmove", internal_memmove },
{ "memcmp", internal_memcmp },
{ "memscan", internal_memscan },

@ -107,7 +107,8 @@ static void signal_typeid_error(color_ostream *out, lua_State *state,
type_identity *type, const char *msg,
int val_index, bool perr, bool signal)
{
std::string error = stl_sprintf(msg, type->getFullName().c_str());
std::string typestr = type ? type->getFullName() : "any pointer";
std::string error = stl_sprintf(msg, typestr.c_str());
if (signal)
{
@ -134,6 +135,8 @@ void *DFHack::Lua::CheckDFObject(lua_State *state, type_identity *type, int val_
if (lua_isnil(state, val_index))
return NULL;
if (lua_islightuserdata(state, val_index) && !lua_touserdata(state, val_index))
return NULL;
void *rv = get_object_internal(state, type, val_index, exact_type, false);