Add on_snoop Lua callback
[lsnes.git] / memorymanip.cpp
blob37aab34c833073461cad756ace8a3ab35cf47a5e
1 #include "lsnes.hpp"
2 #include "window.hpp"
3 #include "command.hpp"
4 #include <iostream>
5 #include <limits>
6 #include <snes/snes.hpp>
7 #include "rom.hpp"
8 #include "memorymanip.hpp"
9 #include "fieldsplit.hpp"
10 #include <sstream>
11 #include <iomanip>
12 #include <cstdint>
13 typedef uint8_t uint8;
14 typedef uint16_t uint16;
15 typedef uint32_t uint32;
16 typedef int8_t int8;
17 typedef int16_t int16;
18 typedef int32_t int32;
19 #include <nall/platform.hpp>
20 #include <nall/endian.hpp>
21 #include <nall/varint.hpp>
22 #include <nall/bit.hpp>
23 #include <nall/serializer.hpp>
24 #include <nall/property.hpp>
25 using namespace nall;
26 #include <ui-libsnes/libsnes.hpp>
27 using namespace SNES;
30 namespace
32 struct translated_address
34 uint32_t rel_addr;
35 uint32_t raw_addr;
36 uint8_t* memory;
37 uint32_t memory_size;
38 bool not_writable;
39 bool native_endian;
42 struct region
44 std::string name;
45 uint32_t base;
46 uint32_t size;
47 uint8_t* memory;
48 bool not_writable;
49 bool native_endian;
52 std::vector<region> memory_regions;
53 uint32_t linear_ram_size = 0;
54 bool system_little_endian = true;
56 struct translated_address translate_address(uint32_t rawaddr) throw()
58 struct translated_address t;
59 t.rel_addr = 0;
60 t.raw_addr = 0;
61 t.memory = NULL;
62 t.memory_size = 0;
63 t.not_writable = true;
64 for(auto i = memory_regions.begin(); i != memory_regions.end(); ++i) {
65 if(i->base > rawaddr || i->base + i->size <= rawaddr)
66 continue;
67 t.rel_addr = rawaddr - i->base;
68 t.raw_addr = rawaddr;
69 t.memory = i->memory;
70 t.memory_size = i->size;
71 t.not_writable = i->not_writable;
72 t.native_endian = i->native_endian;
73 break;
75 return t;
78 struct translated_address translate_address_linear_ram(uint32_t ramlinaddr) throw()
80 struct translated_address t;
81 t.rel_addr = 0;
82 t.raw_addr = 0;
83 t.memory = NULL;
84 t.memory_size = 0;
85 t.not_writable = true;
86 for(auto i = memory_regions.begin(); i != memory_regions.end(); ++i) {
87 if(i->not_writable)
88 continue;
89 if(ramlinaddr >= i->size) {
90 ramlinaddr -= i->size;
91 continue;
93 t.rel_addr = ramlinaddr;
94 t.raw_addr = i->base + ramlinaddr;
95 t.memory = i->memory;
96 t.memory_size = i->size;
97 t.not_writable = i->not_writable;
98 t.native_endian = i->native_endian;
99 break;
101 return t;
104 uint32_t get_linear_ram_size() throw()
106 return linear_ram_size;
109 uint32_t create_region(const std::string& name, uint32_t base, uint8_t* memory, uint32_t size, bool readonly,
110 bool native_endian = false) throw(std::bad_alloc)
112 if(size == 0)
113 return base;
114 struct region r;
115 r.name = name;
116 r.base = base;
117 r.memory = memory;
118 r.size = size;
119 r.not_writable = readonly;
120 r.native_endian = native_endian;
121 if(!readonly)
122 linear_ram_size += size;
123 memory_regions.push_back(r);
124 return base + size;
127 uint32_t create_region(const std::string& name, uint32_t base, MappedRAM& memory, bool readonly,
128 bool native_endian = false) throw(std::bad_alloc)
130 return create_region(name, base, memory.data(), memory.size(), readonly, native_endian);
133 uint16_t native_bigendian_convert(uint16_t x) throw()
135 if(system_little_endian)
136 return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00));
137 else
138 return x;
141 uint32_t native_bigendian_convert(uint32_t x) throw()
143 if(system_little_endian)
144 return (((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
145 ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000));
146 else
147 return x;
150 uint64_t native_bigendian_convert(uint64_t x) throw()
152 if(system_little_endian)
153 return (((x >> 56) & 0xFF) | ((x >> 40) & 0xFF00) |
154 ((x >> 24) & 0xFF0000) | ((x >> 8) & 0xFF000000) |
155 ((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) |
156 ((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF00000000000000ULL));
157 else
158 return x;
163 void refresh_cart_mappings() throw(std::bad_alloc)
165 linear_ram_size = 0;
166 memory_regions.clear();
167 if(get_current_rom_info().first == ROMTYPE_NONE)
168 return;
169 create_region("WRAM", 0x007E0000, cpu.wram, 131072, false);
170 create_region("APURAM", 0x00000000, smp.apuram, 65536, false);
171 create_region("VRAM", 0x00010000, ppu.vram, 65536, false);
172 create_region("OAM", 0x00020000, ppu.oam, 544, false);
173 create_region("CGRAM", 0x00021000, ppu.cgram, 512, false);
174 if(cartridge.has_srtc()) create_region("RTC", 0x00022000, srtc.rtc, 20, false);
175 if(cartridge.has_spc7110rtc()) create_region("RTC", 0x00022000, spc7110.rtc, 20, false);
176 if(cartridge.has_necdsp()) {
177 create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(necdsp.dataRAM), 4096, false, true);
178 create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(necdsp.programROM), 65536, true,
179 true);
180 create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(necdsp.dataROM), 4096, true, true);
182 create_region("SRAM", 0x10000000, cartridge.ram, false);
183 create_region("ROM", 0x80000000, cartridge.rom, true);
184 switch(get_current_rom_info().first) {
185 case ROMTYPE_BSX:
186 case ROMTYPE_BSXSLOTTED:
187 create_region("BSXFLASH", 0x90000000, bsxflash.memory, true);
188 create_region("BSX_RAM", 0x20000000, bsxcartridge.sram, false);
189 create_region("BSX_PRAM", 0x30000000, bsxcartridge.psram, false);
190 break;
191 case ROMTYPE_SUFAMITURBO:
192 create_region("SLOTA_ROM", 0x90000000, sufamiturbo.slotA.rom, true);
193 create_region("SLOTB_ROM", 0xA0000000, sufamiturbo.slotB.rom, true);
194 create_region("SLOTA_RAM", 0x20000000, sufamiturbo.slotA.ram, false);
195 create_region("SLOTB_RAM", 0x30000000, sufamiturbo.slotB.ram, false);
196 break;
197 case ROMTYPE_SGB:
198 create_region("GBROM", 0x90000000, GameBoy::cartridge.romdata, GameBoy::cartridge.romsize, true);
199 create_region("GBRAM", 0x20000000, GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize, false);
200 break;
201 case ROMTYPE_SNES:
202 case ROMTYPE_NONE:
203 break;
207 std::vector<struct memory_region> get_regions() throw(std::bad_alloc)
209 std::vector<struct memory_region> out;
210 for(auto i = memory_regions.begin(); i != memory_regions.end(); ++i) {
211 struct memory_region r;
212 r.region_name = i->name;
213 r.baseaddr = i->base;
214 r.size = i->size;
215 r.lastaddr = i->base + i->size - 1;
216 r.readonly = i->not_writable;
217 r.native_endian = i->native_endian;
218 out.push_back(r);
220 return out;
223 uint8_t memory_read_byte(uint32_t addr) throw()
225 struct translated_address laddr = translate_address(addr);
226 uint8_t value = 0;
227 if(laddr.rel_addr < laddr.memory_size)
228 value |= laddr.memory[laddr.rel_addr++];
229 return value;
232 uint16_t memory_read_word(uint32_t addr) throw()
234 struct translated_address laddr = translate_address(addr);
235 uint16_t value = 0;
236 if(laddr.rel_addr < laddr.memory_size)
237 value |= (static_cast<uint16_t>(laddr.memory[laddr.rel_addr++]) << 8);
238 if(laddr.rel_addr < laddr.memory_size)
239 value |= (static_cast<uint16_t>(laddr.memory[laddr.rel_addr++]));
240 if(laddr.native_endian)
241 value = native_bigendian_convert(value);
242 return value;
245 uint32_t memory_read_dword(uint32_t addr) throw()
247 struct translated_address laddr = translate_address(addr);
248 uint32_t value = 0;
249 if(laddr.rel_addr < laddr.memory_size)
250 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 24);
251 if(laddr.rel_addr < laddr.memory_size)
252 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 16);
253 if(laddr.rel_addr < laddr.memory_size)
254 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 8);
255 if(laddr.rel_addr < laddr.memory_size)
256 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]));
257 if(laddr.native_endian)
258 value = native_bigendian_convert(value);
259 return value;
262 uint64_t memory_read_qword(uint32_t addr) throw()
264 struct translated_address laddr = translate_address(addr);
265 uint64_t value = 0;
266 if(laddr.rel_addr < laddr.memory_size)
267 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 56);
268 if(laddr.rel_addr < laddr.memory_size)
269 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 48);
270 if(laddr.rel_addr < laddr.memory_size)
271 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 40);
272 if(laddr.rel_addr < laddr.memory_size)
273 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 32);
274 if(laddr.rel_addr < laddr.memory_size)
275 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 24);
276 if(laddr.rel_addr < laddr.memory_size)
277 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 16);
278 if(laddr.rel_addr < laddr.memory_size)
279 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 8);
280 if(laddr.rel_addr < laddr.memory_size)
281 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]));
282 if(laddr.native_endian)
283 value = native_bigendian_convert(value);
284 return value;
287 //Byte write to address (false if failed).
288 bool memory_write_byte(uint32_t addr, uint8_t data) throw()
290 struct translated_address laddr = translate_address(addr);
291 if(laddr.rel_addr >= laddr.memory_size || laddr.not_writable)
292 return false;
293 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
294 return true;
297 bool memory_write_word(uint32_t addr, uint16_t data) throw()
299 struct translated_address laddr = translate_address(addr);
300 if(laddr.native_endian)
301 data = native_bigendian_convert(data);
302 if(laddr.rel_addr >= laddr.memory_size - 1 || laddr.not_writable)
303 return false;
304 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
305 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
306 return true;
309 bool memory_write_dword(uint32_t addr, uint32_t data) throw()
311 struct translated_address laddr = translate_address(addr);
312 if(laddr.native_endian)
313 data = native_bigendian_convert(data);
314 if(laddr.rel_addr >= laddr.memory_size - 3 || laddr.not_writable)
315 return false;
316 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 24);
317 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 16);
318 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
319 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
320 return true;
323 bool memory_write_qword(uint32_t addr, uint64_t data) throw()
325 struct translated_address laddr = translate_address(addr);
326 if(laddr.native_endian)
327 data = native_bigendian_convert(data);
328 if(laddr.rel_addr >= laddr.memory_size - 7 || laddr.not_writable)
329 return false;
330 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 56);
331 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 48);
332 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 40);
333 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 32);
334 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 24);
335 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 16);
336 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
337 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
338 return true;
341 memorysearch::memorysearch() throw(std::bad_alloc)
343 reset();
346 void memorysearch::reset() throw(std::bad_alloc)
348 uint32_t linearram = get_linear_ram_size();
349 previous_content.resize(linearram);
350 still_in.resize((linearram + 63) / 64);
351 for(uint32_t i = 0; i < linearram / 64; i++)
352 still_in[i] = 0xFFFFFFFFFFFFFFFFULL;
353 if(linearram % 64)
354 still_in[linearram / 64] = (1ULL << (linearram % 64)) - 1;
355 uint32_t addr = 0;
356 while(addr < linearram) {
357 struct translated_address t = translate_address_linear_ram(addr);
358 memcpy(&previous_content[addr], t.memory, t.memory_size);
359 addr += t.memory_size;
361 candidates = linearram;
365 * \brief Native-value search function for specific value
367 template<typename T>
368 struct search_value
371 * \brief The underlying numeric type
373 typedef T value_type;
376 * \brief Create new search object
378 * \param v The value to search for.
380 search_value(T v) throw()
382 val = v;
386 * \brief Condition function.
387 * \param oldv The old value
388 * \param newv The new value
389 * \return True if new value satisfies condition, false otherwise.
391 bool operator()(T oldv, T newv) const throw()
393 return (newv == val);
397 * \brief The value to look for
399 T val;
403 * \brief Native-value search function for less-than function.
405 template<typename T>
406 struct search_lt
409 * \brief The underlying numeric type
411 typedef T value_type;
414 * \brief Condition function.
415 * \param oldv The old value
416 * \param newv The new value
417 * \return True if new value satisfies condition, false otherwise.
419 bool operator()(T oldv, T newv) const throw()
421 return (newv < oldv);
426 * \brief Native-value search function for less-or-equal-to function.
428 template<typename T>
429 struct search_le
432 * \brief The underlying numeric type
434 typedef T value_type;
437 * \brief Condition function.
438 * \param oldv The old value
439 * \param newv The new value
440 * \return True if new value satisfies condition, false otherwise.
442 bool operator()(T oldv, T newv) const throw()
444 return (newv <= oldv);
449 * \brief Native-value search function for equals function.
451 template<typename T>
452 struct search_eq
455 * \brief The underlying numeric type
457 typedef T value_type;
460 * \brief Condition function.
461 * \param oldv The old value
462 * \param newv The new value
463 * \return True if new value satisfies condition, false otherwise.
465 bool operator()(T oldv, T newv) const throw()
467 return (newv == oldv);
472 * \brief Native-value search function for not-equal function.
474 template<typename T>
475 struct search_ne
478 * \brief The underlying numeric type
480 typedef T value_type;
483 * \brief Condition function.
484 * \param oldv The old value
485 * \param newv The new value
486 * \return True if new value satisfies condition, false otherwise.
488 bool operator()(T oldv, T newv) const throw()
490 return (newv != oldv);
495 * \brief Native-value search function for greater-or-equal-to function.
497 template<typename T>
498 struct search_ge
501 * \brief The underlying numeric type
503 typedef T value_type;
506 * \brief Condition function.
507 * \param oldv The old value
508 * \param newv The new value
509 * \return True if new value satisfies condition, false otherwise.
511 bool operator()(T oldv, T newv) const throw()
513 return (newv >= oldv);
518 * \brief Native-value search function for greater-than function.
520 template<typename T>
521 struct search_gt
524 * \brief The underlying numeric type
526 typedef T value_type;
529 * \brief Condition function.
530 * \param oldv The old value
531 * \param newv The new value
532 * \return True if new value satisfies condition, false otherwise.
534 bool operator()(T oldv, T newv) const throw()
536 return (newv > oldv);
541 * \brief Helper class to decode arguments to search functions
543 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
544 * expected for the search function.
546 template<typename T>
547 struct search_value_helper
550 * \brief The underlying numeric type
552 typedef typename T::value_type value_type;
555 * \brief Constructor constructing condition object
557 * This constructor takes in condition object with the native-value interface and makes condition object with
558 * interface used by search().
560 * \param v The condition object to wrap.
562 search_value_helper(const T& v) throw()
563 : val(v)
568 * \brief Condition function
570 * This function is search()-compatible condition function calling the underlying condition.
572 bool operator()(const uint8_t* newv, const uint8_t* oldv, uint32_t left, bool nativeendian) const throw()
574 if(left < sizeof(value_type))
575 return false;
576 value_type v1 = 0;
577 value_type v2 = 0;
578 if(nativeendian) {
579 v1 = *reinterpret_cast<const value_type*>(oldv);
580 v2 = *reinterpret_cast<const value_type*>(newv);
581 } else
582 for(size_t i = 0; i < sizeof(value_type); i++) {
583 v1 |= static_cast<value_type>(oldv[i]) << (8 * (sizeof(value_type) - i));
584 v2 |= static_cast<value_type>(newv[i]) << (8 * (sizeof(value_type) - i));
586 return val(v1, v2);
590 * \brief The underlying condition.
592 const T& val;
595 template<class T> void memorysearch::search(const T& obj) throw()
597 search_value_helper<T> helper(obj);
598 struct translated_address t = translate_address_linear_ram(0);
599 uint32_t switch_at = t.memory_size;
600 uint32_t base = 0;
601 uint32_t size = previous_content.size();
602 for(uint32_t i = 0; i < size; i++) {
603 if(still_in[i / 64] == 0) {
604 i = (i + 64) >> 6 << 6;
605 i--;
606 continue;
608 //t.memory_size == 0 can happen if cart changes.
609 while(i >= switch_at && t.memory_size > 0) {
610 t = translate_address_linear_ram(switch_at);
611 base = switch_at;
612 switch_at += t.memory_size;
614 if(t.memory_size == 0 || !helper(t.memory + i - base, &previous_content[i],
615 t.memory_size - (i - base), t.native_endian)) {
616 if((still_in[i / 64] >> (i % 64)) & 1) {
617 still_in[i / 64] &= ~(1ULL << (i % 64));
618 candidates--;
622 t = translate_address_linear_ram(0);
623 base = 0;
624 size = previous_content.size();
625 while(base < size) {
626 size_t m = t.memory_size;
627 if(m > (size - base))
628 m = size - base;
629 memcpy(&previous_content[base], t.memory, m);
630 base += t.memory_size;
631 t = translate_address_linear_ram(base);
635 void memorysearch::byte_value(uint8_t value) throw() { search(search_value<uint8_t>(value)); }
636 void memorysearch::byte_slt() throw() { search(search_lt<int8_t>()); }
637 void memorysearch::byte_sle() throw() { search(search_le<int8_t>()); }
638 void memorysearch::byte_seq() throw() { search(search_eq<int8_t>()); }
639 void memorysearch::byte_sne() throw() { search(search_ne<int8_t>()); }
640 void memorysearch::byte_sge() throw() { search(search_ge<int8_t>()); }
641 void memorysearch::byte_sgt() throw() { search(search_gt<int8_t>()); }
642 void memorysearch::byte_ult() throw() { search(search_lt<uint8_t>()); }
643 void memorysearch::byte_ule() throw() { search(search_le<uint8_t>()); }
644 void memorysearch::byte_ueq() throw() { search(search_eq<uint8_t>()); }
645 void memorysearch::byte_une() throw() { search(search_ne<uint8_t>()); }
646 void memorysearch::byte_uge() throw() { search(search_ge<uint8_t>()); }
647 void memorysearch::byte_ugt() throw() { search(search_gt<uint8_t>()); }
649 void memorysearch::word_value(uint16_t value) throw() { search(search_value<uint16_t>(value)); }
650 void memorysearch::word_slt() throw() { search(search_lt<int16_t>()); }
651 void memorysearch::word_sle() throw() { search(search_le<int16_t>()); }
652 void memorysearch::word_seq() throw() { search(search_eq<int16_t>()); }
653 void memorysearch::word_sne() throw() { search(search_ne<int16_t>()); }
654 void memorysearch::word_sge() throw() { search(search_ge<int16_t>()); }
655 void memorysearch::word_sgt() throw() { search(search_gt<int16_t>()); }
656 void memorysearch::word_ult() throw() { search(search_lt<uint16_t>()); }
657 void memorysearch::word_ule() throw() { search(search_le<uint16_t>()); }
658 void memorysearch::word_ueq() throw() { search(search_eq<uint16_t>()); }
659 void memorysearch::word_une() throw() { search(search_ne<uint16_t>()); }
660 void memorysearch::word_uge() throw() { search(search_ge<uint16_t>()); }
661 void memorysearch::word_ugt() throw() { search(search_gt<uint16_t>()); }
663 void memorysearch::dword_value(uint32_t value) throw() { search(search_value<uint32_t>(value)); }
664 void memorysearch::dword_slt() throw() { search(search_lt<int32_t>()); }
665 void memorysearch::dword_sle() throw() { search(search_le<int32_t>()); }
666 void memorysearch::dword_seq() throw() { search(search_eq<int32_t>()); }
667 void memorysearch::dword_sne() throw() { search(search_ne<int32_t>()); }
668 void memorysearch::dword_sge() throw() { search(search_ge<int32_t>()); }
669 void memorysearch::dword_sgt() throw() { search(search_gt<int32_t>()); }
670 void memorysearch::dword_ult() throw() { search(search_lt<uint32_t>()); }
671 void memorysearch::dword_ule() throw() { search(search_le<uint32_t>()); }
672 void memorysearch::dword_ueq() throw() { search(search_eq<uint32_t>()); }
673 void memorysearch::dword_une() throw() { search(search_ne<uint32_t>()); }
674 void memorysearch::dword_uge() throw() { search(search_ge<uint32_t>()); }
675 void memorysearch::dword_ugt() throw() { search(search_gt<uint32_t>()); }
677 void memorysearch::qword_value(uint64_t value) throw() { search(search_value<uint64_t>(value)); }
678 void memorysearch::qword_slt() throw() { search(search_lt<int64_t>()); }
679 void memorysearch::qword_sle() throw() { search(search_le<int64_t>()); }
680 void memorysearch::qword_seq() throw() { search(search_eq<int64_t>()); }
681 void memorysearch::qword_sne() throw() { search(search_ne<int64_t>()); }
682 void memorysearch::qword_sge() throw() { search(search_ge<int64_t>()); }
683 void memorysearch::qword_sgt() throw() { search(search_gt<int64_t>()); }
684 void memorysearch::qword_ult() throw() { search(search_lt<uint64_t>()); }
685 void memorysearch::qword_ule() throw() { search(search_le<uint64_t>()); }
686 void memorysearch::qword_ueq() throw() { search(search_eq<uint64_t>()); }
687 void memorysearch::qword_une() throw() { search(search_ne<uint64_t>()); }
688 void memorysearch::qword_uge() throw() { search(search_ge<uint64_t>()); }
689 void memorysearch::qword_ugt() throw() { search(search_gt<uint64_t>()); }
691 uint32_t memorysearch::get_candidate_count() throw()
693 return candidates;
696 std::list<uint32_t> memorysearch::get_candidates() throw(std::bad_alloc)
698 struct translated_address t = translate_address_linear_ram(0);
699 uint32_t switch_at = t.memory_size;
700 uint32_t base = 0;
701 uint32_t rbase = t.raw_addr;
702 uint32_t size = previous_content.size();
703 std::list<uint32_t> out;
705 for(uint32_t i = 0; i < size; i++) {
706 if(still_in[i / 64] == 0) {
707 i = (i + 64) >> 6 << 6;
708 i--;
709 continue;
711 while(i >= switch_at && t.memory_size > 0) {
712 t = translate_address_linear_ram(switch_at);
713 base = switch_at;
714 rbase = t.raw_addr - t.rel_addr;
715 switch_at += t.memory_size;
717 if((still_in[i / 64] >> (i % 64)) & 1)
718 out.push_back(i - base + rbase);
720 std::cout << "out=" << out.size() << " candidates=" << candidates << std::endl;
721 return out;
724 namespace
726 memorysearch* isrch;
728 std::string tokenize1(const std::string& command, const std::string& syntax);
729 std::pair<std::string, std::string> tokenize2(const std::string& command, const std::string& syntax);
730 std::pair<std::string, std::string> tokenize12(const std::string& command, const std::string& syntax);
732 unsigned char hex(char ch)
734 switch(ch) {
735 case '0': return 0;
736 case '1': return 1;
737 case '2': return 2;
738 case '3': return 3;
739 case '4': return 4;
740 case '5': return 5;
741 case '6': return 6;
742 case '7': return 7;
743 case '8': return 8;
744 case '9': return 9;
745 case 'a': case 'A': return 10;
746 case 'b': case 'B': return 11;
747 case 'c': case 'C': return 12;
748 case 'd': case 'D': return 13;
749 case 'e': case 'E': return 14;
750 case 'f': case 'F': return 15;
752 throw std::runtime_error("Bad hex character");
755 class memorymanip_command : public command
757 public:
758 memorymanip_command(const std::string& cmd) throw(std::bad_alloc)
759 : command(cmd)
761 _command = cmd;
763 ~memorymanip_command() throw() {}
764 void invoke(const std::string& args, window* win) throw(std::bad_alloc, std::runtime_error)
766 tokensplitter t(args);
767 firstword = static_cast<std::string>(t);
768 secondword = static_cast<std::string>(t);
769 has_tail = t;
770 address_bad = true;
771 value_bad = true;
772 has_value = (secondword != "");
773 try {
774 if(firstword.length() >= 2 && firstword.substr(0, 2) == "0x") {
775 if(firstword.length() > 10)
776 throw 42;
777 address = 0;
778 for(unsigned i = 2; i < firstword.length(); i++)
779 address = 16 * address + hex(firstword[i]);
780 } else {
781 address = parse_value<uint32_t>(firstword);
783 address_bad = false;
784 } catch(...) {
786 try {
787 if(secondword.length() >= 2 && secondword.substr(0, 2) == "0x") {
788 if(secondword.length() > 18)
789 throw 42;
790 value = 0;
791 for(unsigned i = 2; i < secondword.length(); i++)
792 value = 16 * value + hex(secondword[i]);
793 } else if(secondword.length() > 0 && secondword[0] == '-') {
794 value = static_cast<uint64_t>(parse_value<int64_t>(secondword));
795 } else {
796 value = parse_value<uint64_t>(secondword);
798 value_bad = false;
799 } catch(...) {
801 invoke2(win);
803 virtual void invoke2(window* win) throw(std::bad_alloc, std::runtime_error) = 0;
804 std::string firstword;
805 std::string secondword;
806 uint32_t address;
807 uint64_t value;
808 bool has_tail;
809 bool address_bad;
810 bool value_bad;
811 bool has_value;
812 std::string _command;
815 template<typename outer, typename inner, typename ret>
816 class read_command : public memorymanip_command
818 public:
819 read_command(const std::string& cmd, ret (*_rfn)(uint32_t addr)) throw(std::bad_alloc)
820 : memorymanip_command(cmd)
822 rfn = _rfn;
824 ~read_command() throw() {}
825 void invoke2(window* win) throw(std::bad_alloc, std::runtime_error)
827 if(address_bad || has_value || has_tail)
828 throw std::runtime_error("Syntax: " + _command + " <address>");
830 std::ostringstream x;
831 x << "0x" << std::hex << address << " -> " << std::dec
832 << static_cast<outer>(static_cast<inner>(rfn(address)));
833 out(win) << x.str() << std::endl;
836 std::string get_short_help() throw(std::bad_alloc) { return "Read memory"; }
837 std::string get_long_help() throw(std::bad_alloc)
839 return "Syntax: " + _command + " <address>\n"
840 "Reads data from memory.\n";
843 ret (*rfn)(uint32_t addr);
846 template<typename arg, int64_t low, uint64_t high>
847 class write_command : public memorymanip_command
849 public:
850 write_command(const std::string& cmd, bool (*_wfn)(uint32_t addr, arg a)) throw(std::bad_alloc)
851 : memorymanip_command(cmd)
853 wfn = _wfn;
855 ~write_command() throw() {}
856 void invoke2(window* win) throw(std::bad_alloc, std::runtime_error)
858 if(address_bad || value_bad || has_tail)
859 throw std::runtime_error("Syntax: " + _command + " <address> <value>");
860 if(static_cast<int64_t>(value) < low || value > high)
861 throw std::runtime_error("Value to write out of range");
862 wfn(address, value & high);
864 std::string get_short_help() throw(std::bad_alloc) { return "Write memory"; }
865 std::string get_long_help() throw(std::bad_alloc)
867 return "Syntax: " + _command + " <address> <value>\n"
868 "Writes data to memory.\n";
870 bool (*wfn)(uint32_t addr, arg a);
873 class memorysearch_command : public memorymanip_command
875 public:
876 memorysearch_command() throw(std::bad_alloc) : memorymanip_command("search-memory") {}
877 void invoke2(window* win) throw(std::bad_alloc, std::runtime_error)
879 if(!isrch)
880 isrch = new memorysearch();
881 if(firstword == "sblt" && !has_value)
882 isrch->byte_slt();
883 else if(firstword == "sble" && !has_value)
884 isrch->byte_sle();
885 else if(firstword == "sbeq" && !has_value)
886 isrch->byte_seq();
887 else if(firstword == "sbne" && !has_value)
888 isrch->byte_sne();
889 else if(firstword == "sbge" && !has_value)
890 isrch->byte_sge();
891 else if(firstword == "sbgt" && !has_value)
892 isrch->byte_sgt();
893 else if(firstword == "ublt" && !has_value)
894 isrch->byte_ult();
895 else if(firstword == "uble" && !has_value)
896 isrch->byte_ule();
897 else if(firstword == "ubeq" && !has_value)
898 isrch->byte_ueq();
899 else if(firstword == "ubne" && !has_value)
900 isrch->byte_une();
901 else if(firstword == "ubge" && !has_value)
902 isrch->byte_uge();
903 else if(firstword == "ubgt" && !has_value)
904 isrch->byte_ugt();
905 else if(firstword == "b" && has_value) {
906 if(static_cast<int64_t>(value) < -128 || value > 255)
907 throw std::runtime_error("Value to compare out of range");
908 isrch->byte_value(value & 0xFF);
909 } else if(firstword == "swlt" && !has_value)
910 isrch->word_slt();
911 else if(firstword == "swle" && !has_value)
912 isrch->word_sle();
913 else if(firstword == "sweq" && !has_value)
914 isrch->word_seq();
915 else if(firstword == "swne" && !has_value)
916 isrch->word_sne();
917 else if(firstword == "swge" && !has_value)
918 isrch->word_sge();
919 else if(firstword == "swgt" && !has_value)
920 isrch->word_sgt();
921 else if(firstword == "uwlt" && !has_value)
922 isrch->word_ult();
923 else if(firstword == "uwle" && !has_value)
924 isrch->word_ule();
925 else if(firstword == "uweq" && !has_value)
926 isrch->word_ueq();
927 else if(firstword == "uwne" && !has_value)
928 isrch->word_une();
929 else if(firstword == "uwge" && !has_value)
930 isrch->word_uge();
931 else if(firstword == "uwgt" && !has_value)
932 isrch->word_ugt();
933 else if(firstword == "w" && has_value) {
934 if(static_cast<int64_t>(value) < -32768 || value > 65535)
935 throw std::runtime_error("Value to compare out of range");
936 isrch->word_value(value & 0xFF);
937 } else if(firstword == "sdlt" && !has_value)
938 isrch->dword_slt();
939 else if(firstword == "sdle" && !has_value)
940 isrch->dword_sle();
941 else if(firstword == "sdeq" && !has_value)
942 isrch->dword_seq();
943 else if(firstword == "sdne" && !has_value)
944 isrch->dword_sne();
945 else if(firstword == "sdge" && !has_value)
946 isrch->dword_sge();
947 else if(firstword == "sdgt" && !has_value)
948 isrch->dword_sgt();
949 else if(firstword == "udlt" && !has_value)
950 isrch->dword_ult();
951 else if(firstword == "udle" && !has_value)
952 isrch->dword_ule();
953 else if(firstword == "udeq" && !has_value)
954 isrch->dword_ueq();
955 else if(firstword == "udne" && !has_value)
956 isrch->dword_une();
957 else if(firstword == "udge" && !has_value)
958 isrch->dword_uge();
959 else if(firstword == "udgt" && !has_value)
960 isrch->dword_ugt();
961 else if(firstword == "d" && has_value) {
962 if(static_cast<int64_t>(value) < -2147483648 || value > 4294967295ULL)
963 throw std::runtime_error("Value to compare out of range");
964 isrch->dword_value(value & 0xFF);
965 } else if(firstword == "sqlt" && !has_value)
966 isrch->qword_slt();
967 else if(firstword == "sqle" && !has_value)
968 isrch->qword_sle();
969 else if(firstword == "sqeq" && !has_value)
970 isrch->qword_seq();
971 else if(firstword == "sqne" && !has_value)
972 isrch->qword_sne();
973 else if(firstword == "sqge" && !has_value)
974 isrch->qword_sge();
975 else if(firstword == "sqgt" && !has_value)
976 isrch->qword_sgt();
977 else if(firstword == "uqlt" && !has_value)
978 isrch->qword_ult();
979 else if(firstword == "uqle" && !has_value)
980 isrch->qword_ule();
981 else if(firstword == "uqeq" && !has_value)
982 isrch->qword_ueq();
983 else if(firstword == "uqne" && !has_value)
984 isrch->qword_une();
985 else if(firstword == "uqge" && !has_value)
986 isrch->qword_uge();
987 else if(firstword == "uqgt" && !has_value)
988 isrch->qword_ugt();
989 else if(firstword == "q" && has_value) {
990 isrch->qword_value(value & 0xFF);
991 } else if(firstword == "reset" && !has_value)
992 isrch->reset();
993 else if(firstword == "count" && !has_value)
995 else if(firstword == "print" && !has_value) {
996 auto c = isrch->get_candidates();
997 for(auto ci = c.begin(); ci != c.end(); ci++) {
998 std::ostringstream x;
999 x << "0x" << std::hex << std::setw(8) << std::setfill('0') << *ci;
1000 out(win) << x.str() << std::endl;
1002 } else
1003 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword + "'");
1004 out(win) << isrch->get_candidate_count() << " candidates remain." << std::endl;
1006 std::string get_short_help() throw(std::bad_alloc) { return "Search memory addresses"; }
1007 std::string get_long_help() throw(std::bad_alloc)
1009 return "Syntax: " + _command + " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
1010 "Syntax: " + _command + " {b,w,d,q} <value>\n"
1011 "Syntax: " + _command + " reset\n"
1012 "Syntax: " + _command + " count\n"
1013 "Syntax: " + _command + " print\n"
1014 "Searches addresses from memory.\n";
1016 } memorysearch_o;
1018 read_command<uint64_t, uint8_t, uint8_t> ru1("read-byte", memory_read_byte);
1019 read_command<uint64_t, uint16_t, uint16_t> ru2("read-word", memory_read_word);
1020 read_command<uint64_t, uint32_t, uint32_t> ru4("read-dword", memory_read_dword);
1021 read_command<uint64_t, uint64_t, uint64_t> ru8("read-qword", memory_read_qword);
1022 read_command<uint64_t, int8_t, uint8_t> rs1("read-sbyte", memory_read_byte);
1023 read_command<uint64_t, int16_t, uint16_t> rs2("read-sword", memory_read_word);
1024 read_command<uint64_t, int32_t, uint32_t> rs4("read-sdword", memory_read_dword);
1025 read_command<uint64_t, int64_t, uint64_t> rs8("read-sqword", memory_read_qword);
1026 write_command<uint8_t, -128, 0xFF> w1("write-byte", memory_write_byte);
1027 write_command<uint16_t, -32768, 0xFFFF> w2("write-word", memory_write_word);
1028 write_command<uint32_t, -2147483648, 0xFFFFFFFFU> w4("write-dword", memory_write_dword);
1029 write_command<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL> w8("write-qword", memory_write_qword);