Get rid of DECLARE_LUACLASS
[lsnes.git] / src / lua / memory.cpp
blobeba33583bbf26152aa11dac0d5a3f4d3ef4bb900
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/minmax.hpp"
12 #include "library/int24.hpp"
14 namespace
16 uint64_t get_vmabase(lua_state& L, 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 get_read_address(lua_state& L, int& base, const char* fn)
26 uint64_t vmabase = 0;
27 if(L.type(base) == LUA_TSTRING) {
28 vmabase = get_vmabase(L, L.get_string(base, fn));
29 base++;
31 uint64_t addr = L.get_numeric_argument<uint64_t>(base++, fn) + vmabase;
32 return addr;
35 template<typename T, T (memory_space::*rfun)(uint64_t addr)>
36 class lua_read_memory : public lua_function
38 public:
39 lua_read_memory(const std::string& name) : lua_function(lua_func_misc, name) {}
40 int invoke(lua_state& L)
42 int base = 1;
43 uint64_t addr = get_read_address(L, base, "lua_read_memory");
44 L.pushnumber(static_cast<T>((lsnes_memory.*rfun)(addr)));
45 return 1;
49 template<typename T, bool (memory_space::*wfun)(uint64_t addr, T value)>
50 class lua_write_memory : public lua_function
52 public:
53 lua_write_memory(const std::string& name) : lua_function(lua_func_misc, name) {}
54 int invoke(lua_state& L)
56 int base = 1;
57 uint64_t addr = get_read_address(L, base, "lua_write_memory");
58 T value = L.get_numeric_argument<T>(base + 2, fname.c_str());
59 (lsnes_memory.*wfun)(addr, value);
60 return 0;
64 class mmap_base
66 public:
67 ~mmap_base() {}
68 virtual void read(lua_state& L, uint64_t addr) = 0;
69 virtual void write(lua_state& L, uint64_t addr) = 0;
73 template<typename T, T (memory_space::*rfun)(uint64_t addr), bool (memory_space::*wfun)(uint64_t addr,
74 T value)>
75 class lua_mmap_memory_helper : public mmap_base
77 public:
78 ~lua_mmap_memory_helper() {}
79 void read(lua_state& L, uint64_t addr)
81 L.pushnumber(static_cast<T>((lsnes_memory.*rfun)(addr)));
84 void write(lua_state& L, uint64_t addr)
86 T value = L.get_numeric_argument<T>(3, "aperture(write)");
87 (lsnes_memory.*wfun)(addr, value);
92 class lua_mmap_struct
94 public:
95 lua_mmap_struct(lua_state& L);
97 ~lua_mmap_struct()
101 int index(lua_state& L, const std::string& fname)
103 const char* c = L.tostring(2);
104 if(!c) {
105 L.pushnil();
106 return 1;
108 std::string c2(c);
109 if(!mappings.count(c2)) {
110 L.pushnil();
111 return 1;
113 auto& x = mappings[c2];
114 x.first->read(L, x.second);
115 return 1;
117 int newindex(lua_state& L, const std::string& fname)
119 const char* c = L.tostring(2);
120 if(!c)
121 return 0;
122 std::string c2(c);
123 if(!mappings.count(c2))
124 return 0;
125 auto& x = mappings[c2];
126 x.first->write(L, x.second);
127 return 0;
129 int map(lua_state& L, const std::string& fname);
130 std::string print()
132 size_t s = mappings.size();
133 return (stringfmt() << s << " " << ((s != 1) ? "mappings" : "mapping")).str();
135 private:
136 std::map<std::string, std::pair<mmap_base*, uint64_t>> mappings;
139 namespace
141 int aperture_read_fun(lua_State* _L)
143 lua_state& L = *reinterpret_cast<lua_state*>(lua_touserdata(_L, lua_upvalueindex(4)));
144 uint64_t base = L.tonumber(lua_upvalueindex(1));
145 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
146 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
147 size = L.tonumber(lua_upvalueindex(2));
148 mmap_base* fn = reinterpret_cast<mmap_base*>(L.touserdata(lua_upvalueindex(3)));
149 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(read)");
150 if(addr > size || addr + base < addr) {
151 L.pushnumber(0);
152 return 1;
154 addr += base;
155 fn->read(L, addr);
156 return 1;
159 int aperture_write_fun(lua_State* _L)
161 lua_state& L = *reinterpret_cast<lua_state*>(lua_touserdata(_L, lua_upvalueindex(4)));
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 mmap_base* fn = reinterpret_cast<mmap_base*>(L.touserdata(lua_upvalueindex(3)));
167 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(write)");
168 if(addr > size || addr + base < addr)
169 return 0;
170 addr += base;
171 fn->write(L, addr);
172 return 0;
175 void aperture_make_fun(lua_state& L, uint64_t base, uint64_t size, mmap_base& type)
177 L.newtable();
178 L.newtable();
179 L.pushstring( "__index");
180 L.pushnumber(base);
181 if(!(size + 1))
182 L.pushnil();
183 else
184 L.pushnumber(size);
185 L.pushlightuserdata(&type);
186 L.pushlightuserdata(&L);
187 L.pushcclosure(aperture_read_fun, 4);
188 L.settable(-3);
189 L.pushstring("__newindex");
190 L.pushnumber(base);
191 if(!(size + 1))
192 L.pushnil();
193 else
194 L.pushnumber(size);
195 L.pushlightuserdata(&type);
196 L.pushlightuserdata(&L);
197 L.pushcclosure(aperture_write_fun, 4);
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;
256 template<debug_type type, bool reg> class lua_registerX : public lua_function
258 public:
259 lua_registerX(const std::string& name) : lua_function(lua_func_misc, name) {}
260 int invoke(lua_state& L)
262 uint64_t addr;
263 int base = 1;
264 if(L.type(1) == LUA_TNIL && type != DEBUG_TRACE) {
265 addr = 0xFFFFFFFFFFFFFFFFULL;
266 base = 2;
267 } else if(type != DEBUG_TRACE)
268 addr = get_read_address(L, base, fname.c_str());
269 else
270 addr = L.get_numeric_argument<uint64_t>(base++, fname.c_str());
271 if(L.type(base) != LUA_TFUNCTION)
272 throw std::runtime_error("Expected last argument to " + fname + " to be function");
273 if(reg) {
274 handle_registerX(L, addr, base);
275 L.pushvalue(base);
276 return 1;
277 } else {
278 handle_unregisterX(L, addr, base);
279 return 0;
282 void handle_registerX(lua_state& L, uint64_t addr, int lfn)
284 auto& cbl = cbs[addr];
286 //Put the context in userdata so it can be gc'd when Lua context is terminated.
287 lua_debug_callback* D = (lua_debug_callback*)L.newuserdata(sizeof(lua_debug_callback));
288 L.newtable();
289 L.pushstring("__gc");
290 L.pushcclosure(&lua_debug_callback::dtor, 0);
291 L.rawset(-3);
292 L.setmetatable(-2);
293 L.pushlightuserdata(&D->addr);
294 L.pushvalue(-2);
295 L.rawset(LUA_REGISTRYINDEX);
296 L.pop(1); //Pop the copy of object.
298 cbl.push_back(D);
300 D->dead = false;
301 D->addr = addr;
302 D->type = type;
303 D->lua_fn = L.topointer(lfn);
304 lua_state* LL = &L.get_master();
305 void* D2 = &D->type;
306 if(type != DEBUG_TRACE)
307 D->h = debug_add_callback(addr, type, [LL, D2](uint64_t addr, uint64_t value) {
308 LL->pushlightuserdata(D2);
309 LL->rawget(LUA_REGISTRYINDEX);
310 LL->pushnumber(addr);
311 LL->pushnumber(value);
312 do_lua_error(*LL, LL->pcall(2, 0, 0));
313 }, [LL, D]() {
314 LL->pushlightuserdata(&D->addr);
315 LL->pushnil();
316 LL->rawset(LUA_REGISTRYINDEX);
317 D->_dtor(LL->handle());
319 else
320 D->h = debug_add_trace_callback(addr, [LL, D2](uint64_t proc, const char* str) {
321 LL->pushlightuserdata(D2);
322 LL->rawget(LUA_REGISTRYINDEX);
323 LL->pushnumber(proc);
324 LL->pushstring(str);
325 do_lua_error(*LL, LL->pcall(2, 0, 0));
326 }, [LL, D]() {
327 LL->pushlightuserdata(&D->addr);
328 LL->pushnil();
329 LL->rawset(LUA_REGISTRYINDEX);
330 D->_dtor(LL->handle());
332 L.pushlightuserdata(D2);
333 L.pushvalue(lfn);
334 L.rawset(LUA_REGISTRYINDEX);
336 void handle_unregisterX(lua_state& L, uint64_t addr, int lfn)
338 if(!cbs.count(addr))
339 return;
340 auto& cbl = cbs[addr];
341 for(auto i = cbl.begin(); i != cbl.end(); i++) {
342 if((*i)->type != type) continue;
343 if(L.topointer(lfn) != (*i)->lua_fn) continue;
344 L.pushlightuserdata(&(*i)->type);
345 L.pushnil();
346 L.rawset(LUA_REGISTRYINDEX);
347 (*i)->_dtor(L.handle());
348 //Lua will GC the object.
349 break;
354 command::fnptr<> callbacks_show_lua(lsnes_cmd, "show-lua-callbacks", "", "",
355 []() throw(std::bad_alloc, std::runtime_error) {
356 for(auto& i : cbs)
357 for(auto& j : i.second)
358 messages << "addr=" << j->addr << " type=" << j->type << " handle="
359 << j->h.handle << " dead=" << j->dead << " lua_fn="
360 << j->lua_fn << std::endl;
363 class lua_mmap_memory : public lua_function
365 public:
366 lua_mmap_memory(const std::string& name, mmap_base& _h) : lua_function(lua_func_misc, name), h(_h) {}
367 int invoke(lua_state& L)
369 if(L.isnoneornil(1)) {
370 aperture_make_fun(L, 0, 0xFFFFFFFFFFFFFFFFULL, h);
371 return 1;
373 int base = 1;
374 uint64_t addr = get_read_address(L, base, "lua_mmap_memory");
375 uint64_t size = L.get_numeric_argument<uint64_t>(base, fname.c_str());
376 if(!size)
377 throw std::runtime_error("Aperture with zero size is not valid");
378 aperture_make_fun(L, addr, size - 1, h);
379 return 1;
381 mmap_base& h;
384 function_ptr_luafun vmacount(lua_func_misc, "memory.vma_count", [](lua_state& L, const std::string& fname)
385 -> int {
386 L.pushnumber(lsnes_memory.get_regions().size());
387 return 1;
390 function_ptr_luafun cheat(lua_func_misc, "memory.cheat", [](lua_state& L, const std::string& fname)
391 -> int {
392 int base = 1;
393 uint64_t addr = get_read_address(L, base, fname.c_str());
394 if(L.type(base) == LUA_TNIL || L.type(base) == LUA_TNONE) {
395 debug_clear_cheat(addr);
396 } else {
397 uint64_t value = L.get_numeric_argument<uint64_t>(base, fname.c_str());
398 debug_set_cheat(addr, value);
400 return 0;
403 function_ptr_luafun xmask(lua_func_misc, "memory.setxmask", [](lua_state& L, const std::string& fname)
404 -> int {
405 uint64_t value = L.get_numeric_argument<uint64_t>(1, fname.c_str());
406 debug_setxmask(value);
407 return 0;
410 int handle_push_vma(lua_state& L, memory_region& r)
412 L.newtable();
413 L.pushstring("region_name");
414 L.pushlstring(r.name.c_str(), r.name.size());
415 L.settable(-3);
416 L.pushstring("baseaddr");
417 L.pushnumber(r.base);
418 L.settable(-3);
419 L.pushstring("size");
420 L.pushnumber(r.size);
421 L.settable(-3);
422 L.pushstring("lastaddr");
423 L.pushnumber(r.last_address());
424 L.settable(-3);
425 L.pushstring("readonly");
426 L.pushboolean(r.readonly);
427 L.settable(-3);
428 L.pushstring("iospace");
429 L.pushboolean(r.special);
430 L.settable(-3);
431 L.pushstring("native_endian");
432 L.pushboolean(r.endian == 0);
433 L.settable(-3);
434 L.pushstring("endian");
435 L.pushnumber(r.endian);
436 L.settable(-3);
437 return 1;
440 function_ptr_luafun readvma(lua_func_misc, "memory.read_vma", [](lua_state& L, const std::string& fname)
441 -> int {
442 std::list<memory_region*> regions = lsnes_memory.get_regions();
443 uint32_t num = L.get_numeric_argument<uint32_t>(1, fname.c_str());
444 uint32_t j = 0;
445 for(auto i = regions.begin(); i != regions.end(); i++, j++)
446 if(j == num)
447 return handle_push_vma(L, **i);
448 L.pushnil();
449 return 1;
452 function_ptr_luafun findvma(lua_func_misc, "memory.find_vma", [](lua_state& L, const std::string& fname)
453 -> int {
454 uint64_t addr = L.get_numeric_argument<uint64_t>(1, fname.c_str());
455 auto r = lsnes_memory.lookup(addr);
456 if(r.first)
457 return handle_push_vma(L, *r.first);
458 L.pushnil();
459 return 1;
462 const char* hexes = "0123456789ABCDEF";
464 function_ptr_luafun hashstate(lua_func_misc, "memory.hash_state", [](lua_state& L, const std::string& fname)
465 -> int {
466 char hash[64];
467 auto x = our_rom.save_core_state();
468 size_t offset = x.size() - 32;
469 for(unsigned i = 0; i < 32; i++) {
470 hash[2 * i + 0] = hexes[static_cast<unsigned char>(x[offset + i]) >> 4];
471 hash[2 * i + 1] = hexes[static_cast<unsigned char>(x[offset + i]) & 0xF];
473 L.pushlstring(hash, 64);
474 return 1;
477 #define BLOCKSIZE 256
479 function_ptr_luafun hashmemory(lua_func_misc, "memory.hash_region", [](lua_state& L, const std::string& fname)
480 -> int {
481 std::string hash;
482 int base = 1;
483 uint64_t addr = get_read_address(L, base, fname.c_str());
484 uint64_t size = L.get_numeric_argument<uint64_t>(base, fname.c_str());
485 char buffer[BLOCKSIZE];
486 sha256 h;
487 while(size > BLOCKSIZE) {
488 for(size_t i = 0; i < BLOCKSIZE; i++)
489 buffer[i] = lsnes_memory.read<uint8_t>(addr + i);
490 h.write(buffer, BLOCKSIZE);
491 addr += BLOCKSIZE;
492 size -= BLOCKSIZE;
494 for(size_t i = 0; i < size; i++)
495 buffer[i] = lsnes_memory.read<uint8_t>(addr + i);
496 h.write(buffer, size);
497 hash = h.read();
498 L.pushlstring(hash.c_str(), 64);
499 return 1;
502 function_ptr_luafun readmemoryr(lua_func_misc, "memory.readregion", [](lua_state& L, const std::string& fname)
503 -> int {
504 std::string hash;
505 int base = 1;
506 uint64_t addr = get_read_address(L, base, fname.c_str());
507 uint64_t size = L.get_numeric_argument<uint64_t>(base, fname.c_str());
508 L.newtable();
509 char buffer[BLOCKSIZE];
510 uint64_t ctr = 0;
511 while(size > 0) {
512 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
513 lsnes_memory.read_range(addr, buffer, rsize);
514 for(size_t i = 0; i < rsize; i++) {
515 L.pushnumber(ctr++);
516 L.pushnumber(static_cast<unsigned char>(buffer[i]));
517 L.settable(-3);
519 addr += rsize;
520 size -= rsize;
522 return 1;
525 function_ptr_luafun writememoryr(lua_func_misc, "memory.writeregion", [](lua_state& L,
526 const std::string& fname) -> int {
527 std::string hash;
528 int base = 1;
529 uint64_t addr = get_read_address(L, base, fname.c_str());
530 uint64_t size = L.get_numeric_argument<uint64_t>(base, fname.c_str());
531 char buffer[BLOCKSIZE];
532 uint64_t ctr = 0;
533 while(size > 0) {
534 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
535 for(size_t i = 0; i < rsize; i++) {
536 L.pushnumber(ctr++);
537 L.gettable(3);
538 buffer[i] = L.tointeger(-1);
539 L.pop(1);
541 lsnes_memory.write_range(addr, buffer, rsize);
542 addr += rsize;
543 size -= rsize;
545 return 1;
548 function_ptr_luafun gui_cbitmap(lua_func_misc, "memory.map_structure", [](lua_state& L,
549 const std::string& fname) -> int {
550 lua_class<lua_mmap_struct>::create(L);
551 return 1;
554 function_ptr_luafun memory_watchexpr(lua_func_misc, "memory.read_expr", [](lua_state& L,
555 const std::string& fname) -> int {
556 std::string val = evaluate_watch(L.get_string(1, fname.c_str()));
557 L.pushstring(val.c_str());
558 return 1;
561 template<bool write, bool sign> int memory_scattergather(lua_state& L, const std::string& fname)
563 uint64_t val = 0;
564 int ptr = 1;
565 unsigned shift = 0;
566 uint64_t addr = 0;
567 uint64_t vmabase = 0;
568 if(write)
569 val = L.get_numeric_argument<uint64_t>(ptr++, fname.c_str());
570 while(L.type(ptr) != LUA_TNIL && L.type(ptr) != LUA_TNONE) {
571 if(L.type(ptr) == LUA_TBOOLEAN) {
572 if(L.toboolean(ptr++))
573 addr++;
574 else
575 addr--;
576 } else if(L.type(ptr) == LUA_TSTRING) {
577 vmabase = get_vmabase(L, L.get_string(ptr++, fname.c_str()));
578 continue;
579 } else
580 addr = L.get_numeric_argument<uint64_t>(ptr++, fname.c_str());
581 if(write)
582 lsnes_memory.write<uint8_t>(addr + vmabase, val >> shift);
583 else
584 val = val + ((uint64_t)lsnes_memory.read<uint8_t>(addr + vmabase) << shift);
585 shift += 8;
587 if(!write) {
588 int64_t sval = val;
589 if(val >= (1ULL << (shift - 1))) sval -= (1ULL << shift);
590 if(sign) L.pushnumber(sval); else L.pushnumber(val);
592 return write ? 0 : 1;
595 function_ptr_luafun scattergather1(lua_func_misc, "memory.read_sg", [](lua_state& L, const std::string& fname)
596 -> int {
597 return memory_scattergather<false, false>(L, fname);
600 function_ptr_luafun scattergather2(lua_func_misc, "memory.sread_sg", [](lua_state& L,
601 const std::string& fname) -> int {
602 return memory_scattergather<false, true>(L, fname);
605 function_ptr_luafun scattergather3(lua_func_misc, "memory.write_sg", [](lua_state& L,
606 const std::string& fname) -> int {
607 return memory_scattergather<true, false>(L, fname);
610 lua_read_memory<uint8_t, &memory_space::read<uint8_t>> rub("memory.readbyte");
611 lua_read_memory<int8_t, &memory_space::read<int8_t>> rsb("memory.readsbyte");
612 lua_read_memory<uint16_t, &memory_space::read<uint16_t>> ruw("memory.readword");
613 lua_read_memory<int16_t, &memory_space::read<int16_t>> rsw("memory.readsword");
614 lua_read_memory<ss_uint24_t, &memory_space::read<ss_uint24_t>> ruh("memory.readhword");
615 lua_read_memory<ss_int24_t, &memory_space::read<ss_int24_t>> rsh("memory.readshword");
616 lua_read_memory<uint32_t, &memory_space::read<uint32_t>> rud("memory.readdword");
617 lua_read_memory<int32_t, &memory_space::read<int32_t>> rsd("memory.readsdword");
618 lua_read_memory<uint64_t, &memory_space::read<uint64_t>> ruq("memory.readqword");
619 lua_read_memory<int64_t, &memory_space::read<int64_t>> rsq("memory.readsqword");
620 lua_read_memory<float, &memory_space::read<float>> rf4("memory.readfloat");
621 lua_read_memory<double, &memory_space::read<double>> rf8("memory.readdouble");
622 lua_write_memory<uint8_t, &memory_space::write<uint8_t>> wb("memory.writebyte");
623 lua_write_memory<uint16_t, &memory_space::write<uint16_t>> ww("memory.writeword");
624 lua_write_memory<ss_uint24_t, &memory_space::write<ss_uint24_t>> wh("memory.writehword");
625 lua_write_memory<uint32_t, &memory_space::write<uint32_t>> wd("memory.writedword");
626 lua_write_memory<uint64_t, &memory_space::write<uint64_t>> wq("memory.writeqword");
627 lua_write_memory<float, &memory_space::write<float>> wf4("memory.writefloat");
628 lua_write_memory<double, &memory_space::write<double>> wf8("memory.writedouble");
629 lua_mmap_memory_helper<uint8_t, &memory_space::read<uint8_t>, &memory_space::write<uint8_t>> mhub;
630 lua_mmap_memory_helper<int8_t, &memory_space::read<int8_t>, &memory_space::write<int8_t>> mhsb;
631 lua_mmap_memory_helper<uint16_t, &memory_space::read<uint16_t>, &memory_space::write<uint16_t>> mhuw;
632 lua_mmap_memory_helper<int16_t, &memory_space::read<int16_t>, &memory_space::write<int16_t>> mhsw;
633 lua_mmap_memory_helper<ss_uint24_t, &memory_space::read<ss_uint24_t>, &memory_space::write<ss_uint24_t>> mhuh;
634 lua_mmap_memory_helper<ss_int24_t, &memory_space::read<ss_int24_t>, &memory_space::write<ss_int24_t>> mhsh;
635 lua_mmap_memory_helper<uint32_t, &memory_space::read<uint32_t>, &memory_space::write<uint32_t>> mhud;
636 lua_mmap_memory_helper<int32_t, &memory_space::read<int32_t>, &memory_space::write<int32_t>> mhsd;
637 lua_mmap_memory_helper<uint64_t, &memory_space::read<uint64_t>, &memory_space::write<uint64_t>> mhuq;
638 lua_mmap_memory_helper<int64_t, &memory_space::read<int64_t>, &memory_space::write<int64_t>> mhsq;
639 lua_mmap_memory_helper<float, &memory_space::read<float>, &memory_space::write<float>> mhf4;
640 lua_mmap_memory_helper<double, &memory_space::read<double>, &memory_space::write<double>> mhf8;
641 lua_mmap_memory mub("memory.mapbyte", mhub);
642 lua_mmap_memory msb("memory.mapsbyte", mhsb);
643 lua_mmap_memory muw("memory.mapword", mhuw);
644 lua_mmap_memory msw("memory.mapsword", mhsw);
645 lua_mmap_memory muh("memory.maphword", mhuh);
646 lua_mmap_memory msh("memory.mapshword", mhsh);
647 lua_mmap_memory mud("memory.mapdword", mhud);
648 lua_mmap_memory msd("memory.mapsdword", mhsd);
649 lua_mmap_memory muq("memory.mapqword", mhuq);
650 lua_mmap_memory msq("memory.mapsqword", mhsq);
651 lua_mmap_memory mf4("memory.mapfloat", mhf4);
652 lua_mmap_memory mf8("memory.mapdouble", mhf8);
653 lua_registerX<DEBUG_READ, true> mrr("memory.registerread");
654 lua_registerX<DEBUG_READ, false> murr("memory.unregisterread");
655 lua_registerX<DEBUG_WRITE, true> mrw("memory.registerwrite");
656 lua_registerX<DEBUG_WRITE, false> murw("memory.unregisterwrite");
657 lua_registerX<DEBUG_EXEC, true> mrx("memory.registerexec");
658 lua_registerX<DEBUG_EXEC, false> murx("memory.unregisterexec");
659 lua_registerX<DEBUG_TRACE, true> mrt("memory.registertrace");
660 lua_registerX<DEBUG_TRACE, false> murt("memory.unregistertrace");
662 lua_class<lua_mmap_struct> class_mmap_struct("MMAP_STRUCT");
665 int lua_mmap_struct::map(lua_state& L, const std::string& fname)
667 const char* name = L.tostring(2);
668 int base = 0;
669 uint64_t vmabase = 0;
670 if(L.type(3) == LUA_TSTRING) {
671 vmabase = get_vmabase(L, L.get_string(3, fname.c_str()));
672 base = 1;
674 uint64_t addr = L.get_numeric_argument<uint64_t>(base + 3, fname.c_str());
675 const char* type = L.tostring(base + 4);
676 if(!name)
677 (stringfmt() << fname << ": Bad name").throwex();
678 if(!type)
679 (stringfmt() << fname << ": Bad type").throwex();
680 std::string name2(name);
681 std::string type2(type);
682 if(type2 == "byte")
683 mappings[name2] = std::make_pair(&mhub, addr);
684 else if(type2 == "sbyte")
685 mappings[name2] = std::make_pair(&mhsb, addr);
686 else if(type2 == "word")
687 mappings[name2] = std::make_pair(&mhuw, addr);
688 else if(type2 == "sword")
689 mappings[name2] = std::make_pair(&mhsw, addr);
690 else if(type2 == "hword")
691 mappings[name2] = std::make_pair(&mhuh, addr);
692 else if(type2 == "shword")
693 mappings[name2] = std::make_pair(&mhsh, addr);
694 else if(type2 == "dword")
695 mappings[name2] = std::make_pair(&mhud, addr);
696 else if(type2 == "sdword")
697 mappings[name2] = std::make_pair(&mhsd, addr);
698 else if(type2 == "qword")
699 mappings[name2] = std::make_pair(&mhuq, addr);
700 else if(type2 == "sqword")
701 mappings[name2] = std::make_pair(&mhsq, addr);
702 else if(type2 == "float")
703 mappings[name2] = std::make_pair(&mhf4, addr);
704 else if(type2 == "double")
705 mappings[name2] = std::make_pair(&mhf8, addr);
706 else
707 (stringfmt() << fname << ": Bad type").throwex();
708 return 0;
711 lua_mmap_struct::lua_mmap_struct(lua_state& L)
713 objclass<lua_mmap_struct>().bind_multi(L, {
714 {"__index", &lua_mmap_struct::index},
715 {"__newindex", &lua_mmap_struct::newindex},
716 {"__call", &lua_mmap_struct::map},