Lua: memory2: More functions corresponding to memory.*
This commit is contained in:
parent
a8fa742a36
commit
d1176cbf9e
6 changed files with 480 additions and 74 deletions
|
@ -173,8 +173,6 @@ public:
|
|||
return tostring(hashout);
|
||||
}
|
||||
private:
|
||||
sha256(const sha256& x) throw();
|
||||
sha256& operator=(const sha256& x) throw();
|
||||
uint32_t state[8];
|
||||
uint32_t datablock[16];
|
||||
unsigned blockbytes;
|
||||
|
|
13
include/lua/debug.hpp
Normal file
13
include/lua/debug.hpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef _lua_debug__hpp__included__
|
||||
#define _lua_debug__hpp__included__
|
||||
|
||||
#include "internal.hpp"
|
||||
#include "core/debug.hpp"
|
||||
|
||||
template<debug_type type>
|
||||
void handle_registerX(lua::state& L, uint64_t addr, int lfn);
|
||||
|
||||
template<debug_type type>
|
||||
void handle_unregisterX(lua::state& L, uint64_t addr, int lfn);
|
||||
|
||||
#endif
|
135
lua.lyx
135
lua.lyx
|
@ -6909,6 +6909,141 @@ Write value <val> to given memory area <marea> at byte offsets <addr>..., given
|
|||
True increments address by 1, and false decrements address by 1.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
memory2.<marea>:cheat: Set/Clear cheat
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: none memory2.<marea>:cheat(number addr, [number value])
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Set/Clear cheat at offset <addr> of memory area <marea>.
|
||||
If <value> is given, cheat with specified value is set.
|
||||
Otherwise cheat on address is removed.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
memory2.<marea>:sha256: SHA-256
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: string memory2.<marea>:sha256(number addr, number size[, number rows,
|
||||
number stride])
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Compute SHA-256 of <rows> (default 1) chunks of <size> bytes each, starting
|
||||
from offset <addr> of area <marea>.
|
||||
The chunks are separated by <stride>.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
memory2.<marea>:skein: Skein-512-256
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: string memory2.<marea>:skein(number addr, number size[, number rows,
|
||||
number stride])
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Same as memory2.<marea>:sha256, except with Skein-512-256 as hash function.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
memory2.<marea>:store{,cmp}: Copy region to Lua memory with compare
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: none memory2.<marea>:store(number addr, number daddr, number size[,
|
||||
number rows, number stride])
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: boolean memory2.<marea>:storecmp(number addr, number daddr, number
|
||||
size[, number rows, number stride])
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Copy <rows> (default 1) chunks of <size> bytes each, starting from offset
|
||||
<addr> of area <marea>.
|
||||
The chunks are separated by <stride>.
|
||||
The target is Lua host memory, starting from offset <daddr>.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Additionally, the storecmp method returns false if target was modified (otherwis
|
||||
e true).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
memory2.<marea>:readregion: Read region
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax table memory2.<marea>:readregion(number addr, number size)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Read <size> bytes starting from <addr> in <marea> and return as array.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
memory2.<marea>:writeregion: Write region
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax none memory2.<marea>:writeregion(number addr, table data)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Write array <data> to bytes starting from <addr> in <marea>.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
memory2.<marea>:register{read,write,exec}: Register hook
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: function memory2.<marea>:registerread(number addr, function fn);
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: function memory2.<marea>:registerwrite(number addr, function fn);
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: function memory2.<marea>:registerexec(number addr, function fn);
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Register debug callback <fn> of specified type at offset <addr> of memory
|
||||
area <marea>.
|
||||
Returns <fn>.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
memory2.<marea>:unregister{read,write,exec}: Unregister hook
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: none memory2.<marea>:unregisterread(number addr, function fn);
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: none memory2.<marea>:unregisterwrite(number addr, function fn);
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: none memory2.<marea>:unregisterexec(number addr, function fn);
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Unregister debug callback <fn> of specified type at offset <addr> of memory
|
||||
area <marea>.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
\begin_inset Newpage pagebreak
|
||||
\end_inset
|
||||
|
|
BIN
lua.pdf
BIN
lua.pdf
Binary file not shown.
|
@ -244,81 +244,84 @@ namespace
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<debug_type type, bool reg>
|
||||
void handle_registerX(lua::state& L, uint64_t addr, int lfn)
|
||||
{
|
||||
auto& cbl = cbs[addr];
|
||||
template<debug_type type>
|
||||
void handle_registerX(lua::state& L, uint64_t addr, int lfn)
|
||||
{
|
||||
auto& cbl = cbs[addr];
|
||||
|
||||
//Put the context in userdata so it can be gc'd when Lua context is terminated.
|
||||
lua_debug_callback* D = (lua_debug_callback*)L.newuserdata(sizeof(lua_debug_callback));
|
||||
L.newtable();
|
||||
L.pushstring("__gc");
|
||||
L.pushcclosure(&lua_debug_callback::dtor, 0);
|
||||
L.rawset(-3);
|
||||
L.setmetatable(-2);
|
||||
L.pushlightuserdata(&D->addr);
|
||||
L.pushvalue(-2);
|
||||
L.rawset(LUA_REGISTRYINDEX);
|
||||
L.pop(1); //Pop the copy of object.
|
||||
|
||||
cbl.push_back(D);
|
||||
|
||||
D->dead = false;
|
||||
D->addr = addr;
|
||||
D->type = type;
|
||||
D->lua_fn = L.topointer(lfn);
|
||||
lua::state* LL = &L.get_master();
|
||||
void* D2 = &D->type;
|
||||
if(type != DEBUG_TRACE)
|
||||
D->h = debug_add_callback(addr, type, [LL, D2](uint64_t addr, uint64_t value) {
|
||||
LL->pushlightuserdata(D2);
|
||||
LL->rawget(LUA_REGISTRYINDEX);
|
||||
LL->pushnumber(addr);
|
||||
LL->pushnumber(value);
|
||||
do_lua_error(*LL, LL->pcall(2, 0, 0));
|
||||
}, [LL, D]() {
|
||||
LL->pushlightuserdata(&D->addr);
|
||||
LL->pushnil();
|
||||
LL->rawset(LUA_REGISTRYINDEX);
|
||||
D->_dtor(LL->handle());
|
||||
});
|
||||
else
|
||||
D->h = debug_add_trace_callback(addr, [LL, D2](uint64_t proc, const char* str) {
|
||||
LL->pushlightuserdata(D2);
|
||||
LL->rawget(LUA_REGISTRYINDEX);
|
||||
LL->pushnumber(proc);
|
||||
LL->pushstring(str);
|
||||
do_lua_error(*LL, LL->pcall(2, 0, 0));
|
||||
}, [LL, D]() {
|
||||
LL->pushlightuserdata(&D->addr);
|
||||
LL->pushnil();
|
||||
LL->rawset(LUA_REGISTRYINDEX);
|
||||
D->_dtor(LL->handle());
|
||||
});
|
||||
L.pushlightuserdata(D2);
|
||||
L.pushvalue(lfn);
|
||||
//Put the context in userdata so it can be gc'd when Lua context is terminated.
|
||||
lua_debug_callback* D = (lua_debug_callback*)L.newuserdata(sizeof(lua_debug_callback));
|
||||
L.newtable();
|
||||
L.pushstring("__gc");
|
||||
L.pushcclosure(&lua_debug_callback::dtor, 0);
|
||||
L.rawset(-3);
|
||||
L.setmetatable(-2);
|
||||
L.pushlightuserdata(&D->addr);
|
||||
L.pushvalue(-2);
|
||||
L.rawset(LUA_REGISTRYINDEX);
|
||||
L.pop(1); //Pop the copy of object.
|
||||
|
||||
cbl.push_back(D);
|
||||
|
||||
D->dead = false;
|
||||
D->addr = addr;
|
||||
D->type = type;
|
||||
D->lua_fn = L.topointer(lfn);
|
||||
lua::state* LL = &L.get_master();
|
||||
void* D2 = &D->type;
|
||||
if(type != DEBUG_TRACE)
|
||||
D->h = debug_add_callback(addr, type, [LL, D2](uint64_t addr, uint64_t value) {
|
||||
LL->pushlightuserdata(D2);
|
||||
LL->rawget(LUA_REGISTRYINDEX);
|
||||
LL->pushnumber(addr);
|
||||
LL->pushnumber(value);
|
||||
do_lua_error(*LL, LL->pcall(2, 0, 0));
|
||||
}, [LL, D]() {
|
||||
LL->pushlightuserdata(&D->addr);
|
||||
LL->pushnil();
|
||||
LL->rawset(LUA_REGISTRYINDEX);
|
||||
D->_dtor(LL->handle());
|
||||
});
|
||||
else
|
||||
D->h = debug_add_trace_callback(addr, [LL, D2](uint64_t proc, const char* str) {
|
||||
LL->pushlightuserdata(D2);
|
||||
LL->rawget(LUA_REGISTRYINDEX);
|
||||
LL->pushnumber(proc);
|
||||
LL->pushstring(str);
|
||||
do_lua_error(*LL, LL->pcall(2, 0, 0));
|
||||
}, [LL, D]() {
|
||||
LL->pushlightuserdata(&D->addr);
|
||||
LL->pushnil();
|
||||
LL->rawset(LUA_REGISTRYINDEX);
|
||||
D->_dtor(LL->handle());
|
||||
});
|
||||
L.pushlightuserdata(D2);
|
||||
L.pushvalue(lfn);
|
||||
L.rawset(LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
template<debug_type type>
|
||||
void handle_unregisterX(lua::state& L, uint64_t addr, int lfn)
|
||||
{
|
||||
if(!cbs.count(addr))
|
||||
return;
|
||||
auto& cbl = cbs[addr];
|
||||
for(auto i = cbl.begin(); i != cbl.end(); i++) {
|
||||
if((*i)->type != type) continue;
|
||||
if(L.topointer(lfn) != (*i)->lua_fn) continue;
|
||||
L.pushlightuserdata(&(*i)->type);
|
||||
L.pushnil();
|
||||
L.rawset(LUA_REGISTRYINDEX);
|
||||
(*i)->_dtor(L.handle());
|
||||
//Lua will GC the object.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<debug_type type, bool reg>
|
||||
void handle_unregisterX(lua::state& L, uint64_t addr, int lfn)
|
||||
{
|
||||
if(!cbs.count(addr))
|
||||
return;
|
||||
auto& cbl = cbs[addr];
|
||||
for(auto i = cbl.begin(); i != cbl.end(); i++) {
|
||||
if((*i)->type != type) continue;
|
||||
if(L.topointer(lfn) != (*i)->lua_fn) continue;
|
||||
L.pushlightuserdata(&(*i)->type);
|
||||
L.pushnil();
|
||||
L.rawset(LUA_REGISTRYINDEX);
|
||||
(*i)->_dtor(L.handle());
|
||||
//Lua will GC the object.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<debug_type type, bool reg>
|
||||
int lua_registerX(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
|
@ -334,11 +337,11 @@ namespace
|
|||
P(P.function(lfn));
|
||||
|
||||
if(reg) {
|
||||
handle_registerX<type, reg>(L, addr, lfn);
|
||||
handle_registerX<type>(L, addr, lfn);
|
||||
L.pushvalue(lfn);
|
||||
return 1;
|
||||
} else {
|
||||
handle_unregisterX<type, reg>(L, addr, lfn);
|
||||
handle_unregisterX<type>(L, addr, lfn);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include "lua/internal.hpp"
|
||||
#include "lua/debug.hpp"
|
||||
#include "core/memorymanip.hpp"
|
||||
#include "core/memorywatch.hpp"
|
||||
#include "core/moviedata.hpp"
|
||||
#include "core/moviefile.hpp"
|
||||
#include "core/rom.hpp"
|
||||
#include "library/sha256.hpp"
|
||||
#include "library/skein.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/serialization.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
|
@ -53,6 +55,12 @@ namespace
|
|||
int info(lua::state& L, lua::parameters& P);
|
||||
template<class T, bool _bswap> int rw(lua::state& L, lua::parameters& P);
|
||||
template<bool write, bool sign> int scattergather(lua::state& L, lua::parameters& P);
|
||||
template<class T> int hash(lua::state& L, lua::parameters& P);
|
||||
template<bool cmp> int storecmp(lua::state& L, lua::parameters& P);
|
||||
int readregion(lua::state& L, lua::parameters& P);
|
||||
int writeregion(lua::state& L, lua::parameters& P);
|
||||
int cheat(lua::state& L, lua::parameters& P);
|
||||
template<debug_type type, bool reg> int registerX(lua::state& L, lua::parameters& P);
|
||||
std::string print()
|
||||
{
|
||||
return vma;
|
||||
|
@ -78,6 +86,40 @@ namespace
|
|||
}
|
||||
};
|
||||
|
||||
struct l_sha256_h
|
||||
{
|
||||
static sha256 create()
|
||||
{
|
||||
return sha256();
|
||||
}
|
||||
static void write(sha256& h, void* b, size_t s)
|
||||
{
|
||||
h.write(reinterpret_cast<uint8_t*>(b), s);
|
||||
}
|
||||
static std::string read(sha256& h)
|
||||
{
|
||||
return h.read();
|
||||
}
|
||||
};
|
||||
|
||||
struct l_skein_h
|
||||
{
|
||||
static skein::hash create()
|
||||
{
|
||||
return skein::hash(skein::hash::PIPE_512, 256);
|
||||
}
|
||||
static void write(skein::hash& h, void* b, size_t s)
|
||||
{
|
||||
h.write(reinterpret_cast<uint8_t*>(b), s);
|
||||
}
|
||||
static std::string read(skein::hash& h)
|
||||
{
|
||||
uint8_t buf[32];
|
||||
h.read(buf);
|
||||
return hex::b_to(buf, 32);
|
||||
}
|
||||
};
|
||||
|
||||
lua::_class<lua_vma> class_vma(lua_class_memory, "VMA", {}, {
|
||||
{"info", &lua_vma::info},
|
||||
{"read", &lua_vma::scattergather<false, false>},
|
||||
|
@ -107,6 +149,19 @@ namespace
|
|||
{"iqword", &lua_vma::rw<uint64_t, true>},
|
||||
{"ifloat", &lua_vma::rw<float, true>},
|
||||
{"idouble", &lua_vma::rw<double, true>},
|
||||
{"cheat", &lua_vma::cheat},
|
||||
{"sha256", &lua_vma::hash<l_sha256_h>},
|
||||
{"skein", &lua_vma::hash<l_skein_h>},
|
||||
{"store", &lua_vma::storecmp<false>},
|
||||
{"storecmp", &lua_vma::storecmp<true>},
|
||||
{"readregion", &lua_vma::readregion},
|
||||
{"writeregion", &lua_vma::writeregion},
|
||||
{"registerread", &lua_vma::registerX<DEBUG_READ, true>},
|
||||
{"unregisterread", &lua_vma::registerX<DEBUG_READ, false>},
|
||||
{"registerwrite", &lua_vma::registerX<DEBUG_WRITE, true>},
|
||||
{"unregisterwrite", &lua_vma::registerX<DEBUG_WRITE, false>},
|
||||
{"registerexec", &lua_vma::registerX<DEBUG_EXEC, true>},
|
||||
{"unregisterexec", &lua_vma::registerX<DEBUG_EXEC, false>},
|
||||
}, &lua_vma::print);
|
||||
|
||||
lua::_class<lua_vma_list> class_vmalist(lua_class_memory, "VMALIST", {
|
||||
|
@ -192,6 +247,208 @@ namespace
|
|||
return write ? 0 : 1;
|
||||
}
|
||||
|
||||
template<class T> int lua_vma::hash(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
uint64_t addr, size, rows, stride = 0;
|
||||
bool equals = true;
|
||||
|
||||
P(P.skipped(), addr, size, P.optional(rows, 1));
|
||||
if(rows > 1) P(stride);
|
||||
|
||||
//First verify that all reads are to the region.
|
||||
uint64_t tmp = addr;
|
||||
if(size > vmasize && rows)
|
||||
throw std::runtime_error("Region out of range");
|
||||
for(uint64_t i = 0; i < rows; i++) {
|
||||
if(tmp >= vmasize || tmp + size > vmasize)
|
||||
throw std::runtime_error("Region out of range");
|
||||
tmp += stride;
|
||||
}
|
||||
|
||||
auto hstate = T::create();
|
||||
//Try to map the VMA.
|
||||
char* vmabuf = lsnes_memory.get_physical_mapping(vmabase, vmasize);
|
||||
if(vmabuf) {
|
||||
for(uint64_t i = 0; i < rows; i++) {
|
||||
T::write(hstate, vmabuf + addr, size);
|
||||
addr += stride;
|
||||
}
|
||||
} else {
|
||||
uint8_t buf[512]; //Must be power of 2.
|
||||
unsigned bf = 0;
|
||||
for(uint64_t i = 0; i < rows; i++) {
|
||||
for(uint64_t j = 0; j < size; j++) {
|
||||
buf[bf] = lsnes_memory.read<uint8_t>(vmabase + addr + j);
|
||||
bf = (bf + 1) & (sizeof(buf) - 1);
|
||||
if(!bf)
|
||||
T::write(hstate, buf, sizeof(buf));
|
||||
}
|
||||
addr += stride;
|
||||
}
|
||||
if(bf)
|
||||
T::write(hstate, buf, bf);
|
||||
}
|
||||
L.pushlstring(T::read(hstate));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_vma::readregion(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
uint64_t addr, size;
|
||||
|
||||
P(P.skipped(), addr, size);
|
||||
|
||||
if(addr >= vmasize || size > vmasize || addr + size > vmasize)
|
||||
throw std::runtime_error("Read out of range");
|
||||
|
||||
L.newtable();
|
||||
char* vmabuf = lsnes_memory.get_physical_mapping(vmabase, vmasize);
|
||||
if(vmabuf) {
|
||||
uint64_t ctr = 1;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
L.pushnumber(ctr++);
|
||||
L.pushnumber(static_cast<unsigned char>(vmabuf[addr + i]));
|
||||
L.settable(-3);
|
||||
}
|
||||
} else {
|
||||
uint64_t ctr = 1;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
L.pushnumber(ctr++);
|
||||
L.pushnumber(lsnes_memory.read<uint8_t>(addr + i));
|
||||
L.settable(-3);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_vma::writeregion(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
uint64_t addr;
|
||||
int ltbl;
|
||||
|
||||
P(P.skipped(), addr, P.table(ltbl));
|
||||
|
||||
auto g = lsnes_memory.lookup(vmabase);
|
||||
if(!g.first || g.first->readonly)
|
||||
throw std::runtime_error("Memory address is read-only");
|
||||
if(addr >= vmasize)
|
||||
throw std::runtime_error("Write out of range");
|
||||
|
||||
uint64_t ctr = 1;
|
||||
char* vmabuf = lsnes_memory.get_physical_mapping(vmabase, vmasize);
|
||||
if(vmabuf) {
|
||||
for(size_t i = 0;; i++) {
|
||||
L.pushnumber(ctr++);
|
||||
L.gettable(ltbl);
|
||||
if(L.type(-1) == LUA_TNIL)
|
||||
break;
|
||||
if(addr + i >= vmasize)
|
||||
throw std::runtime_error("Write out of range");
|
||||
vmabuf[addr + i] = L.tointeger(-1);
|
||||
L.pop(1);
|
||||
}
|
||||
} else {
|
||||
for(size_t i = 0;; i++) {
|
||||
L.pushnumber(ctr++);
|
||||
L.gettable(ltbl);
|
||||
if(L.type(-1) == LUA_TNIL)
|
||||
break;
|
||||
if(addr + i >= vmasize)
|
||||
throw std::runtime_error("Write out of range");
|
||||
lsnes_memory.write<uint8_t>(vmabase + addr + i, L.tointeger(-1));
|
||||
L.pop(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<bool cmp> int lua_vma::storecmp(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
uint64_t addr, daddr, size, rows, stride = 0;
|
||||
bool equals = true;
|
||||
|
||||
P(P.skipped(), addr, daddr, size, P.optional(rows, 1));
|
||||
if(rows > 1) P(stride);
|
||||
|
||||
//First verify that all reads are to the region.
|
||||
uint64_t tmp = addr;
|
||||
if(size > vmasize && rows)
|
||||
throw std::runtime_error("Source out of range");
|
||||
for(uint64_t i = 0; i < rows; i++) {
|
||||
if(tmp >= vmasize || tmp + size > vmasize)
|
||||
throw std::runtime_error("Source out of range");
|
||||
tmp += stride;
|
||||
}
|
||||
//Calculate new size of target.
|
||||
auto& h = movb.get_mfile().host_memory;
|
||||
size_t rsize = size * rows;
|
||||
if(size && rsize / size != rows)
|
||||
throw std::runtime_error("Copy size out of range");
|
||||
if((size_t)daddr + rsize < rsize)
|
||||
throw std::runtime_error("Target out of range");
|
||||
if(daddr + rsize > h.size()) {
|
||||
h.resize(daddr + rsize);
|
||||
equals = false;
|
||||
}
|
||||
|
||||
//Try to map the VMA.
|
||||
char* vmabuf = lsnes_memory.get_physical_mapping(vmabase, vmasize);
|
||||
if(vmabuf) {
|
||||
for(uint64_t i = 0; i < rows; i++) {
|
||||
bool eq = (cmp && !memcmp(&h[daddr], vmabuf + addr, size));
|
||||
if(!eq)
|
||||
memcpy(&h[daddr], vmabuf + addr, size);
|
||||
equals &= eq;
|
||||
addr += stride;
|
||||
daddr += size;
|
||||
}
|
||||
} else {
|
||||
for(uint64_t i = 0; i < rows; i++) {
|
||||
for(uint64_t j = 0; j < size; j++) {
|
||||
uint8_t byte = lsnes_memory.read<uint8_t>(vmabase + addr + j);
|
||||
bool eq = (cmp && ((uint8_t)h[daddr + j] == byte));
|
||||
h[daddr + j] = byte;
|
||||
equals &= eq;
|
||||
}
|
||||
addr += stride;
|
||||
daddr += size;
|
||||
}
|
||||
}
|
||||
if(cmp) L.pushboolean(equals);
|
||||
return cmp ? 1 : 0;
|
||||
}
|
||||
|
||||
template<debug_type type, bool reg> int lua_vma::registerX(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
uint64_t addr;
|
||||
int lfn;
|
||||
P(P.skipped(), addr, P.function(lfn));
|
||||
|
||||
if(reg) {
|
||||
handle_registerX<type>(L, vmabase + addr, lfn);
|
||||
L.pushvalue(lfn);
|
||||
return 1;
|
||||
} else {
|
||||
handle_unregisterX<type>(L, vmabase + addr, lfn);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int lua_vma::cheat(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
uint64_t addr, value;
|
||||
|
||||
P(P.skipped(), addr);
|
||||
if(addr >= vmasize)
|
||||
throw std::runtime_error("Address out of range");
|
||||
if(P.is_novalue()) {
|
||||
debug_clear_cheat(vmabase + addr);
|
||||
} else {
|
||||
P(value);
|
||||
debug_set_cheat(vmabase + addr, value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_vma_list::lua_vma_list(lua::state& L)
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue