Refactor dynamic state to its own subobject
[lsnes.git] / src / lua / memory.cpp
blobf79d839b171ef20a89e452216fd6b739359f8e7e
1 #include "cmdhelp/lua.hpp"
2 #include "core/command.hpp"
3 #include "core/debug.hpp"
4 #include "core/instance.hpp"
5 #include "core/memorymanip.hpp"
6 #include "core/memorywatch.hpp"
7 #include "core/messages.hpp"
8 #include "core/moviedata.hpp"
9 #include "core/moviefile.hpp"
10 #include "core/rom.hpp"
11 #include "lua/address.hpp"
12 #include "lua/internal.hpp"
13 #include "library/sha256.hpp"
14 #include "library/string.hpp"
15 #include "library/skein.hpp"
16 #include "library/memoryspace.hpp"
17 #include "library/minmax.hpp"
18 #include "library/hex.hpp"
19 #include "library/int24.hpp"
21 namespace
23 template<typename T, T (memory_space::*rfun)(uint64_t addr),
24 bool (memory_space::*wfun)(uint64_t addr, T value)>
25 void do_rw(lua::state& L, uint64_t addr, bool wrflag)
27 auto& core = CORE();
28 if(wrflag) {
29 T value = L.get_numeric_argument<T>(3, "aperture(write)");
30 (core.memory->*wfun)(addr, value);
31 } else
32 L.pushnumber(static_cast<T>((core.memory->*rfun)(addr)));
35 template<typename T, T (memory_space::*rfun)(uint64_t addr)>
36 int lua_read_memory(lua::state& L, lua::parameters& P)
38 auto addr = lua_get_read_address(P);
39 L.pushnumber(static_cast<T>((CORE().memory->*rfun)(addr)));
40 return 1;
43 template<typename T, bool (memory_space::*wfun)(uint64_t addr, T value)>
44 int lua_write_memory(lua::state& L, lua::parameters& P)
46 auto addr = lua_get_read_address(P);
47 T value = P.arg<T>();
48 (CORE().memory->*wfun)(addr, value);
49 return 0;
53 class lua_mmap_struct
55 public:
56 lua_mmap_struct(lua::state& L);
57 static size_t overcommit() { return 0; }
59 ~lua_mmap_struct()
63 int index(lua::state& L, lua::parameters& P)
65 const char* c = L.tostring(2);
66 if(!c) {
67 L.pushnil();
68 return 1;
70 std::string c2(c);
71 if(!mappings.count(c2)) {
72 L.pushnil();
73 return 1;
75 auto& x = mappings[c2];
76 x.rw(L, x.addr, false);
77 return 1;
79 int newindex(lua::state& L, lua::parameters& P)
81 const char* c = L.tostring(2);
82 if(!c)
83 return 0;
84 std::string c2(c);
85 if(!mappings.count(c2))
86 return 0;
87 auto& x = mappings[c2];
88 x.rw(L, x.addr, true);
89 return 0;
91 static int create(lua::state& L, lua::parameters& P)
93 lua::_class<lua_mmap_struct>::create(L);
94 return 1;
96 int map(lua::state& L, lua::parameters& P);
97 std::string print()
99 size_t s = mappings.size();
100 return (stringfmt() << s << " " << ((s != 1) ? "mappings" : "mapping")).str();
102 private:
103 struct mapping
105 mapping() {}
106 mapping(uint64_t _addr, void (*_rw)(lua::state& L, uint64_t addr, bool wrflag))
107 : addr(_addr), rw(_rw)
110 uint64_t addr;
111 void (*rw)(lua::state& L, uint64_t addr, bool wrflag);
113 std::map<std::string, mapping> mappings;
116 namespace
118 template<typename T, T (memory_space::*rfun)(uint64_t addr)>
119 int aperture_read_fun(lua_State* _L)
121 lua::state& mL = *reinterpret_cast<lua::state*>(lua_touserdata(_L, lua_upvalueindex(3)));
122 lua::state L(mL, _L);
124 uint64_t base = L.tointeger(lua_upvalueindex(1));
125 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
126 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
127 size = L.tointeger(lua_upvalueindex(2));
128 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(read)");
129 if(addr > size || addr + base < addr) {
130 L.pushnumber(0);
131 return 1;
133 addr += base;
134 L.pushnumber(static_cast<T>((CORE().memory->*rfun)(addr)));
135 return 1;
138 template<typename T, bool (memory_space::*wfun)(uint64_t addr, T value)>
139 int aperture_write_fun(lua_State* _L)
141 lua::state& mL = *reinterpret_cast<lua::state*>(lua_touserdata(_L, lua_upvalueindex(3)));
142 lua::state L(mL, _L);
144 uint64_t base = L.tointeger(lua_upvalueindex(1));
145 uint64_t size = 0xFFFFFFFFFFFFFFFFULL;
146 if(L.type(lua_upvalueindex(2)) == LUA_TNUMBER)
147 size = L.tointeger(lua_upvalueindex(2));
148 uint64_t addr = L.get_numeric_argument<uint64_t>(2, "aperture(write)");
149 if(addr > size || addr + base < addr)
150 return 0;
151 addr += base;
152 T value = L.get_numeric_argument<T>(3, "aperture(write)");
153 (CORE().memory->*wfun)(addr, value);
154 return 0;
157 template<typename T, T (memory_space::*rfun)(uint64_t addr), bool (memory_space::*wfun)(uint64_t addr,
158 T value)>
159 void aperture_make_fun(lua::state& L, uint64_t base, uint64_t size)
161 L.newtable();
162 L.newtable();
163 L.pushstring( "__index");
164 L.pushnumber(base);
165 if(!(size + 1))
166 L.pushnil();
167 else
168 L.pushnumber(size);
169 L.pushlightuserdata(&L);
170 L.pushcclosure(aperture_read_fun<T, rfun>, 3);
171 L.settable(-3);
172 L.pushstring("__newindex");
173 L.pushnumber(base);
174 if(!(size + 1))
175 L.pushnil();
176 else
177 L.pushnumber(size);
178 L.pushlightuserdata(&L);
179 L.pushcclosure(aperture_write_fun<T, wfun>, 3);
180 L.settable(-3);
181 L.setmetatable(-2);
184 void do_lua_error(lua::state& L, int ret)
186 if(!ret) return;
187 switch(ret) {
188 case LUA_ERRRUN:
189 messages << "Error in Lua memory callback: " << L.get_string(-1, "errhnd") << std::endl;
190 L.pop(1);
191 return;
192 case LUA_ERRMEM:
193 messages << "Error in Lua memory callback (Out of memory)" << std::endl;
194 return;
195 case LUA_ERRERR:
196 messages << "Error in Lua memory callback (Double fault)" << std::endl;
197 return;
198 default:
199 messages << "Error in Lua memory callback (\?\?\?)" << std::endl;
200 return;
204 char CONST_lua_cb_list_key = 0;
206 struct lua_debug_callback2 : public debug_context::callback_base
208 lua::state* L;
209 uint64_t addr;
210 debug_context::etype type;
211 bool dead;
212 const void* lua_fn;
213 ~lua_debug_callback2();
214 void link_to_list();
215 void set_lua_fn(int slot);
216 void unregister();
217 void callback(const debug_context::params& p);
218 void killed(uint64_t addr, debug_context::etype type);
219 static int on_lua_gc(lua_State* L);
220 lua_debug_callback2* prev;
221 lua_debug_callback2* next;
224 struct lua_debug_callback_dict
226 ~lua_debug_callback_dict();
227 std::map<std::pair<debug_context::etype, uint64_t>, lua_debug_callback2*> cblist;
228 static int on_lua_gc(lua_State* L);
231 lua_debug_callback2::~lua_debug_callback2()
233 if(!prev) {
234 L->pushlightuserdata(&CONST_lua_cb_list_key);
235 L->rawget(LUA_REGISTRYINDEX);
236 if(!L->isnil(-1)) {
237 lua_debug_callback_dict* dc = (lua_debug_callback_dict*)L->touserdata(-1);
238 std::pair<debug_context::etype, uint64_t> key = std::make_pair(type, addr);
239 if(dc->cblist.count(key)) {
240 dc->cblist[key] = next;
241 if(!next)
242 dc->cblist.erase(key);
245 L->pop(1);
247 //Unlink from list.
248 if(prev) prev->next = next;
249 if(next) next->prev = prev;
250 prev = next = NULL;
253 void lua_debug_callback2::link_to_list()
255 prev = NULL;
256 L->pushlightuserdata(&CONST_lua_cb_list_key);
257 L->rawget(LUA_REGISTRYINDEX);
258 if(L->isnil(-1)) {
259 //No existing dict, create one.
260 L->pop(1);
261 L->pushlightuserdata(&CONST_lua_cb_list_key);
262 lua_debug_callback_dict* D = (lua_debug_callback_dict*)
263 L->newuserdata(sizeof(lua_debug_callback_dict));
264 new(D) lua_debug_callback_dict;
265 L->newtable();
266 L->pushstring("__gc");
267 L->pushcclosure(&lua_debug_callback_dict::on_lua_gc, 0);
268 L->rawset(-3);
269 L->setmetatable(-2);
270 L->rawset(LUA_REGISTRYINDEX);
272 L->pushlightuserdata(&CONST_lua_cb_list_key);
273 L->rawget(LUA_REGISTRYINDEX);
274 lua_debug_callback2* was = NULL;
275 lua_debug_callback_dict* dc = (lua_debug_callback_dict*)L->touserdata(-1);
276 std::pair<debug_context::etype, uint64_t> key = std::make_pair(type, addr);
277 if(dc->cblist.count(key))
278 was = dc->cblist[key];
279 dc->cblist[key] = this;
280 next = was;
281 L->pop(1);
285 void lua_debug_callback2::set_lua_fn(int slot)
287 //Convert to absolute slot.
288 if(slot < 0)
289 slot = L->gettop() + slot;
290 //Write the function.
291 L->pushlightuserdata((char*)this + 1);
292 L->pushvalue(slot);
293 L->rawset(LUA_REGISTRYINDEX);
294 lua_fn = L->topointer(slot);
297 void lua_debug_callback2::unregister()
299 //Unregister.
300 CORE().dbg->remove_callback(addr, type, *this);
301 dead = true;
302 //Delink from Lua, prompting Lua to GC this.
303 L->pushlightuserdata(this);
304 L->pushnil();
305 L->rawset(LUA_REGISTRYINDEX);
306 L->pushlightuserdata((char*)this + 1);
307 L->pushnil();
308 L->rawset(LUA_REGISTRYINDEX);
311 void lua_debug_callback2::callback(const debug_context::params& p)
313 L->pushlightuserdata((char*)this + 1);
314 L->rawget(LUA_REGISTRYINDEX);
315 switch(p.type) {
316 case debug_context::DEBUG_READ:
317 case debug_context::DEBUG_WRITE:
318 case debug_context::DEBUG_EXEC:
319 L->pushnumber(p.rwx.addr);
320 L->pushnumber(p.rwx.value);
321 do_lua_error(*L, L->pcall(2, 0, 0));
322 break;
323 case debug_context::DEBUG_TRACE:
324 L->pushnumber(p.trace.cpu);
325 L->pushstring(p.trace.decoded_insn);
326 L->pushboolean(p.trace.true_insn);
327 do_lua_error(*L, L->pcall(3, 0, 0));
328 break;
329 case debug_context::DEBUG_FRAME:
330 L->pushnumber(p.frame.frame);
331 L->pushboolean(p.frame.loadstated);
332 do_lua_error(*L, L->pcall(2, 0, 0));
333 break;
334 default:
335 //Remove the junk from stack.
336 L->pop(1);
337 break;
341 void lua_debug_callback2::killed(uint64_t addr, debug_context::etype type)
343 //Assume this has been unregistered.
344 dead = true;
345 //Delink from Lua, lua will GC this.
346 L->pushlightuserdata(this);
347 L->pushnil();
348 L->rawset(LUA_REGISTRYINDEX);
349 L->pushlightuserdata((char*)this + 1);
350 L->pushnil();
351 L->rawset(LUA_REGISTRYINDEX);
354 int lua_debug_callback2::on_lua_gc(lua_State* _L)
356 //We need to destroy the object.
357 lua_debug_callback2* D = (lua_debug_callback2*)lua_touserdata(_L, 1);
358 if(!D->dead) {
359 //Unregister this!
360 CORE().dbg->remove_callback(D->addr, D->type, *D);
361 D->dead = true;
363 D->~lua_debug_callback2();
364 return 0;
367 lua_debug_callback_dict::~lua_debug_callback_dict()
371 int lua_debug_callback_dict::on_lua_gc(lua_State* _L)
373 lua_pushlightuserdata(_L, &CONST_lua_cb_list_key);
374 lua_pushnil(_L);
375 lua_rawset(_L, LUA_REGISTRYINDEX);
376 lua_debug_callback_dict* D = (lua_debug_callback_dict*)lua_touserdata(_L, 1);
377 D->~lua_debug_callback_dict();
378 return 0;
382 template<debug_context::etype type>
383 void handle_registerX(lua::state& L, uint64_t addr, int lfn)
385 //Put the context in userdata so it can be gc'd when Lua context is terminated.
386 lua_debug_callback2* D = (lua_debug_callback2*)L.newuserdata(sizeof(lua_debug_callback2));
387 new(D) lua_debug_callback2;
388 L.newtable();
389 L.pushstring("__gc");
390 L.pushcclosure(&lua_debug_callback2::on_lua_gc, 0);
391 L.rawset(-3);
392 L.setmetatable(-2);
393 L.pushlightuserdata(D);
394 L.pushvalue(-2);
395 L.rawset(LUA_REGISTRYINDEX);
396 L.pop(1); //Pop the copy of object.
398 D->L = &L.get_master();
399 D->addr = addr;
400 D->type = type;
401 D->dead = false;
402 D->set_lua_fn(lfn);
403 D->link_to_list();
405 CORE().dbg->add_callback(addr, type, *D);
408 template<debug_context::etype type>
409 void handle_unregisterX(lua::state& L, uint64_t addr, int lfn)
411 lua_debug_callback_dict* Dx;
412 lua_debug_callback2* D = NULL;
413 L.pushlightuserdata(&CONST_lua_cb_list_key);
414 L.rawget(LUA_REGISTRYINDEX);
415 if(!L.isnil(-1)) {
416 Dx = (lua_debug_callback_dict*)L.touserdata(-1);
417 auto key = std::make_pair(type, addr);
418 if(Dx->cblist.count(key))
419 D = Dx->cblist[key];
420 L.pop(1);
421 while(D) {
422 if(D->dead || D->type != type || D->addr != addr || L.topointer(lfn) != D->lua_fn) {
423 D = D->next;
424 continue;
426 //Remove this.
427 auto Dold = D;
428 D = D->next;
429 Dold->unregister();
431 } else
432 L.pop(1);
435 typedef void(*dummy1_t)(lua::state& L, uint64_t addr, int lfn);
436 dummy1_t dummy_628963286932869328692386963[] = {
437 handle_registerX<debug_context::DEBUG_READ>,
438 handle_registerX<debug_context::DEBUG_WRITE>,
439 handle_registerX<debug_context::DEBUG_EXEC>,
440 handle_unregisterX<debug_context::DEBUG_READ>,
441 handle_unregisterX<debug_context::DEBUG_WRITE>,
442 handle_unregisterX<debug_context::DEBUG_EXEC>,
445 namespace
447 template<debug_context::etype type, bool reg>
448 int lua_registerX(lua::state& L, lua::parameters& P)
450 uint64_t addr;
451 int lfn;
452 if(P.is_nil() && type != debug_context::DEBUG_TRACE) {
453 addr = 0xFFFFFFFFFFFFFFFFULL;
454 P.skip();
455 } else if(type != debug_context::DEBUG_TRACE)
456 addr = lua_get_read_address(P);
457 else
458 P(addr);
459 P(P.function(lfn));
461 if(reg) {
462 handle_registerX<type>(L, addr, lfn);
463 L.pushvalue(lfn);
464 return 1;
465 } else {
466 handle_unregisterX<type>(L, addr, lfn);
467 return 0;
471 command::fnptr<> CMD_callbacks_show_lua(lsnes_cmds, CLUA::scb,
472 []() throw(std::bad_alloc, std::runtime_error) {
473 auto& core = CORE();
474 lua::state& L = *core.lua;
475 lua_debug_callback2* D;
476 lua_debug_callback_dict* Dx;
477 L.pushlightuserdata(&CONST_lua_cb_list_key);
478 L.rawget(LUA_REGISTRYINDEX);
479 if(!L.isnil(-1)) {
480 Dx = (lua_debug_callback_dict*)L.touserdata(-1);
481 for(auto Dy : Dx->cblist) {
482 D = Dy.second;
483 while(D) {
484 messages << "addr=" << core.memory->address_to_textual(D->addr)
485 << " type=" << D->type << " handle=" << D << " dead=" << D->dead
486 << " lua_fn=" << D->lua_fn << std::endl;
487 D = D->next;
491 L.pop(1);
494 template<typename T, T (memory_space::*rfun)(uint64_t addr), bool (memory_space::*wfun)(uint64_t addr,
495 T value)>
496 int lua_mmap_memory(lua::state& L, lua::parameters& P)
498 if(P.is_novalue()) {
499 static char deprecation;
500 if(L.do_once(&deprecation))
501 messages << P.get_fname() << ": Mapping entiere space is deprecated." << std::endl;
502 aperture_make_fun<T, rfun, wfun>(L.get_master(), 0, 0xFFFFFFFFFFFFFFFFULL);
503 return 1;
505 auto addr = lua_get_read_address(P);
506 auto size = P.arg<uint64_t>();
507 if(!size)
508 throw std::runtime_error("Aperture with zero size is not valid");
509 aperture_make_fun<T, rfun, wfun>(L.get_master(), addr, size - 1);
510 return 1;
513 int handle_push_vma(lua::state& L, memory_space::region& r)
515 L.newtable();
516 L.pushstring("region_name");
517 L.pushlstring(r.name.c_str(), r.name.size());
518 L.settable(-3);
519 L.pushstring("baseaddr");
520 L.pushnumber(r.base);
521 L.settable(-3);
522 L.pushstring("size");
523 L.pushnumber(r.size);
524 L.settable(-3);
525 L.pushstring("lastaddr");
526 L.pushnumber(r.last_address());
527 L.settable(-3);
528 L.pushstring("readonly");
529 L.pushboolean(r.readonly);
530 L.settable(-3);
531 L.pushstring("iospace");
532 L.pushboolean(r.special);
533 L.settable(-3);
534 L.pushstring("native_endian");
535 L.pushboolean(r.endian == 0);
536 L.settable(-3);
537 L.pushstring("endian");
538 L.pushnumber(r.endian);
539 L.settable(-3);
540 return 1;
543 template<bool write, bool sign> int memory_scattergather(lua::state& L, lua::parameters& P)
545 auto& core = CORE();
546 static char deprecation;
547 uint64_t val = 0;
548 unsigned shift = 0;
549 uint64_t addr = 0;
550 uint64_t vmabase = 0;
551 bool have_vmabase = false;
552 if(write)
553 val = P.arg<uint64_t>();
554 while(P.more()) {
555 if(P.is_boolean()) {
556 if(P.arg<bool>())
557 addr++;
558 else
559 addr--;
560 } else if(P.is<lua_address>()) {
561 auto laddr = P.arg<lua_address*>();
562 vmabase = lua_get_vmabase(laddr->get_vma());
563 have_vmabase = true;
564 addr = laddr->get_offset();
565 //No continue, fall through.
566 } else if(P.is_string()) {
567 vmabase = lua_get_vmabase(P.arg<std::string>());
568 have_vmabase = true;
569 continue;
570 } else
571 addr = P.arg<uint64_t>();
572 if(!have_vmabase && L.do_once(&deprecation))
573 messages << P.get_fname() << ": Global memory form is deprecated." << std::endl;
574 if(write)
575 core.memory->write<uint8_t>(addr + vmabase, val >> shift);
576 else
577 val = val + ((uint64_t)core.memory->read<uint8_t>(addr + vmabase) << shift);
578 shift += 8;
580 if(!write) {
581 int64_t sval = val;
582 if(val >= (1ULL << (shift - 1))) sval -= (1ULL << shift);
583 if(sign) L.pushnumber(sval); else L.pushnumber(val);
585 return write ? 0 : 1;
588 #define BLOCKSIZE 256
590 int vma_count(lua::state& L, lua::parameters& P)
592 L.pushnumber(CORE().memory->get_regions().size());
593 return 1;
596 int cheat(lua::state& L, lua::parameters& P)
598 auto& core = CORE();
599 uint64_t addr, value;
601 addr = lua_get_read_address(P);
603 if(P.is_novalue()) {
604 core.dbg->clear_cheat(addr);
605 } else {
606 P(value);
607 core.dbg->set_cheat(addr, value);
609 return 0;
612 int setxmask(lua::state& L, lua::parameters& P)
614 auto value = P.arg<uint64_t>();
615 CORE().dbg->setxmask(value);
616 return 0;
619 int read_vma(lua::state& L, lua::parameters& P)
621 uint32_t num;
623 P(num);
625 std::list<memory_space::region*> regions = CORE().memory->get_regions();
626 uint32_t j = 0;
627 for(auto i = regions.begin(); i != regions.end(); i++, j++)
628 if(j == num)
629 return handle_push_vma(L, **i);
630 L.pushnil();
631 return 1;
634 int find_vma(lua::state& L, lua::parameters& P)
636 uint64_t addr;
638 P(addr);
640 auto r = CORE().memory->lookup(addr);
641 if(r.first)
642 return handle_push_vma(L, *r.first);
643 L.pushnil();
644 return 1;
647 int hash_state(lua::state& L, lua::parameters& P)
649 auto& core = CORE();
650 auto x = core.rom->save_core_state();
651 size_t offset = x.size() - 32;
652 L.pushlstring(hex::b_to((uint8_t*)&x[offset], 32));
653 return 1;
656 template<typename H, void(*update)(H& state, const char* mem, size_t memsize),
657 std::string(*read)(H& state), bool extra>
658 int hash_core(H& state, lua::state& L, lua::parameters& P)
660 auto& core = CORE();
661 std::string hash;
662 uint64_t addr, size, low, high;
663 uint64_t stride = 0, rows = 1;
664 bool mappable = true;
665 char buffer[BLOCKSIZE];
667 addr = lua_get_read_address(P);
668 P(size);
669 if(extra) {
670 P(P.optional(rows, 1));
671 if(rows > 1)
672 P(stride);
675 rpair(low, high) = memoryspace_row_bounds(addr, size, rows, stride);
676 if(low > high || high - low + 1 == 0)
677 mappable = false;
679 char* pbuffer = mappable ? core.memory->get_physical_mapping(low, high - low + 1) : NULL;
680 if(low > high) {
681 } else if(pbuffer) {
682 uint64_t offset = addr - low;
683 for(uint64_t i = 0; i < rows; i++) {
684 update(state, pbuffer + offset, size);
685 offset += stride;
687 } else {
688 uint64_t offset = addr;
689 for(uint64_t i = 0; i < rows; i++) {
690 size_t sz = size;
691 while(sz > 0) {
692 size_t ssz = min(sz, static_cast<size_t>(BLOCKSIZE));
693 for(size_t i = 0; i < ssz; i++)
694 buffer[i] = core.memory->read<uint8_t>(offset + i);
695 offset += ssz;
696 sz -= ssz;
697 update(state, buffer, ssz);
699 offset += (stride - size);
702 hash = read(state);
703 L.pushlstring(hash);
704 return 1;
707 void lua_sha256_update(sha256& s, const char* ptr, size_t size)
709 s.write(ptr, size);
712 std::string lua_sha256_read(sha256& s)
714 return s.read();
717 void lua_skein_update(skein::hash& s, const char* ptr, size_t size)
719 s.write(reinterpret_cast<const uint8_t*>(ptr), size);
722 std::string lua_skein_read(skein::hash& s)
724 uint8_t buf[32];
725 s.read(buf);
726 return hex::b_to(buf, 32, false);
729 template<bool extended>
730 int hash_region(lua::state& L, lua::parameters& P)
732 sha256 h;
733 return hash_core<sha256, lua_sha256_update, lua_sha256_read, extended>(h, L, P);
736 int hash_region_skein(lua::state& L, lua::parameters& P)
738 skein::hash h(skein::hash::PIPE_512, 256);
739 return hash_core<skein::hash, lua_skein_update, lua_skein_read, true>(h, L, P);
742 template<bool cmp>
743 int copy_to_host(lua::state& L, lua::parameters& P)
745 auto& core = CORE();
746 uint64_t addr, daddr, size, low, high;
747 uint64_t stride = 0, rows = 1;
748 bool equals = true, mappable = true;
750 addr = lua_get_read_address(P);
751 P(daddr, size, P.optional(rows, 1));
752 if(rows > 1)
753 P(stride);
755 rpair(low, high) = memoryspace_row_bounds(addr, size, rows, stride);
756 if(low > high || high - low + 1 == 0)
757 mappable = false;
758 if(rows && (size_t)(size * rows) / rows != size)
759 throw std::runtime_error("Size to copy too large");
760 if((size_t)(daddr + rows * size) < daddr)
761 throw std::runtime_error("Size to copy too large");
763 auto& h = core.mlogic->get_mfile().dyn.host_memory;
764 if(daddr + rows * size > h.size()) {
765 equals = false;
766 h.resize(daddr + rows * size);
769 char* pbuffer = mappable ? core.memory->get_physical_mapping(low, high - low + 1) : NULL;
770 if(!size && !rows) {
771 } else if(pbuffer) {
772 //Mapable.
773 uint64_t offset = addr - low;
774 for(uint64_t i = 0; i < rows; i++) {
775 bool eq = (cmp && !memcmp(&h[daddr + i * size], pbuffer + offset, size));
776 if(!eq)
777 memcpy(&h[daddr + i * size], pbuffer + offset, size);
778 equals &= eq;
779 offset += stride;
781 } else {
782 //Not mapable.
783 for(uint64_t i = 0; i < rows; i++) {
784 uint64_t addr1 = addr + i * stride;
785 uint64_t addr2 = daddr + i * size;
786 for(uint64_t j = 0; j < size; j++) {
787 uint8_t byte = core.memory->read<uint8_t>(addr1 + j);
788 bool eq = (cmp && h[addr2 + j] == (char)byte);
789 if(!eq)
790 h[addr2 + j] = byte;
791 equals &= eq;
795 if(cmp)
796 L.pushboolean(equals);
797 return cmp ? 1 : 0;
800 int readregion(lua::state& L, lua::parameters& P)
802 auto& core = CORE();
803 uint64_t addr, size;
805 addr = lua_get_read_address(P);
806 P(size);
808 L.newtable();
809 char buffer[BLOCKSIZE];
810 uint64_t ctr = 0;
811 while(size > 0) {
812 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
813 core.memory->read_range(addr, buffer, rsize);
814 for(size_t i = 0; i < rsize; i++) {
815 L.pushnumber(ctr++);
816 L.pushnumber(static_cast<unsigned char>(buffer[i]));
817 L.settable(-3);
819 addr += rsize;
820 size -= rsize;
822 return 1;
825 int writeregion(lua::state& L, lua::parameters& P)
827 auto& core = CORE();
828 uint64_t addr, size;
829 int ltbl;
831 addr = lua_get_read_address(P);
832 P(size, P.table(ltbl));
834 char buffer[BLOCKSIZE];
835 uint64_t ctr = 0;
836 while(size > 0) {
837 size_t rsize = min(size, static_cast<uint64_t>(BLOCKSIZE));
838 for(size_t i = 0; i < rsize; i++) {
839 L.pushnumber(ctr++);
840 L.gettable(ltbl);
841 buffer[i] = L.tointeger(-1);
842 L.pop(1);
844 core.memory->write_range(addr, buffer, rsize);
845 addr += rsize;
846 size -= rsize;
848 return 1;
851 lua::functions LUA_memory_fns(lua_func_misc, "memory", {
852 {"vma_count", vma_count},
853 {"cheat", cheat},
854 {"setxmask", setxmask},
855 {"read_vma", read_vma},
856 {"find_vma", find_vma},
857 {"hash_state", hash_state},
858 {"hash_region", hash_region<false>},
859 {"hash_region2", hash_region<true>},
860 {"hash_region_skein", hash_region_skein},
861 {"store", copy_to_host<false>},
862 {"storecmp", copy_to_host<true>},
863 {"readregion", readregion},
864 {"writeregion", writeregion},
865 {"read_sg", memory_scattergather<false, false>},
866 {"sread_sg", memory_scattergather<false, true>},
867 {"write_sg", memory_scattergather<true, false>},
868 {"readbyte", lua_read_memory<uint8_t, &memory_space::read<uint8_t>>},
869 {"readsbyte", lua_read_memory<int8_t, &memory_space::read<int8_t>>},
870 {"readword", lua_read_memory<uint16_t, &memory_space::read<uint16_t>>},
871 {"readsword", lua_read_memory<int16_t, &memory_space::read<int16_t>>},
872 {"readhword", lua_read_memory<ss_uint24_t, &memory_space::read<ss_uint24_t>>},
873 {"readshword", lua_read_memory<ss_int24_t, &memory_space::read<ss_int24_t>>},
874 {"readdword", lua_read_memory<uint32_t, &memory_space::read<uint32_t>>},
875 {"readsdword", lua_read_memory<int32_t, &memory_space::read<int32_t>>},
876 {"readqword", lua_read_memory<uint64_t, &memory_space::read<uint64_t>>},
877 {"readsqword", lua_read_memory<int64_t, &memory_space::read<int64_t>>},
878 {"readfloat", lua_read_memory<float, &memory_space::read<float>>},
879 {"readdouble", lua_read_memory<double, &memory_space::read<double>>},
880 {"writebyte", lua_write_memory<uint8_t, &memory_space::write<uint8_t>>},
881 {"writeword", lua_write_memory<uint16_t, &memory_space::write<uint16_t>>},
882 {"writehword", lua_write_memory<ss_uint24_t, &memory_space::write<ss_uint24_t>>},
883 {"writedword", lua_write_memory<uint32_t, &memory_space::write<uint32_t>>},
884 {"writeqword", lua_write_memory<uint64_t, &memory_space::write<uint64_t>>},
885 {"writefloat", lua_write_memory<float, &memory_space::write<float>>},
886 {"writedouble", lua_write_memory<double, &memory_space::write<double>>},
887 {"mapbyte", lua_mmap_memory<uint8_t, &memory_space::read<uint8_t>, &memory_space::write<uint8_t>>},
888 {"mapsbyte", lua_mmap_memory<int8_t, &memory_space::read<int8_t>, &memory_space::write<int8_t>>},
889 {"mapword", lua_mmap_memory<uint16_t, &memory_space::read<uint16_t>, &memory_space::write<uint16_t>>},
890 {"mapsword", lua_mmap_memory<int16_t, &memory_space::read<int16_t>, &memory_space::write<int16_t>>},
891 {"maphword", lua_mmap_memory<ss_uint24_t, &memory_space::read<ss_uint24_t>,
892 &memory_space::write<ss_uint24_t>>},
893 {"mapshword", lua_mmap_memory<ss_int24_t, &memory_space::read<ss_int24_t>,
894 &memory_space::write<ss_int24_t>>},
895 {"mapdword", lua_mmap_memory<uint32_t, &memory_space::read<uint32_t>,
896 &memory_space::write<uint32_t>>},
897 {"mapsdword", lua_mmap_memory<int32_t, &memory_space::read<int32_t>, &memory_space::write<int32_t>>},
898 {"mapqword", lua_mmap_memory<uint64_t, &memory_space::read<uint64_t>,
899 &memory_space::write<uint64_t>>},
900 {"mapsqword", lua_mmap_memory<int64_t, &memory_space::read<int64_t>, &memory_space::write<int64_t>>},
901 {"mapfloat", lua_mmap_memory<float, &memory_space::read<float>, &memory_space::write<float>>},
902 {"mapdouble", lua_mmap_memory<double, &memory_space::read<double>, &memory_space::write<double>>},
903 {"registerread", lua_registerX<debug_context::DEBUG_READ, true>},
904 {"unregisterread", lua_registerX<debug_context::DEBUG_READ, false>},
905 {"registerwrite", lua_registerX<debug_context::DEBUG_WRITE, true>},
906 {"unregisterwrite", lua_registerX<debug_context::DEBUG_WRITE, false>},
907 {"registerexec", lua_registerX<debug_context::DEBUG_EXEC, true>},
908 {"unregisterexec", lua_registerX<debug_context::DEBUG_EXEC, false>},
909 {"registertrace", lua_registerX<debug_context::DEBUG_TRACE, true>},
910 {"unregistertrace", lua_registerX<debug_context::DEBUG_TRACE, false>},
913 lua::_class<lua_mmap_struct> LUA_class_mmap_struct(lua_class_memory, "MMAP_STRUCT", {
914 {"new", &lua_mmap_struct::create},
915 }, {
916 {"__index", &lua_mmap_struct::index},
917 {"__newindex", &lua_mmap_struct::newindex},
918 {"__call", &lua_mmap_struct::map},
919 }, &lua_mmap_struct::print);
922 int lua_mmap_struct::map(lua::state& L, lua::parameters& P)
924 std::string name, type;
925 uint64_t addr;
927 P(P.skipped(), name);
928 addr = lua_get_read_address(P);
929 P(type);
931 if(type == "byte")
932 mappings[name] = mapping(addr, do_rw<uint8_t, &memory_space::read<uint8_t>,
933 &memory_space::write<uint8_t>>);
934 else if(type == "sbyte")
935 mappings[name] = mapping(addr, do_rw<int8_t, &memory_space::read<int8_t>,
936 &memory_space::write<int8_t>>);
937 else if(type == "word")
938 mappings[name] = mapping(addr, do_rw<uint16_t, &memory_space::read<uint16_t>,
939 &memory_space::write<uint16_t>>);
940 else if(type == "sword")
941 mappings[name] = mapping(addr, do_rw<int16_t, &memory_space::read<int16_t>,
942 &memory_space::write<int16_t>>);
943 else if(type == "hword")
944 mappings[name] = mapping(addr, do_rw<ss_uint24_t, &memory_space::read<ss_uint24_t>,
945 &memory_space::write<ss_uint24_t>>);
946 else if(type == "shword")
947 mappings[name] = mapping(addr, do_rw<ss_int24_t, &memory_space::read<ss_int24_t>,
948 &memory_space::write<ss_int24_t>>);
949 else if(type == "dword")
950 mappings[name] = mapping(addr, do_rw<uint32_t, &memory_space::read<uint32_t>,
951 &memory_space::write<uint32_t>>);
952 else if(type == "sdword")
953 mappings[name] = mapping(addr, do_rw<int32_t, &memory_space::read<int32_t>,
954 &memory_space::write<int32_t>>);
955 else if(type == "qword")
956 mappings[name] = mapping(addr, do_rw<uint64_t, &memory_space::read<uint64_t>,
957 &memory_space::write<uint64_t>>);
958 else if(type == "sqword")
959 mappings[name] = mapping(addr, do_rw<int64_t, &memory_space::read<int64_t>,
960 &memory_space::write<int64_t>>);
961 else if(type == "float")
962 mappings[name] = mapping(addr, do_rw<float, &memory_space::read<float>,
963 &memory_space::write<float>>);
964 else if(type == "double")
965 mappings[name] = mapping(addr, do_rw<double, &memory_space::read<double>,
966 &memory_space::write<double>>);
967 else
968 (stringfmt() << P.get_fname() << ": Bad type").throwex();
969 return 0;
972 lua_mmap_struct::lua_mmap_struct(lua::state& L)