Lua: Deprecate global addresses
[lsnes.git] / src / lua / memory.cpp
blob8800a10e761eba05cdbfb69ee1b682f64ebb3f31
1 #include "core/command.hpp"
2 #include "lua/internal.hpp"
3 #include "core/debug.hpp"
4 #include "core/memorymanip.hpp"
5 #include "core/memorywatch.hpp"
6 #include "core/moviedata.hpp"
7 #include "core/moviefile.hpp"
8 #include "core/rom.hpp"
9 #include "library/sha256.hpp"
10 #include "library/string.hpp"
11 #include "library/skein.hpp"
12 #include "library/minmax.hpp"
13 #include "library/hex.hpp"
14 #include "library/int24.hpp"
16 uint64_t lua_get_vmabase(const std::string& vma)
18 for(auto i : lsnes_memory.get_regions())
19 if(i->name == vma)
20 return i->base;
21 throw std::runtime_error("No such VMA");
24 uint64_t lua_get_read_address(lua::parameters& P)
26 static std::map<std::string, char> deprecation_keys;
27 char* deprecation = &deprecation_keys[P.get_fname()];
28 uint64_t vmabase = 0;
29 if(P.is_string())
30 vmabase = lua_get_vmabase(P.arg<std::string>());
31 else {
32 //Deprecated.
33 if(P.get_state().do_once(deprecation))
34 messages << P.get_fname() << ": Global memory form is deprecated." << std::endl;
36 auto addr = P.arg<uint64_t>();
37 return addr + vmabase;
40 namespace
42 template<typename T, T (memory_space::*rfun)(uint64_t addr),
43 bool (memory_space::*wfun)(uint64_t addr, T value)>
44 void do_rw(lua::state& L, uint64_t addr, bool wrflag)
46 if(wrflag) {
47 T value = L.get_numeric_argument<T>(3, "aperture(write)");
48 (lsnes_memory.*wfun)(addr, value);
49 } else
50 L.pushnumber(static_cast<T>((lsnes_memory.*rfun)(addr)));
53 template<typename T, T (memory_space::*rfun)(uint64_t addr)>
54 int lua_read_memory(lua::state& L, lua::parameters& P)
56 auto addr = lua_get_read_address(P);
57 L.pushnumber(static_cast<T>((lsnes_memory.*rfun)(addr)));
58 return 1;
61 template<typename T, bool (memory_space::*wfun)(uint64_t addr, T value)>
62 int lua_write_memory(lua::state& L, lua::parameters& P)
64 auto addr = lua_get_read_address(P);
65 T value = P.arg<T>();
66 (lsnes_memory.*wfun)(addr, value);
67 return 0;
71 class lua_mmap_struct
73 public:
74 lua_mmap_struct(lua::state& L);
75 static size_t overcommit() { return 0; }
77 ~lua_mmap_struct()
81 int index(lua::state& L, lua::parameters& P)
83 const char* c = L.tostring(2);
84 if(!c) {
85 L.pushnil();
86 return 1;
88 std::string c2(c);
89 if(!mappings.count(c2)) {
90 L.pushnil();
91 return 1;
93 auto& x = mappings[c2];
94 x.rw(L, x.addr, false);
95 return 1;
97 int newindex(lua::state& L, lua::parameters& P)
99 const char* c = L.tostring(2);
100 if(!c)
101 return 0;
102 std::string c2(c);
103 if(!mappings.count(c2))
104 return 0;
105 auto& x = mappings[c2];
106 x.rw(L, x.addr, true);
107 return 0;
109 static int create(lua::state& L, lua::parameters& P)
111 lua::_class<lua_mmap_struct>::create(L);
112 return 1;
114 int map(lua::state& L, lua::parameters& P);
115 std::string print()
117 size_t s = mappings.size();
118 return (stringfmt() << s << " " << ((s != 1) ? "mappings" : "mapping")).str();
120 private:
121 struct mapping
123 mapping() {}
124 mapping(uint64_t _addr, void (*_rw)(lua::state& L, uint64_t addr, bool wrflag))
125 : addr(_addr), rw(_rw)
128 uint64_t addr;
129 void (*rw)(lua::state& L, uint64_t addr, bool wrflag);
131 std::map<std::string, mapping> mappings;
134 namespace
136 template<typename T, T (memory_space::*rfun)(uint64_t addr)>
137 int aperture_read_fun(lua_State* _L)
139 lua::state& mL = *reinterpret_cast<lua::state*>(lua_touserdata(_L, lua_upvalueindex(3)));
140 lua::state L(mL, _L);
142 uint64_t base = L.tonumber(lua_upvalueindex(1));
143 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
144 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
145 size = L.tonumber(lua_upvalueindex(2));
146 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(read)");
147 if(addr > size || addr + base < addr) {
148 L.pushnumber(0);
149 return 1;
151 addr += base;
152 L.pushnumber(static_cast<T>((lsnes_memory.*rfun)(addr)));
153 return 1;
156 template<typename T, bool (memory_space::*wfun)(uint64_t addr, T value)>
157 int aperture_write_fun(lua_State* _L)
159 lua::state& mL = *reinterpret_cast<lua::state*>(lua_touserdata(_L, lua_upvalueindex(3)));
160 lua::state L(mL, _L);
162 uint64_t base = L.tonumber(lua_upvalueindex(1));
163 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
164 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
165 size = L.tonumber(lua_upvalueindex(2));
166 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(write)");
167 if(addr > size || addr + base < addr)
168 return 0;
169 addr += base;
170 T value = L.get_numeric_argument<T>(3, "aperture(write)");
171 (lsnes_memory.*wfun)(addr, value);
172 return 0;
175 template<typename T, T (memory_space::*rfun)(uint64_t addr), bool (memory_space::*wfun)(uint64_t addr,
176 T value)>
177 void aperture_make_fun(lua::state& L, uint64_t base, uint64_t size)
179 L.newtable();
180 L.newtable();
181 L.pushstring( "__index");
182 L.pushnumber(base);
183 if(!(size + 1))
184 L.pushnil();
185 else
186 L.pushnumber(size);
187 L.pushlightuserdata(&L);
188 L.pushcclosure(aperture_read_fun<T, rfun>, 3);
189 L.settable(-3);
190 L.pushstring("__newindex");
191 L.pushnumber(base);
192 if(!(size + 1))
193 L.pushnil();
194 else
195 L.pushnumber(size);
196 L.pushlightuserdata(&L);
197 L.pushcclosure(aperture_write_fun<T, wfun>, 3);
198 L.settable(-3);
199 L.setmetatable(-2);
202 struct lua_debug_callback
204 uint64_t addr;
205 debug_type type;
206 debug_handle h;
207 bool dead;
208 const void* lua_fn;
209 static int dtor(lua_State* L)
211 lua_debug_callback* D = (lua_debug_callback*)lua_touserdata(L, 1);
212 return D->_dtor(L);
214 int _dtor(lua_State* L);
216 std::map<uint64_t, std::list<lua_debug_callback*>> cbs;
218 int lua_debug_callback::_dtor(lua_State* L)
220 if(dead) return 0;
221 dead = true;
222 lua_pushlightuserdata(L, &type);
223 lua_pushnil(L);
224 lua_rawset(L, LUA_REGISTRYINDEX);
225 debug_remove_callback(addr, type, h);
226 for(auto j = cbs[addr].begin(); j != cbs[addr].end(); j++)
227 if(*j == this) {
228 cbs[addr].erase(j);
229 break;
231 if(cbs[addr].empty())
232 cbs.erase(addr);
233 return 0;
236 void do_lua_error(lua::state& L, int ret)
238 if(!ret) return;
239 switch(ret) {
240 case LUA_ERRRUN:
241 messages << "Error in Lua memory callback: " << L.get_string(-1, "errhnd") << std::endl;
242 L.pop(1);
243 return;
244 case LUA_ERRMEM:
245 messages << "Error in Lua memory callback (Out of memory)" << std::endl;
246 return;
247 case LUA_ERRERR:
248 messages << "Error in Lua memory callback (Double fault)" << std::endl;
249 return;
250 default:
251 messages << "Error in Lua memory callback (\?\?\?)" << std::endl;
252 return;
257 template<debug_type type>
258 void handle_registerX(lua::state& L, uint64_t addr, int lfn)
260 auto& cbl = cbs[addr];
262 //Put the context in userdata so it can be gc'd when Lua context is terminated.
263 lua_debug_callback* D = (lua_debug_callback*)L.newuserdata(sizeof(lua_debug_callback));
264 L.newtable();
265 L.pushstring("__gc");
266 L.pushcclosure(&lua_debug_callback::dtor, 0);
267 L.rawset(-3);
268 L.setmetatable(-2);
269 L.pushlightuserdata(&D->addr);
270 L.pushvalue(-2);
271 L.rawset(LUA_REGISTRYINDEX);
272 L.pop(1); //Pop the copy of object.
274 cbl.push_back(D);
276 D->dead = false;
277 D->addr = addr;
278 D->type = type;
279 D->lua_fn = L.topointer(lfn);
280 lua::state* LL = &L.get_master();
281 void* D2 = &D->type;
282 if(type != DEBUG_TRACE)
283 D->h = debug_add_callback(addr, type, [LL, D2](uint64_t addr, uint64_t value) {
284 LL->pushlightuserdata(D2);
285 LL->rawget(LUA_REGISTRYINDEX);
286 LL->pushnumber(addr);
287 LL->pushnumber(value);
288 do_lua_error(*LL, LL->pcall(2, 0, 0));
289 }, [LL, D]() {
290 LL->pushlightuserdata(&D->addr);
291 LL->pushnil();
292 LL->rawset(LUA_REGISTRYINDEX);
293 D->_dtor(LL->handle());
295 else
296 D->h = debug_add_trace_callback(addr, [LL, D2](uint64_t proc, const char* str, bool true_insn) {
297 LL->pushlightuserdata(D2);
298 LL->rawget(LUA_REGISTRYINDEX);
299 LL->pushnumber(proc);
300 LL->pushstring(str);
301 LL->pushboolean(true_insn);
302 do_lua_error(*LL, LL->pcall(3, 0, 0));
303 }, [LL, D]() {
304 LL->pushlightuserdata(&D->addr);
305 LL->pushnil();
306 LL->rawset(LUA_REGISTRYINDEX);
307 D->_dtor(LL->handle());
309 L.pushlightuserdata(D2);
310 L.pushvalue(lfn);
311 L.rawset(LUA_REGISTRYINDEX);
314 template<debug_type type>
315 void handle_unregisterX(lua::state& L, uint64_t addr, int lfn)
317 if(!cbs.count(addr))
318 return;
319 auto& cbl = cbs[addr];
320 for(auto i = cbl.begin(); i != cbl.end(); i++) {
321 if((*i)->type != type) continue;
322 if(L.topointer(lfn) != (*i)->lua_fn) continue;
323 L.pushlightuserdata(&(*i)->type);
324 L.pushnil();
325 L.rawset(LUA_REGISTRYINDEX);
326 (*i)->_dtor(L.handle());
327 //Lua will GC the object.
328 break;
332 typedef void(*dummy1_t)(lua::state& L, uint64_t addr, int lfn);
333 dummy1_t dummy_628963286932869328692386963[] = {
334 handle_registerX<DEBUG_READ>,
335 handle_registerX<DEBUG_WRITE>,
336 handle_registerX<DEBUG_EXEC>,
337 handle_unregisterX<DEBUG_READ>,
338 handle_unregisterX<DEBUG_WRITE>,
339 handle_unregisterX<DEBUG_EXEC>,
342 namespace
344 template<debug_type type, bool reg>
345 int lua_registerX(lua::state& L, lua::parameters& P)
347 uint64_t addr;
348 int lfn;
349 if(P.is_nil() && type != DEBUG_TRACE) {
350 addr = 0xFFFFFFFFFFFFFFFFULL;
351 P.skip();
352 } else if(type != DEBUG_TRACE)
353 addr = lua_get_read_address(P);
354 else
355 P(addr);
356 P(P.function(lfn));
358 if(reg) {
359 handle_registerX<type>(L, addr, lfn);
360 L.pushvalue(lfn);
361 return 1;
362 } else {
363 handle_unregisterX<type>(L, addr, lfn);
364 return 0;
368 command::fnptr<> callbacks_show_lua(lsnes_cmd, "show-lua-callbacks", "", "",
369 []() throw(std::bad_alloc, std::runtime_error) {
370 for(auto& i : cbs)
371 for(auto& j : i.second)
372 messages << "addr=" << j->addr << " type=" << j->type << " handle="
373 << j->h.handle << " dead=" << j->dead << " lua_fn="
374 << j->lua_fn << std::endl;
377 template<typename T, T (memory_space::*rfun)(uint64_t addr), bool (memory_space::*wfun)(uint64_t addr,
378 T value)>
379 int lua_mmap_memory(lua::state& L, lua::parameters& P)
381 if(P.is_novalue()) {
382 static char deprecation;
383 if(L.do_once(&deprecation))
384 messages << P.get_fname() << ": Mapping entiere space is deprecated." << std::endl;
385 aperture_make_fun<T, rfun, wfun>(L.get_master(), 0, 0xFFFFFFFFFFFFFFFFULL);
386 return 1;
388 auto addr = lua_get_read_address(P);
389 auto size = P.arg<uint64_t>();
390 if(!size)
391 throw std::runtime_error("Aperture with zero size is not valid");
392 aperture_make_fun<T, rfun, wfun>(L.get_master(), addr, size - 1);
393 return 1;
396 int handle_push_vma(lua::state& L, memory_region& r)
398 L.newtable();
399 L.pushstring("region_name");
400 L.pushlstring(r.name.c_str(), r.name.size());
401 L.settable(-3);
402 L.pushstring("baseaddr");
403 L.pushnumber(r.base);
404 L.settable(-3);
405 L.pushstring("size");
406 L.pushnumber(r.size);
407 L.settable(-3);
408 L.pushstring("lastaddr");
409 L.pushnumber(r.last_address());
410 L.settable(-3);
411 L.pushstring("readonly");
412 L.pushboolean(r.readonly);
413 L.settable(-3);
414 L.pushstring("iospace");
415 L.pushboolean(r.special);
416 L.settable(-3);
417 L.pushstring("native_endian");
418 L.pushboolean(r.endian == 0);
419 L.settable(-3);
420 L.pushstring("endian");
421 L.pushnumber(r.endian);
422 L.settable(-3);
423 return 1;
426 template<bool write, bool sign> int memory_scattergather(lua::state& L, lua::parameters& P)
428 static char deprecation;
429 uint64_t val = 0;
430 unsigned shift = 0;
431 uint64_t addr = 0;
432 uint64_t vmabase = 0;
433 bool have_vmabase = false;
434 if(write)
435 val = P.arg<uint64_t>();
436 while(P.more()) {
437 if(P.is_boolean()) {
438 if(P.arg<bool>())
439 addr++;
440 else
441 addr--;
442 } else if(P.is_string()) {
443 vmabase = lua_get_vmabase(P.arg<std::string>());
444 have_vmabase = true;
445 continue;
446 } else
447 addr = P.arg<uint64_t>();
448 if(!have_vmabase && L.do_once(&deprecation))
449 messages << P.get_fname() << ": Global memory form is deprecated." << std::endl;
450 if(write)
451 lsnes_memory.write<uint8_t>(addr + vmabase, val >> shift);
452 else
453 val = val + ((uint64_t)lsnes_memory.read<uint8_t>(addr + vmabase) << shift);
454 shift += 8;
456 if(!write) {
457 int64_t sval = val;
458 if(val >= (1ULL << (shift - 1))) sval -= (1ULL << shift);
459 if(sign) L.pushnumber(sval); else L.pushnumber(val);
461 return write ? 0 : 1;
464 #define BLOCKSIZE 256
466 int vma_count(lua::state& L, lua::parameters& P)
468 L.pushnumber(lsnes_memory.get_regions().size());
469 return 1;
472 int cheat(lua::state& L, lua::parameters& P)
474 uint64_t addr, value;
476 addr = lua_get_read_address(P);
478 if(P.is_novalue()) {
479 debug_clear_cheat(addr);
480 } else {
481 P(value);
482 debug_set_cheat(addr, value);
484 return 0;
487 int setxmask(lua::state& L, lua::parameters& P)
489 auto value = P.arg<uint64_t>();
490 debug_setxmask(value);
491 return 0;
494 int read_vma(lua::state& L, lua::parameters& P)
496 uint32_t num;
498 P(num);
500 std::list<memory_region*> regions = lsnes_memory.get_regions();
501 uint32_t j = 0;
502 for(auto i = regions.begin(); i != regions.end(); i++, j++)
503 if(j == num)
504 return handle_push_vma(L, **i);
505 L.pushnil();
506 return 1;
509 int find_vma(lua::state& L, lua::parameters& P)
511 uint64_t addr;
513 P(addr);
515 auto r = lsnes_memory.lookup(addr);
516 if(r.first)
517 return handle_push_vma(L, *r.first);
518 L.pushnil();
519 return 1;
522 int hash_state(lua::state& L, lua::parameters& P)
524 auto x = our_rom.save_core_state();
525 size_t offset = x.size() - 32;
526 L.pushlstring(hex::b_to((uint8_t*)&x[offset], 32));
527 return 1;
530 template<typename H, void(*update)(H& state, const char* mem, size_t memsize),
531 std::string(*read)(H& state), bool extra>
532 int hash_core(H& state, lua::state& L, lua::parameters& P)
534 std::string hash;
535 uint64_t addr, size, low, high;
536 uint64_t stride = 0, rows = 1;
537 bool mappable = true;
538 char buffer[BLOCKSIZE];
540 addr = lua_get_read_address(P);
541 P(size);
542 if(extra) {
543 P(P.optional(rows, 1));
544 if(rows > 1)
545 P(stride);
548 rpair(low, high) = memoryspace_row_bounds(addr, size, rows, stride);
549 if(low > high || high - low + 1 == 0)
550 mappable = false;
552 char* pbuffer = mappable ? lsnes_memory.get_physical_mapping(low, high - low + 1) : NULL;
553 if(low > high) {
554 } else if(pbuffer) {
555 uint64_t offset = addr - low;
556 for(uint64_t i = 0; i < rows; i++) {
557 update(state, pbuffer + offset, size);
558 offset += stride;
560 } else {
561 uint64_t offset = addr;
562 for(uint64_t i = 0; i < rows; i++) {
563 size_t sz = size;
564 while(sz > 0) {
565 size_t ssz = min(sz, static_cast<size_t>(BLOCKSIZE));
566 for(size_t i = 0; i < ssz; i++)
567 buffer[i] = lsnes_memory.read<uint8_t>(offset + i);
568 offset += ssz;
569 sz -= ssz;
570 update(state, buffer, ssz);
572 offset += (stride - size);
575 hash = read(state);
576 L.pushlstring(hash);
577 return 1;
580 void lua_sha256_update(sha256& s, const char* ptr, size_t size)
582 s.write(ptr, size);
585 std::string lua_sha256_read(sha256& s)
587 return s.read();
590 void lua_skein_update(skein::hash& s, const char* ptr, size_t size)
592 s.write(reinterpret_cast<const uint8_t*>(ptr), size);
595 std::string lua_skein_read(skein::hash& s)
597 uint8_t buf[32];
598 s.read(buf);
599 return hex::b_to(buf, 32, false);
602 template<bool extended>
603 int hash_region(lua::state& L, lua::parameters& P)
605 sha256 h;
606 return hash_core<sha256, lua_sha256_update, lua_sha256_read, extended>(h, L, P);
609 int hash_region_skein(lua::state& L, lua::parameters& P)
611 skein::hash h(skein::hash::PIPE_512, 256);
612 return hash_core<skein::hash, lua_skein_update, lua_skein_read, true>(h, L, P);
615 template<bool cmp>
616 int copy_to_host(lua::state& L, lua::parameters& P)
618 uint64_t addr, daddr, size, low, high;
619 uint64_t stride = 0, rows = 1;
620 bool equals = true, mappable = true;
622 addr = lua_get_read_address(P);
623 P(daddr, size, P.optional(rows, 1));
624 if(rows > 1)
625 P(stride);
627 rpair(low, high) = memoryspace_row_bounds(addr, size, rows, stride);
628 if(low > high || high - low + 1 == 0)
629 mappable = false;
630 if(rows && (size_t)(size * rows) / rows != size)
631 throw std::runtime_error("Size to copy too large");
632 if((size_t)(daddr + rows * size) < daddr)
633 throw std::runtime_error("Size to copy too large");
635 auto& h = movb.get_mfile().host_memory;
636 if(daddr + rows * size > h.size()) {
637 equals = false;
638 h.resize(daddr + rows * size);
641 char* pbuffer = mappable ? lsnes_memory.get_physical_mapping(low, high - low + 1) : NULL;
642 if(!size && !rows) {
643 } else if(pbuffer) {
644 //Mapable.
645 uint64_t offset = addr - low;
646 for(uint64_t i = 0; i < rows; i++) {
647 bool eq = (cmp && !memcmp(&h[daddr + i * size], pbuffer + offset, size));
648 if(!eq)
649 memcpy(&h[daddr + i * size], pbuffer + offset, size);
650 equals &= eq;
651 offset += stride;
653 } else {
654 //Not mapable.
655 for(uint64_t i = 0; i < rows; i++) {
656 uint64_t addr1 = addr + i * stride;
657 uint64_t addr2 = daddr + i * size;
658 for(uint64_t j = 0; j < size; j++) {
659 uint8_t byte = lsnes_memory.read<uint8_t>(addr1 + j);
660 bool eq = (cmp && h[addr2 + j] == (char)byte);
661 if(!eq)
662 h[addr2 + j] = byte;
663 equals &= eq;
667 if(cmp)
668 L.pushboolean(equals);
669 return cmp ? 1 : 0;
672 int readregion(lua::state& L, lua::parameters& P)
674 uint64_t addr, size;
676 addr = lua_get_read_address(P);
677 P(size);
679 L.newtable();
680 char buffer[BLOCKSIZE];
681 uint64_t ctr = 0;
682 while(size > 0) {
683 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
684 lsnes_memory.read_range(addr, buffer, rsize);
685 for(size_t i = 0; i < rsize; i++) {
686 L.pushnumber(ctr++);
687 L.pushnumber(static_cast<unsigned char>(buffer[i]));
688 L.settable(-3);
690 addr += rsize;
691 size -= rsize;
693 return 1;
696 int writeregion(lua::state& L, lua::parameters& P)
698 uint64_t addr, size;
699 int ltbl;
701 addr = lua_get_read_address(P);
702 P(size, P.table(ltbl));
704 char buffer[BLOCKSIZE];
705 uint64_t ctr = 0;
706 while(size > 0) {
707 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
708 for(size_t i = 0; i < rsize; i++) {
709 L.pushnumber(ctr++);
710 L.gettable(ltbl);
711 buffer[i] = L.tointeger(-1);
712 L.pop(1);
714 lsnes_memory.write_range(addr, buffer, rsize);
715 addr += rsize;
716 size -= rsize;
718 return 1;
721 lua::functions memoryfuncs(lua_func_misc, "memory", {
722 {"vma_count", vma_count},
723 {"cheat", cheat},
724 {"setxmask", setxmask},
725 {"read_vma", read_vma},
726 {"find_vma", find_vma},
727 {"hash_state", hash_state},
728 {"hash_region", hash_region<false>},
729 {"hash_region2", hash_region<true>},
730 {"hash_region_skein", hash_region_skein},
731 {"store", copy_to_host<false>},
732 {"storecmp", copy_to_host<true>},
733 {"readregion", readregion},
734 {"writeregion", readregion},
735 {"read_sg", memory_scattergather<false, false>},
736 {"sread_sg", memory_scattergather<false, true>},
737 {"write_sg", memory_scattergather<true, false>},
738 {"readbyte", lua_read_memory<uint8_t, &memory_space::read<uint8_t>>},
739 {"readsbyte", lua_read_memory<int8_t, &memory_space::read<int8_t>>},
740 {"readword", lua_read_memory<uint16_t, &memory_space::read<uint16_t>>},
741 {"readsword", lua_read_memory<int16_t, &memory_space::read<int16_t>>},
742 {"readhword", lua_read_memory<ss_uint24_t, &memory_space::read<ss_uint24_t>>},
743 {"readshword", lua_read_memory<ss_int24_t, &memory_space::read<ss_int24_t>>},
744 {"readdword", lua_read_memory<uint32_t, &memory_space::read<uint32_t>>},
745 {"readsdword", lua_read_memory<int32_t, &memory_space::read<int32_t>>},
746 {"readqword", lua_read_memory<uint64_t, &memory_space::read<uint64_t>>},
747 {"readsqword", lua_read_memory<int64_t, &memory_space::read<int64_t>>},
748 {"readfloat", lua_read_memory<float, &memory_space::read<float>>},
749 {"readdouble", lua_read_memory<double, &memory_space::read<double>>},
750 {"writebyte", lua_write_memory<uint8_t, &memory_space::write<uint8_t>>},
751 {"writeword", lua_write_memory<uint16_t, &memory_space::write<uint16_t>>},
752 {"writehword", lua_write_memory<ss_uint24_t, &memory_space::write<ss_uint24_t>>},
753 {"writedword", lua_write_memory<uint32_t, &memory_space::write<uint32_t>>},
754 {"writeqword", lua_write_memory<uint64_t, &memory_space::write<uint64_t>>},
755 {"writefloat", lua_write_memory<float, &memory_space::write<float>>},
756 {"writedouble", lua_write_memory<double, &memory_space::write<double>>},
757 {"mapbyte", lua_mmap_memory<uint8_t, &memory_space::read<uint8_t>, &memory_space::write<uint8_t>>},
758 {"mapsbyte", lua_mmap_memory<int8_t, &memory_space::read<int8_t>, &memory_space::write<int8_t>>},
759 {"mapword", lua_mmap_memory<uint16_t, &memory_space::read<uint16_t>, &memory_space::write<uint16_t>>},
760 {"mapsword", lua_mmap_memory<int16_t, &memory_space::read<int16_t>, &memory_space::write<int16_t>>},
761 {"maphword", lua_mmap_memory<ss_uint24_t, &memory_space::read<ss_uint24_t>,
762 &memory_space::write<ss_uint24_t>>},
763 {"mapshword", lua_mmap_memory<ss_int24_t, &memory_space::read<ss_int24_t>,
764 &memory_space::write<ss_int24_t>>},
765 {"mapdword", lua_mmap_memory<uint32_t, &memory_space::read<uint32_t>,
766 &memory_space::write<uint32_t>>},
767 {"mapsdword", lua_mmap_memory<int32_t, &memory_space::read<int32_t>, &memory_space::write<int32_t>>},
768 {"mapqword", lua_mmap_memory<uint64_t, &memory_space::read<uint64_t>,
769 &memory_space::write<uint64_t>>},
770 {"mapsqword", lua_mmap_memory<int64_t, &memory_space::read<int64_t>, &memory_space::write<int64_t>>},
771 {"mapfloat", lua_mmap_memory<float, &memory_space::read<float>, &memory_space::write<float>>},
772 {"mapdouble", lua_mmap_memory<double, &memory_space::read<double>, &memory_space::write<double>>},
773 {"registerread", lua_registerX<DEBUG_READ, true>},
774 {"unregisterread", lua_registerX<DEBUG_READ, false>},
775 {"registerwrite", lua_registerX<DEBUG_WRITE, true>},
776 {"unregisterwrite", lua_registerX<DEBUG_WRITE, false>},
777 {"registerexec", lua_registerX<DEBUG_EXEC, true>},
778 {"unregisterexec", lua_registerX<DEBUG_EXEC, false>},
779 {"registertrace", lua_registerX<DEBUG_TRACE, true>},
780 {"unregistertrace", lua_registerX<DEBUG_TRACE, false>},
783 lua::_class<lua_mmap_struct> class_mmap_struct(lua_class_memory, "MMAP_STRUCT", {
784 {"new", &lua_mmap_struct::create},
785 }, {
786 {"__index", &lua_mmap_struct::index},
787 {"__newindex", &lua_mmap_struct::newindex},
788 {"__call", &lua_mmap_struct::map},
789 }, &lua_mmap_struct::print);
792 int lua_mmap_struct::map(lua::state& L, lua::parameters& P)
794 std::string name, type;
795 uint64_t addr;
797 P(P.skipped(), name);
798 addr = lua_get_read_address(P);
799 P(type);
801 if(type == "byte")
802 mappings[name] = mapping(addr, do_rw<uint8_t, &memory_space::read<uint8_t>,
803 &memory_space::write<uint8_t>>);
804 else if(type == "sbyte")
805 mappings[name] = mapping(addr, do_rw<int8_t, &memory_space::read<int8_t>,
806 &memory_space::write<int8_t>>);
807 else if(type == "word")
808 mappings[name] = mapping(addr, do_rw<uint16_t, &memory_space::read<uint16_t>,
809 &memory_space::write<uint16_t>>);
810 else if(type == "sword")
811 mappings[name] = mapping(addr, do_rw<int16_t, &memory_space::read<int16_t>,
812 &memory_space::write<int16_t>>);
813 else if(type == "hword")
814 mappings[name] = mapping(addr, do_rw<ss_uint24_t, &memory_space::read<ss_uint24_t>,
815 &memory_space::write<ss_uint24_t>>);
816 else if(type == "shword")
817 mappings[name] = mapping(addr, do_rw<ss_int24_t, &memory_space::read<ss_int24_t>,
818 &memory_space::write<ss_int24_t>>);
819 else if(type == "dword")
820 mappings[name] = mapping(addr, do_rw<uint32_t, &memory_space::read<uint32_t>,
821 &memory_space::write<uint32_t>>);
822 else if(type == "sdword")
823 mappings[name] = mapping(addr, do_rw<int32_t, &memory_space::read<int32_t>,
824 &memory_space::write<int32_t>>);
825 else if(type == "qword")
826 mappings[name] = mapping(addr, do_rw<uint64_t, &memory_space::read<uint64_t>,
827 &memory_space::write<uint64_t>>);
828 else if(type == "sqword")
829 mappings[name] = mapping(addr, do_rw<int64_t, &memory_space::read<int64_t>,
830 &memory_space::write<int64_t>>);
831 else if(type == "float")
832 mappings[name] = mapping(addr, do_rw<float, &memory_space::read<float>,
833 &memory_space::write<float>>);
834 else if(type == "double")
835 mappings[name] = mapping(addr, do_rw<double, &memory_space::read<double>,
836 &memory_space::write<double>>);
837 else
838 (stringfmt() << P.get_fname() << ": Bad type").throwex();
839 return 0;
842 lua_mmap_struct::lua_mmap_struct(lua::state& L)