Add header file in order to make it compile with bsnes v086
[lsnes.git] / src / core / memorymanip.cpp
bloba5c363f560bf406930c4dfef8b15fa6c013d79f8
1 #include "lsnes.hpp"
2 #include <snes/snes.hpp>
3 #include <gameboy/gameboy.hpp>
4 #include <ui-libsnes/libsnes.hpp>
6 #include "core/command.hpp"
7 #include "core/memorymanip.hpp"
8 #include "core/misc.hpp"
9 #include "core/rom.hpp"
11 #include <iostream>
12 #include <limits>
13 #include <sstream>
14 #include <iomanip>
15 #include <cstdint>
17 typedef uint8_t uint8;
18 typedef uint16_t uint16;
19 typedef uint32_t uint32;
20 typedef int8_t int8;
21 typedef int16_t int16;
22 typedef int32_t int32;
23 #include <nall/platform.hpp>
24 #include <nall/endian.hpp>
25 #include <nall/varint.hpp>
26 #include <nall/bit.hpp>
27 #include <nall/serializer.hpp>
28 #include <nall/property.hpp>
29 using namespace nall;
30 using namespace SNES;
33 namespace
35 struct translated_address
37 uint32_t rel_addr;
38 uint32_t raw_addr;
39 uint8_t* memory;
40 uint32_t memory_size;
41 bool not_writable;
42 bool native_endian;
45 struct region
47 std::string name;
48 uint32_t base;
49 uint32_t size;
50 uint8_t* memory;
51 bool not_writable;
52 bool native_endian;
55 std::vector<region> memory_regions;
56 uint32_t linear_ram_size = 0;
57 bool system_little_endian = true;
59 struct translated_address translate_address(uint32_t rawaddr) throw()
61 struct translated_address t;
62 t.rel_addr = 0;
63 t.raw_addr = 0;
64 t.memory = NULL;
65 t.memory_size = 0;
66 t.not_writable = true;
67 for(auto i : memory_regions) {
68 if(i.base > rawaddr || i.base + i.size <= rawaddr)
69 continue;
70 t.rel_addr = rawaddr - i.base;
71 t.raw_addr = rawaddr;
72 t.memory = i.memory;
73 t.memory_size = i.size;
74 t.not_writable = i.not_writable;
75 t.native_endian = i.native_endian;
76 break;
78 return t;
81 struct translated_address translate_address_linear_ram(uint32_t ramlinaddr) throw()
83 struct translated_address t;
84 t.rel_addr = 0;
85 t.raw_addr = 0;
86 t.memory = NULL;
87 t.memory_size = 0;
88 t.not_writable = true;
89 for(auto i : memory_regions) {
90 if(i.not_writable)
91 continue;
92 if(ramlinaddr >= i.size) {
93 ramlinaddr -= i.size;
94 continue;
96 t.rel_addr = ramlinaddr;
97 t.raw_addr = i.base + ramlinaddr;
98 t.memory = i.memory;
99 t.memory_size = i.size;
100 t.not_writable = i.not_writable;
101 t.native_endian = i.native_endian;
102 break;
104 return t;
107 uint32_t get_linear_ram_size() throw()
109 return linear_ram_size;
112 uint32_t create_region(const std::string& name, uint32_t base, uint8_t* memory, uint32_t size, bool readonly,
113 bool native_endian = false) throw(std::bad_alloc)
115 if(size == 0)
116 return base;
117 struct region r;
118 r.name = name;
119 r.base = base;
120 r.memory = memory;
121 r.size = size;
122 r.not_writable = readonly;
123 r.native_endian = native_endian;
124 if(!readonly)
125 linear_ram_size += size;
126 memory_regions.push_back(r);
127 return base + size;
130 uint32_t create_region(const std::string& name, uint32_t base, SNES::MappedRAM& memory, bool readonly,
131 bool native_endian = false) throw(std::bad_alloc)
133 return create_region(name, base, memory.data(), memory.size(), readonly, native_endian);
136 uint16_t native_littleendian_convert(uint16_t x) throw()
138 if(!system_little_endian)
139 return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00));
140 else
141 return x;
144 uint32_t native_littleendian_convert(uint32_t x) throw()
146 if(!system_little_endian)
147 return (((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
148 ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000));
149 else
150 return x;
153 uint64_t native_littleendian_convert(uint64_t x) throw()
155 if(!system_little_endian)
156 return (((x >> 56) & 0xFF) | ((x >> 40) & 0xFF00) |
157 ((x >> 24) & 0xFF0000) | ((x >> 8) & 0xFF000000) |
158 ((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) |
159 ((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF00000000000000ULL));
160 else
161 return x;
165 void refresh_cart_mappings() throw(std::bad_alloc)
167 linear_ram_size = 0;
168 memory_regions.clear();
169 if(get_current_rom_info().first == ROMTYPE_NONE)
170 return;
171 create_region("WRAM", 0x007E0000, SNES::cpu.wram, 131072, false);
172 create_region("APURAM", 0x00000000, SNES::smp.apuram, 65536, false);
173 create_region("VRAM", 0x00010000, SNES::ppu.vram, 65536, false);
174 create_region("OAM", 0x00020000, SNES::ppu.oam, 544, false);
175 create_region("CGRAM", 0x00021000, SNES::ppu.cgram, 512, false);
176 if(SNES::cartridge.has_srtc()) create_region("RTC", 0x00022000, SNES::srtc.rtc, 20, false);
177 if(SNES::cartridge.has_spc7110rtc()) create_region("RTC", 0x00022000, SNES::spc7110.rtc, 20, false);
178 if(SNES::cartridge.has_necdsp()) {
179 create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataRAM), 4096, false,
180 true);
181 create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp.programROM), 65536, true,
182 true);
183 create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataROM), 4096, true,
184 true);
186 create_region("SRAM", 0x10000000, SNES::cartridge.ram, false);
187 create_region("ROM", 0x80000000, SNES::cartridge.rom, true);
188 switch(get_current_rom_info().first) {
189 case ROMTYPE_BSX:
190 case ROMTYPE_BSXSLOTTED:
191 create_region("BSXFLASH", 0x90000000, SNES::bsxflash.memory, true);
192 create_region("BSX_RAM", 0x20000000, SNES::bsxcartridge.sram, false);
193 create_region("BSX_PRAM", 0x30000000, SNES::bsxcartridge.psram, false);
194 break;
195 case ROMTYPE_SUFAMITURBO:
196 create_region("SLOTA_ROM", 0x90000000, SNES::sufamiturbo.slotA.rom, true);
197 create_region("SLOTB_ROM", 0xA0000000, SNES::sufamiturbo.slotB.rom, true);
198 create_region("SLOTA_RAM", 0x20000000, SNES::sufamiturbo.slotA.ram, false);
199 create_region("SLOTB_RAM", 0x30000000, SNES::sufamiturbo.slotB.ram, false);
200 break;
201 case ROMTYPE_SGB:
202 create_region("GBROM", 0x90000000, GameBoy::cartridge.romdata, GameBoy::cartridge.romsize, true);
203 create_region("GBRAM", 0x20000000, GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize, false);
204 break;
205 case ROMTYPE_SNES:
206 case ROMTYPE_NONE:
207 break;
211 std::vector<struct memory_region> get_regions() throw(std::bad_alloc)
213 std::vector<struct memory_region> out;
214 for(auto i : memory_regions) {
215 struct memory_region r;
216 r.region_name = i.name;
217 r.baseaddr = i.base;
218 r.size = i.size;
219 r.lastaddr = i.base + i.size - 1;
220 r.readonly = i.not_writable;
221 r.native_endian = i.native_endian;
222 out.push_back(r);
224 return out;
227 uint8_t memory_read_byte(uint32_t addr) throw()
229 struct translated_address laddr = translate_address(addr);
230 uint8_t value = 0;
231 if(laddr.rel_addr < laddr.memory_size)
232 value |= laddr.memory[laddr.rel_addr++];
233 return value;
236 uint16_t memory_read_word(uint32_t addr) throw()
238 struct translated_address laddr = translate_address(addr);
239 uint16_t value = 0;
240 if(laddr.rel_addr < laddr.memory_size)
241 value |= (static_cast<uint16_t>(laddr.memory[laddr.rel_addr++]));
242 if(laddr.rel_addr < laddr.memory_size)
243 value |= (static_cast<uint16_t>(laddr.memory[laddr.rel_addr++]) << 8);
244 if(laddr.native_endian)
245 value = native_littleendian_convert(value);
246 return value;
249 uint32_t memory_read_dword(uint32_t addr) throw()
251 struct translated_address laddr = translate_address(addr);
252 uint32_t value = 0;
253 if(laddr.rel_addr < laddr.memory_size)
254 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]));
255 if(laddr.rel_addr < laddr.memory_size)
256 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 8);
257 if(laddr.rel_addr < laddr.memory_size)
258 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 16);
259 if(laddr.rel_addr < laddr.memory_size)
260 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 24);
261 if(laddr.native_endian)
262 value = native_littleendian_convert(value);
263 return value;
266 uint64_t memory_read_qword(uint32_t addr) throw()
268 struct translated_address laddr = translate_address(addr);
269 uint64_t value = 0;
270 if(laddr.rel_addr < laddr.memory_size)
271 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]));
272 if(laddr.rel_addr < laddr.memory_size)
273 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 8);
274 if(laddr.rel_addr < laddr.memory_size)
275 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 16);
276 if(laddr.rel_addr < laddr.memory_size)
277 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 24);
278 if(laddr.rel_addr < laddr.memory_size)
279 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 32);
280 if(laddr.rel_addr < laddr.memory_size)
281 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 40);
282 if(laddr.rel_addr < laddr.memory_size)
283 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 48);
284 if(laddr.rel_addr < laddr.memory_size)
285 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 56);
286 if(laddr.native_endian)
287 value = native_littleendian_convert(value);
288 return value;
291 //Byte write to address (false if failed).
292 bool memory_write_byte(uint32_t addr, uint8_t data) throw()
294 struct translated_address laddr = translate_address(addr);
295 if(laddr.rel_addr >= laddr.memory_size || laddr.not_writable)
296 return false;
297 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
298 return true;
301 bool memory_write_word(uint32_t addr, uint16_t data) throw()
303 struct translated_address laddr = translate_address(addr);
304 if(laddr.native_endian)
305 data = native_littleendian_convert(data);
306 if(laddr.rel_addr >= laddr.memory_size - 1 || laddr.not_writable)
307 return false;
308 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
309 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
310 return true;
313 bool memory_write_dword(uint32_t addr, uint32_t data) throw()
315 struct translated_address laddr = translate_address(addr);
316 if(laddr.native_endian)
317 data = native_littleendian_convert(data);
318 if(laddr.rel_addr >= laddr.memory_size - 3 || laddr.not_writable)
319 return false;
320 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
321 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
322 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 16);
323 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 24);
324 return true;
327 bool memory_write_qword(uint32_t addr, uint64_t data) throw()
329 struct translated_address laddr = translate_address(addr);
330 if(laddr.native_endian)
331 data = native_littleendian_convert(data);
332 if(laddr.rel_addr >= laddr.memory_size - 7 || laddr.not_writable)
333 return false;
334 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
335 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
336 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 16);
337 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 24);
338 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 32);
339 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 40);
340 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 48);
341 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 56);
342 return true;
345 memorysearch::memorysearch() throw(std::bad_alloc)
347 reset();
350 void memorysearch::reset() throw(std::bad_alloc)
352 uint32_t linearram = get_linear_ram_size();
353 previous_content.resize(linearram);
354 still_in.resize((linearram + 63) / 64);
355 for(uint32_t i = 0; i < linearram / 64; i++)
356 still_in[i] = 0xFFFFFFFFFFFFFFFFULL;
357 if(linearram % 64)
358 still_in[linearram / 64] = (1ULL << (linearram % 64)) - 1;
359 uint32_t addr = 0;
360 while(addr < linearram) {
361 struct translated_address t = translate_address_linear_ram(addr);
362 memcpy(&previous_content[addr], t.memory, t.memory_size);
363 addr += t.memory_size;
365 candidates = linearram;
369 * \brief Native-value search function for trivial true function
371 struct search_update
374 * \brief The underlying numeric type
376 typedef uint8_t value_type;
379 * \brief Condition function.
380 * \param oldv The old value
381 * \param newv The new value
382 * \return True if new value satisfies condition, false otherwise.
384 bool operator()(uint8_t oldv, uint8_t newv) const throw()
386 return true;
391 * \brief Native-value search function for specific value
393 template<typename T>
394 struct search_value
397 * \brief The underlying numeric type
399 typedef T value_type;
402 * \brief Create new search object
404 * \param v The value to search for.
406 search_value(T v) throw()
408 val = v;
412 * \brief Condition function.
413 * \param oldv The old value
414 * \param newv The new value
415 * \return True if new value satisfies condition, false otherwise.
417 bool operator()(T oldv, T newv) const throw()
419 return (newv == val);
423 * \brief The value to look for
425 T val;
429 * \brief Native-value search function for less-than function.
431 template<typename T>
432 struct search_lt
435 * \brief The underlying numeric type
437 typedef T value_type;
440 * \brief Condition function.
441 * \param oldv The old value
442 * \param newv The new value
443 * \return True if new value satisfies condition, false otherwise.
445 bool operator()(T oldv, T newv) const throw()
447 return (newv < oldv);
452 * \brief Native-value search function for less-or-equal-to function.
454 template<typename T>
455 struct search_le
458 * \brief The underlying numeric type
460 typedef T value_type;
463 * \brief Condition function.
464 * \param oldv The old value
465 * \param newv The new value
466 * \return True if new value satisfies condition, false otherwise.
468 bool operator()(T oldv, T newv) const throw()
470 return (newv <= oldv);
475 * \brief Native-value search function for equals function.
477 template<typename T>
478 struct search_eq
481 * \brief The underlying numeric type
483 typedef T value_type;
486 * \brief Condition function.
487 * \param oldv The old value
488 * \param newv The new value
489 * \return True if new value satisfies condition, false otherwise.
491 bool operator()(T oldv, T newv) const throw()
493 return (newv == oldv);
498 * \brief Native-value search function for not-equal function.
500 template<typename T>
501 struct search_ne
504 * \brief The underlying numeric type
506 typedef T value_type;
509 * \brief Condition function.
510 * \param oldv The old value
511 * \param newv The new value
512 * \return True if new value satisfies condition, false otherwise.
514 bool operator()(T oldv, T newv) const throw()
516 return (newv != oldv);
521 * \brief Native-value search function for greater-or-equal-to function.
523 template<typename T>
524 struct search_ge
527 * \brief The underlying numeric type
529 typedef T value_type;
532 * \brief Condition function.
533 * \param oldv The old value
534 * \param newv The new value
535 * \return True if new value satisfies condition, false otherwise.
537 bool operator()(T oldv, T newv) const throw()
539 return (newv >= oldv);
544 * \brief Native-value search function for greater-than function.
546 template<typename T>
547 struct search_gt
550 * \brief The underlying numeric type
552 typedef T value_type;
555 * \brief Condition function.
556 * \param oldv The old value
557 * \param newv The new value
558 * \return True if new value satisfies condition, false otherwise.
560 bool operator()(T oldv, T newv) const throw()
562 return (newv > oldv);
567 * \brief Helper class to decode arguments to search functions
569 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
570 * expected for the search function.
572 template<typename T>
573 struct search_value_helper
576 * \brief The underlying numeric type
578 typedef typename T::value_type value_type;
581 * \brief Constructor constructing condition object
583 * This constructor takes in condition object with the native-value interface and makes condition object with
584 * interface used by search().
586 * \param v The condition object to wrap.
588 search_value_helper(const T& v) throw()
589 : val(v)
594 * \brief Condition function
596 * This function is search()-compatible condition function calling the underlying condition.
598 bool operator()(const uint8_t* newv, const uint8_t* oldv, uint32_t left, bool nativeendian) const throw()
600 if(left < sizeof(value_type))
601 return false;
602 value_type v1 = 0;
603 value_type v2 = 0;
604 if(nativeendian) {
605 v1 = *reinterpret_cast<const value_type*>(oldv);
606 v2 = *reinterpret_cast<const value_type*>(newv);
607 } else
608 for(size_t i = 0; i < sizeof(value_type); i++) {
609 v1 |= static_cast<value_type>(oldv[i]) << (8 * i);
610 v2 |= static_cast<value_type>(newv[i]) << (8 * i);
612 return val(v1, v2);
616 * \brief The underlying condition.
618 const T& val;
621 template<class T> void memorysearch::search(const T& obj) throw()
623 search_value_helper<T> helper(obj);
624 struct translated_address t = translate_address_linear_ram(0);
625 uint32_t switch_at = t.memory_size;
626 uint32_t base = 0;
627 uint32_t size = previous_content.size();
628 for(uint32_t i = 0; i < size; i++) {
629 if(still_in[i / 64] == 0) {
630 i = (i + 64) >> 6 << 6;
631 i--;
632 continue;
634 //t.memory_size == 0 can happen if cart changes.
635 while(i >= switch_at && t.memory_size > 0) {
636 t = translate_address_linear_ram(switch_at);
637 base = switch_at;
638 switch_at += t.memory_size;
640 if(t.memory_size == 0 || !helper(t.memory + i - base, &previous_content[i],
641 t.memory_size - (i - base), t.native_endian)) {
642 if((still_in[i / 64] >> (i % 64)) & 1) {
643 still_in[i / 64] &= ~(1ULL << (i % 64));
644 candidates--;
648 t = translate_address_linear_ram(0);
649 base = 0;
650 size = previous_content.size();
651 while(base < size) {
652 size_t m = t.memory_size;
653 if(m > (size - base))
654 m = size - base;
655 memcpy(&previous_content[base], t.memory, m);
656 base += t.memory_size;
657 t = translate_address_linear_ram(base);
661 void memorysearch::byte_value(uint8_t value) throw() { search(search_value<uint8_t>(value)); }
662 void memorysearch::byte_slt() throw() { search(search_lt<int8_t>()); }
663 void memorysearch::byte_sle() throw() { search(search_le<int8_t>()); }
664 void memorysearch::byte_seq() throw() { search(search_eq<int8_t>()); }
665 void memorysearch::byte_sne() throw() { search(search_ne<int8_t>()); }
666 void memorysearch::byte_sge() throw() { search(search_ge<int8_t>()); }
667 void memorysearch::byte_sgt() throw() { search(search_gt<int8_t>()); }
668 void memorysearch::byte_ult() throw() { search(search_lt<uint8_t>()); }
669 void memorysearch::byte_ule() throw() { search(search_le<uint8_t>()); }
670 void memorysearch::byte_ueq() throw() { search(search_eq<uint8_t>()); }
671 void memorysearch::byte_une() throw() { search(search_ne<uint8_t>()); }
672 void memorysearch::byte_uge() throw() { search(search_ge<uint8_t>()); }
673 void memorysearch::byte_ugt() throw() { search(search_gt<uint8_t>()); }
675 void memorysearch::word_value(uint16_t value) throw() { search(search_value<uint16_t>(value)); }
676 void memorysearch::word_slt() throw() { search(search_lt<int16_t>()); }
677 void memorysearch::word_sle() throw() { search(search_le<int16_t>()); }
678 void memorysearch::word_seq() throw() { search(search_eq<int16_t>()); }
679 void memorysearch::word_sne() throw() { search(search_ne<int16_t>()); }
680 void memorysearch::word_sge() throw() { search(search_ge<int16_t>()); }
681 void memorysearch::word_sgt() throw() { search(search_gt<int16_t>()); }
682 void memorysearch::word_ult() throw() { search(search_lt<uint16_t>()); }
683 void memorysearch::word_ule() throw() { search(search_le<uint16_t>()); }
684 void memorysearch::word_ueq() throw() { search(search_eq<uint16_t>()); }
685 void memorysearch::word_une() throw() { search(search_ne<uint16_t>()); }
686 void memorysearch::word_uge() throw() { search(search_ge<uint16_t>()); }
687 void memorysearch::word_ugt() throw() { search(search_gt<uint16_t>()); }
689 void memorysearch::dword_value(uint32_t value) throw() { search(search_value<uint32_t>(value)); }
690 void memorysearch::dword_slt() throw() { search(search_lt<int32_t>()); }
691 void memorysearch::dword_sle() throw() { search(search_le<int32_t>()); }
692 void memorysearch::dword_seq() throw() { search(search_eq<int32_t>()); }
693 void memorysearch::dword_sne() throw() { search(search_ne<int32_t>()); }
694 void memorysearch::dword_sge() throw() { search(search_ge<int32_t>()); }
695 void memorysearch::dword_sgt() throw() { search(search_gt<int32_t>()); }
696 void memorysearch::dword_ult() throw() { search(search_lt<uint32_t>()); }
697 void memorysearch::dword_ule() throw() { search(search_le<uint32_t>()); }
698 void memorysearch::dword_ueq() throw() { search(search_eq<uint32_t>()); }
699 void memorysearch::dword_une() throw() { search(search_ne<uint32_t>()); }
700 void memorysearch::dword_uge() throw() { search(search_ge<uint32_t>()); }
701 void memorysearch::dword_ugt() throw() { search(search_gt<uint32_t>()); }
703 void memorysearch::qword_value(uint64_t value) throw() { search(search_value<uint64_t>(value)); }
704 void memorysearch::qword_slt() throw() { search(search_lt<int64_t>()); }
705 void memorysearch::qword_sle() throw() { search(search_le<int64_t>()); }
706 void memorysearch::qword_seq() throw() { search(search_eq<int64_t>()); }
707 void memorysearch::qword_sne() throw() { search(search_ne<int64_t>()); }
708 void memorysearch::qword_sge() throw() { search(search_ge<int64_t>()); }
709 void memorysearch::qword_sgt() throw() { search(search_gt<int64_t>()); }
710 void memorysearch::qword_ult() throw() { search(search_lt<uint64_t>()); }
711 void memorysearch::qword_ule() throw() { search(search_le<uint64_t>()); }
712 void memorysearch::qword_ueq() throw() { search(search_eq<uint64_t>()); }
713 void memorysearch::qword_une() throw() { search(search_ne<uint64_t>()); }
714 void memorysearch::qword_uge() throw() { search(search_ge<uint64_t>()); }
715 void memorysearch::qword_ugt() throw() { search(search_gt<uint64_t>()); }
717 void memorysearch::update() throw() { search(search_update()); }
719 uint32_t memorysearch::get_candidate_count() throw()
721 return candidates;
724 std::list<uint32_t> memorysearch::get_candidates() throw(std::bad_alloc)
726 struct translated_address t = translate_address_linear_ram(0);
727 uint32_t switch_at = t.memory_size;
728 uint32_t base = 0;
729 uint32_t rbase = t.raw_addr;
730 uint32_t size = previous_content.size();
731 std::list<uint32_t> out;
733 for(uint32_t i = 0; i < size; i++) {
734 if(still_in[i / 64] == 0) {
735 i = (i + 64) >> 6 << 6;
736 i--;
737 continue;
739 while(i >= switch_at && t.memory_size > 0) {
740 t = translate_address_linear_ram(switch_at);
741 base = switch_at;
742 rbase = t.raw_addr - t.rel_addr;
743 switch_at += t.memory_size;
745 if((still_in[i / 64] >> (i % 64)) & 1)
746 out.push_back(i - base + rbase);
748 std::cout << "out=" << out.size() << " candidates=" << candidates << std::endl;
749 return out;
752 namespace
754 memorysearch* isrch;
756 std::string tokenize1(const std::string& command, const std::string& syntax);
757 std::pair<std::string, std::string> tokenize2(const std::string& command, const std::string& syntax);
758 std::pair<std::string, std::string> tokenize12(const std::string& command, const std::string& syntax);
760 unsigned char hex(char ch)
762 switch(ch) {
763 case '0': return 0;
764 case '1': return 1;
765 case '2': return 2;
766 case '3': return 3;
767 case '4': return 4;
768 case '5': return 5;
769 case '6': return 6;
770 case '7': return 7;
771 case '8': return 8;
772 case '9': return 9;
773 case 'a': case 'A': return 10;
774 case 'b': case 'B': return 11;
775 case 'c': case 'C': return 12;
776 case 'd': case 'D': return 13;
777 case 'e': case 'E': return 14;
778 case 'f': case 'F': return 15;
780 throw std::runtime_error("Bad hex character");
783 class memorymanip_command : public command
785 public:
786 memorymanip_command(const std::string& cmd) throw(std::bad_alloc)
787 : command(cmd)
789 _command = cmd;
791 ~memorymanip_command() throw() {}
792 void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error)
794 tokensplitter t(args);
795 firstword = static_cast<std::string>(t);
796 secondword = static_cast<std::string>(t);
797 has_tail = t;
798 address_bad = true;
799 value_bad = true;
800 has_value = (secondword != "");
801 try {
802 if(firstword.length() >= 2 && firstword.substr(0, 2) == "0x") {
803 if(firstword.length() > 10)
804 throw 42;
805 address = 0;
806 for(unsigned i = 2; i < firstword.length(); i++)
807 address = 16 * address + hex(firstword[i]);
808 } else {
809 address = parse_value<uint32_t>(firstword);
811 address_bad = false;
812 } catch(...) {
814 try {
815 if(secondword.length() >= 2 && secondword.substr(0, 2) == "0x") {
816 if(secondword.length() > 18)
817 throw 42;
818 value = 0;
819 for(unsigned i = 2; i < secondword.length(); i++)
820 value = 16 * value + hex(secondword[i]);
821 } else if(secondword.length() > 0 && secondword[0] == '-') {
822 value = static_cast<uint64_t>(parse_value<int64_t>(secondword));
823 } else {
824 value = parse_value<uint64_t>(secondword);
826 value_bad = false;
827 } catch(...) {
829 invoke2();
831 virtual void invoke2() throw(std::bad_alloc, std::runtime_error) = 0;
832 std::string firstword;
833 std::string secondword;
834 uint32_t address;
835 uint64_t value;
836 bool has_tail;
837 bool address_bad;
838 bool value_bad;
839 bool has_value;
840 std::string _command;
843 template<typename outer, typename inner, typename ret>
844 class read_command : public memorymanip_command
846 public:
847 read_command(const std::string& cmd, ret (*_rfn)(uint32_t addr)) throw(std::bad_alloc)
848 : memorymanip_command(cmd)
850 rfn = _rfn;
852 ~read_command() throw() {}
853 void invoke2() throw(std::bad_alloc, std::runtime_error)
855 if(address_bad || has_value || has_tail)
856 throw std::runtime_error("Syntax: " + _command + " <address>");
858 std::ostringstream x;
859 x << "0x" << std::hex << address << " -> " << std::dec
860 << static_cast<outer>(static_cast<inner>(rfn(address)));
861 messages << x.str() << std::endl;
864 std::string get_short_help() throw(std::bad_alloc) { return "Read memory"; }
865 std::string get_long_help() throw(std::bad_alloc)
867 return "Syntax: " + _command + " <address>\n"
868 "Reads data from memory.\n";
871 ret (*rfn)(uint32_t addr);
874 template<typename arg, int64_t low, uint64_t high>
875 class write_command : public memorymanip_command
877 public:
878 write_command(const std::string& cmd, bool (*_wfn)(uint32_t addr, arg a)) throw(std::bad_alloc)
879 : memorymanip_command(cmd)
881 wfn = _wfn;
883 ~write_command() throw() {}
884 void invoke2() throw(std::bad_alloc, std::runtime_error)
886 if(address_bad || value_bad || has_tail)
887 throw std::runtime_error("Syntax: " + _command + " <address> <value>");
888 if(static_cast<int64_t>(value) < low || value > high)
889 throw std::runtime_error("Value to write out of range");
890 wfn(address, value & high);
892 std::string get_short_help() throw(std::bad_alloc) { return "Write memory"; }
893 std::string get_long_help() throw(std::bad_alloc)
895 return "Syntax: " + _command + " <address> <value>\n"
896 "Writes data to memory.\n";
898 bool (*wfn)(uint32_t addr, arg a);
901 class memorysearch_command : public memorymanip_command
903 public:
904 memorysearch_command() throw(std::bad_alloc) : memorymanip_command("search-memory") {}
905 void invoke2() throw(std::bad_alloc, std::runtime_error)
907 if(!isrch)
908 isrch = new memorysearch();
909 if(firstword == "sblt" && !has_value)
910 isrch->byte_slt();
911 else if(firstword == "sble" && !has_value)
912 isrch->byte_sle();
913 else if(firstword == "sbeq" && !has_value)
914 isrch->byte_seq();
915 else if(firstword == "sbne" && !has_value)
916 isrch->byte_sne();
917 else if(firstword == "sbge" && !has_value)
918 isrch->byte_sge();
919 else if(firstword == "sbgt" && !has_value)
920 isrch->byte_sgt();
921 else if(firstword == "ublt" && !has_value)
922 isrch->byte_ult();
923 else if(firstword == "uble" && !has_value)
924 isrch->byte_ule();
925 else if(firstword == "ubeq" && !has_value)
926 isrch->byte_ueq();
927 else if(firstword == "ubne" && !has_value)
928 isrch->byte_une();
929 else if(firstword == "ubge" && !has_value)
930 isrch->byte_uge();
931 else if(firstword == "ubgt" && !has_value)
932 isrch->byte_ugt();
933 else if(firstword == "b" && has_value) {
934 if(static_cast<int64_t>(value) < -128 || value > 255)
935 throw std::runtime_error("Value to compare out of range");
936 isrch->byte_value(value & 0xFF);
937 } else if(firstword == "swlt" && !has_value)
938 isrch->word_slt();
939 else if(firstword == "swle" && !has_value)
940 isrch->word_sle();
941 else if(firstword == "sweq" && !has_value)
942 isrch->word_seq();
943 else if(firstword == "swne" && !has_value)
944 isrch->word_sne();
945 else if(firstword == "swge" && !has_value)
946 isrch->word_sge();
947 else if(firstword == "swgt" && !has_value)
948 isrch->word_sgt();
949 else if(firstword == "uwlt" && !has_value)
950 isrch->word_ult();
951 else if(firstword == "uwle" && !has_value)
952 isrch->word_ule();
953 else if(firstword == "uweq" && !has_value)
954 isrch->word_ueq();
955 else if(firstword == "uwne" && !has_value)
956 isrch->word_une();
957 else if(firstword == "uwge" && !has_value)
958 isrch->word_uge();
959 else if(firstword == "uwgt" && !has_value)
960 isrch->word_ugt();
961 else if(firstword == "w" && has_value) {
962 if(static_cast<int64_t>(value) < -32768 || value > 65535)
963 throw std::runtime_error("Value to compare out of range");
964 isrch->word_value(value & 0xFF);
965 } else if(firstword == "sdlt" && !has_value)
966 isrch->dword_slt();
967 else if(firstword == "sdle" && !has_value)
968 isrch->dword_sle();
969 else if(firstword == "sdeq" && !has_value)
970 isrch->dword_seq();
971 else if(firstword == "sdne" && !has_value)
972 isrch->dword_sne();
973 else if(firstword == "sdge" && !has_value)
974 isrch->dword_sge();
975 else if(firstword == "sdgt" && !has_value)
976 isrch->dword_sgt();
977 else if(firstword == "udlt" && !has_value)
978 isrch->dword_ult();
979 else if(firstword == "udle" && !has_value)
980 isrch->dword_ule();
981 else if(firstword == "udeq" && !has_value)
982 isrch->dword_ueq();
983 else if(firstword == "udne" && !has_value)
984 isrch->dword_une();
985 else if(firstword == "udge" && !has_value)
986 isrch->dword_uge();
987 else if(firstword == "udgt" && !has_value)
988 isrch->dword_ugt();
989 else if(firstword == "d" && has_value) {
990 if(static_cast<int64_t>(value) < -2147483648LL || value > 4294967295ULL)
991 throw std::runtime_error("Value to compare out of range");
992 isrch->dword_value(value & 0xFF);
993 } else if(firstword == "sqlt" && !has_value)
994 isrch->qword_slt();
995 else if(firstword == "sqle" && !has_value)
996 isrch->qword_sle();
997 else if(firstword == "sqeq" && !has_value)
998 isrch->qword_seq();
999 else if(firstword == "sqne" && !has_value)
1000 isrch->qword_sne();
1001 else if(firstword == "sqge" && !has_value)
1002 isrch->qword_sge();
1003 else if(firstword == "sqgt" && !has_value)
1004 isrch->qword_sgt();
1005 else if(firstword == "uqlt" && !has_value)
1006 isrch->qword_ult();
1007 else if(firstword == "uqle" && !has_value)
1008 isrch->qword_ule();
1009 else if(firstword == "uqeq" && !has_value)
1010 isrch->qword_ueq();
1011 else if(firstword == "uqne" && !has_value)
1012 isrch->qword_une();
1013 else if(firstword == "uqge" && !has_value)
1014 isrch->qword_uge();
1015 else if(firstword == "uqgt" && !has_value)
1016 isrch->qword_ugt();
1017 else if(firstword == "q" && has_value)
1018 isrch->qword_value(value & 0xFF);
1019 else if(firstword == "update" && !has_value)
1020 isrch->update();
1021 else if(firstword == "reset" && !has_value)
1022 isrch->reset();
1023 else if(firstword == "count" && !has_value)
1025 else if(firstword == "print" && !has_value) {
1026 auto c = isrch->get_candidates();
1027 for(auto ci : c) {
1028 std::ostringstream x;
1029 x << "0x" << std::hex << std::setw(8) << std::setfill('0') << ci;
1030 messages << x.str() << std::endl;
1032 } else
1033 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword + "'");
1034 messages << isrch->get_candidate_count() << " candidates remain." << std::endl;
1036 std::string get_short_help() throw(std::bad_alloc) { return "Search memory addresses"; }
1037 std::string get_long_help() throw(std::bad_alloc)
1039 return "Syntax: " + _command + " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
1040 "Syntax: " + _command + " {b,w,d,q} <value>\n"
1041 "Syntax: " + _command + " update\n"
1042 "Syntax: " + _command + " reset\n"
1043 "Syntax: " + _command + " count\n"
1044 "Syntax: " + _command + " print\n"
1045 "Searches addresses from memory.\n";
1047 } memorysearch_o;
1049 read_command<uint64_t, uint8_t, uint8_t> ru1("read-byte", memory_read_byte);
1050 read_command<uint64_t, uint16_t, uint16_t> ru2("read-word", memory_read_word);
1051 read_command<uint64_t, uint32_t, uint32_t> ru4("read-dword", memory_read_dword);
1052 read_command<uint64_t, uint64_t, uint64_t> ru8("read-qword", memory_read_qword);
1053 read_command<uint64_t, int8_t, uint8_t> rs1("read-sbyte", memory_read_byte);
1054 read_command<uint64_t, int16_t, uint16_t> rs2("read-sword", memory_read_word);
1055 read_command<uint64_t, int32_t, uint32_t> rs4("read-sdword", memory_read_dword);
1056 read_command<uint64_t, int64_t, uint64_t> rs8("read-sqword", memory_read_qword);
1057 write_command<uint8_t, -128, 0xFF> w1("write-byte", memory_write_byte);
1058 write_command<uint16_t, -32768, 0xFFFF> w2("write-word", memory_write_word);
1059 write_command<uint32_t, -2147483648LL, 0xFFFFFFFFULL> w4("write-dword", memory_write_dword);
1060 write_command<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL> w8("write-qword", memory_write_qword);