lsnes rr1-Δ10
[lsnes.git] / src / core / memorymanip.cpp
blob6a2c41112e14bd167ad125378fca1f9be5c36e5a
1 #include "core/bsnes.hpp"
2 #include <gameboy/gameboy.hpp>
4 #include "core/command.hpp"
5 #include "core/memorymanip.hpp"
6 #include "core/misc.hpp"
7 #include "core/rom.hpp"
8 #include "library/string.hpp"
10 #include <iostream>
11 #include <limits>
12 #include <sstream>
13 #include <iomanip>
14 #include <cstdint>
16 typedef uint8_t uint8;
17 typedef uint16_t uint16;
18 typedef uint32_t uint32;
19 typedef int8_t int8;
20 typedef int16_t int16;
21 typedef int32_t int32;
22 #include <nall/platform.hpp>
23 #include <nall/endian.hpp>
24 #include <nall/varint.hpp>
25 #include <nall/bit.hpp>
26 #include <nall/serializer.hpp>
27 #include <nall/property.hpp>
28 using namespace nall;
29 using namespace SNES;
32 namespace
34 struct translated_address
36 uint64_t rel_addr;
37 uint64_t raw_addr;
38 uint8_t* memory;
39 uint64_t memory_size;
40 bool not_writable;
41 bool native_endian;
42 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write);
45 struct region
47 std::string name;
48 uint64_t base;
49 uint64_t size;
50 uint8_t* memory;
51 bool not_writable;
52 bool native_endian;
53 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write);
56 std::vector<region> memory_regions;
57 uint64_t linear_ram_size = 0;
58 bool system_little_endian = true;
60 uint8_t snes_bus_iospace_rw(uint64_t offset, uint8_t data, bool write)
62 if(write)
63 SNES::bus.write(offset, data);
64 else
65 return SNES::bus.read(offset);
68 struct translated_address translate_address(uint64_t rawaddr) throw()
70 struct translated_address t;
71 t.rel_addr = 0;
72 t.raw_addr = 0;
73 t.memory = NULL;
74 t.memory_size = 0;
75 t.not_writable = true;
76 for(auto i : memory_regions) {
77 if(i.base > rawaddr || i.base + i.size <= rawaddr)
78 continue;
79 t.rel_addr = rawaddr - i.base;
80 t.raw_addr = rawaddr;
81 t.memory = i.memory;
82 t.memory_size = i.size;
83 t.not_writable = i.not_writable;
84 t.native_endian = i.native_endian;
85 t.iospace_rw = i.iospace_rw;
86 break;
88 return t;
91 struct translated_address translate_address_linear_ram(uint64_t ramlinaddr) throw()
93 struct translated_address t;
94 t.rel_addr = 0;
95 t.raw_addr = 0;
96 t.memory = NULL;
97 t.memory_size = 0;
98 t.not_writable = true;
99 for(auto i : memory_regions) {
100 if(i.not_writable || i.iospace_rw)
101 continue;
102 if(ramlinaddr >= i.size) {
103 ramlinaddr -= i.size;
104 continue;
106 t.rel_addr = ramlinaddr;
107 t.raw_addr = i.base + ramlinaddr;
108 t.memory = i.memory;
109 t.memory_size = i.size;
110 t.not_writable = i.not_writable;
111 t.native_endian = i.native_endian;
112 break;
114 return t;
117 uint64_t get_linear_ram_size() throw()
119 return linear_ram_size;
122 uint64_t create_region(const std::string& name, uint64_t base, uint64_t size,
123 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write)) throw(std::bad_alloc)
125 if(size == 0)
126 return base;
127 struct region r;
128 r.name = name;
129 r.base = base;
130 r.memory = NULL;
131 r.size = size;
132 r.not_writable = false;
133 r.native_endian = false;
134 r.iospace_rw = iospace_rw;
135 memory_regions.push_back(r);
136 return base + size;
139 uint64_t create_region(const std::string& name, uint64_t base, uint8_t* memory, uint64_t size, bool readonly,
140 bool native_endian = false) throw(std::bad_alloc)
142 if(size == 0)
143 return base;
144 struct region r;
145 r.name = name;
146 r.base = base;
147 r.memory = memory;
148 r.size = size;
149 r.not_writable = readonly;
150 r.native_endian = native_endian;
151 r.iospace_rw = NULL;
152 if(!readonly)
153 linear_ram_size += size;
154 memory_regions.push_back(r);
155 return base + size;
158 uint64_t create_region(const std::string& name, uint64_t base, SNES::MappedRAM& memory, bool readonly,
159 bool native_endian = false) throw(std::bad_alloc)
161 return create_region(name, base, memory.data(), memory.size(), readonly, native_endian);
164 uint8_t native_littleendian_convert(uint8_t x) throw()
166 return x;
169 uint16_t native_littleendian_convert(uint16_t x) throw()
171 if(!system_little_endian)
172 return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00));
173 else
174 return x;
177 uint32_t native_littleendian_convert(uint32_t x) throw()
179 if(!system_little_endian)
180 return (((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
181 ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000));
182 else
183 return x;
186 uint64_t native_littleendian_convert(uint64_t x) throw()
188 if(!system_little_endian)
189 return (((x >> 56) & 0xFF) | ((x >> 40) & 0xFF00) |
190 ((x >> 24) & 0xFF0000) | ((x >> 8) & 0xFF000000) |
191 ((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) |
192 ((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF00000000000000ULL));
193 else
194 return x;
197 template<typename T>
198 inline T memory_read_generic(uint64_t addr) throw()
200 struct translated_address laddr = translate_address(addr);
201 T value = 0;
202 if(laddr.iospace_rw) {
203 for(size_t i = 0; i < sizeof(T); i++)
204 if(laddr.rel_addr < laddr.memory_size)
205 value |= laddr.iospace_rw(laddr.rel_addr++, 0, false) << (8 * i);
206 } else {
207 for(size_t i = 0; i < sizeof(T); i++)
208 if(laddr.rel_addr < laddr.memory_size)
209 value |= laddr.memory[laddr.rel_addr++] << (8 * i);
211 if(laddr.native_endian)
212 value = native_littleendian_convert(value);
213 return value;
216 template<typename T>
217 inline bool memory_write_generic(uint64_t addr, T data) throw()
219 struct translated_address laddr = translate_address(addr);
220 if(laddr.native_endian)
221 data = native_littleendian_convert(data);
222 if(laddr.rel_addr >= laddr.memory_size - (sizeof(T) - 1) || laddr.not_writable)
223 return false;
224 if(laddr.iospace_rw) {
225 for(size_t i = 0; i < sizeof(T); i++)
226 laddr.iospace_rw(laddr.rel_addr++, static_cast<uint8_t>(data >> (8 * i)), true);
227 } else {
228 for(size_t i = 0; i < sizeof(T); i++)
229 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> (8 * i));
231 return true;
235 void refresh_cart_mappings() throw(std::bad_alloc)
237 linear_ram_size = 0;
238 memory_regions.clear();
239 if(get_current_rom_info().first == ROMTYPE_NONE)
240 return;
241 create_region("WRAM", 0x007E0000, SNES::cpu.wram, 131072, false);
242 create_region("APURAM", 0x00000000, SNES::smp.apuram, 65536, false);
243 create_region("VRAM", 0x00010000, SNES::ppu.vram, 65536, false);
244 create_region("OAM", 0x00020000, SNES::ppu.oam, 544, false);
245 create_region("CGRAM", 0x00021000, SNES::ppu.cgram, 512, false);
246 if(SNES::cartridge.has_srtc()) create_region("RTC", 0x00022000, SNES::srtc.rtc, 20, false);
247 if(SNES::cartridge.has_spc7110rtc()) create_region("RTC", 0x00022000, SNES::spc7110.rtc, 20, false);
248 if(SNES::cartridge.has_necdsp()) {
249 create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataRAM), 4096, false,
250 true);
251 create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp.programROM), 65536, true,
252 true);
253 create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataROM), 4096, true,
254 true);
256 create_region("SRAM", 0x10000000, SNES::cartridge.ram, false);
257 create_region("ROM", 0x80000000, SNES::cartridge.rom, true);
258 create_region("BUS", 0x1000000, 0x1000000, snes_bus_iospace_rw);
259 switch(get_current_rom_info().first) {
260 case ROMTYPE_BSX:
261 case ROMTYPE_BSXSLOTTED:
262 create_region("BSXFLASH", 0x90000000, SNES::bsxflash.memory, true);
263 create_region("BSX_RAM", 0x20000000, SNES::bsxcartridge.sram, false);
264 create_region("BSX_PRAM", 0x30000000, SNES::bsxcartridge.psram, false);
265 break;
266 case ROMTYPE_SUFAMITURBO:
267 create_region("SLOTA_ROM", 0x90000000, SNES::sufamiturbo.slotA.rom, true);
268 create_region("SLOTB_ROM", 0xA0000000, SNES::sufamiturbo.slotB.rom, true);
269 create_region("SLOTA_RAM", 0x20000000, SNES::sufamiturbo.slotA.ram, false);
270 create_region("SLOTB_RAM", 0x30000000, SNES::sufamiturbo.slotB.ram, false);
271 break;
272 case ROMTYPE_SGB:
273 create_region("GBROM", 0x90000000, GameBoy::cartridge.romdata, GameBoy::cartridge.romsize, true);
274 create_region("GBRAM", 0x20000000, GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize, false);
275 break;
276 case ROMTYPE_SNES:
277 case ROMTYPE_NONE:
278 break;
282 std::vector<struct memory_region> get_regions() throw(std::bad_alloc)
284 std::vector<struct memory_region> out;
285 for(auto i : memory_regions) {
286 struct memory_region r;
287 r.region_name = i.name;
288 r.baseaddr = i.base;
289 r.size = i.size;
290 r.lastaddr = i.base + i.size - 1;
291 r.readonly = i.not_writable;
292 r.iospace = (i.iospace_rw != NULL);
293 r.native_endian = i.native_endian;
294 out.push_back(r);
296 return out;
299 uint8_t memory_read_byte(uint64_t addr) throw()
301 return memory_read_generic<uint8_t>(addr);
304 uint16_t memory_read_word(uint64_t addr) throw()
306 return memory_read_generic<uint16_t>(addr);
309 uint32_t memory_read_dword(uint64_t addr) throw()
311 return memory_read_generic<uint32_t>(addr);
314 uint64_t memory_read_qword(uint64_t addr) throw()
316 return memory_read_generic<uint64_t>(addr);
319 //Byte write to address (false if failed).
320 bool memory_write_byte(uint64_t addr, uint8_t data) throw()
322 return memory_write_generic<uint8_t>(addr, data);
325 bool memory_write_word(uint64_t addr, uint16_t data) throw()
327 return memory_write_generic<uint16_t>(addr, data);
330 bool memory_write_dword(uint64_t addr, uint32_t data) throw()
332 return memory_write_generic<uint32_t>(addr, data);
335 bool memory_write_qword(uint64_t addr, uint64_t data) throw()
337 return memory_write_generic<uint64_t>(addr, data);
340 memorysearch::memorysearch() throw(std::bad_alloc)
342 reset();
345 void memorysearch::reset() throw(std::bad_alloc)
347 uint64_t linearram = get_linear_ram_size();
348 previous_content.resize(linearram);
349 still_in.resize((linearram + 63) / 64);
350 for(uint64_t i = 0; i < linearram / 64; i++)
351 still_in[i] = 0xFFFFFFFFFFFFFFFFULL;
352 if(linearram % 64)
353 still_in[linearram / 64] = (1ULL << (linearram % 64)) - 1;
354 uint64_t addr = 0;
355 while(addr < linearram) {
356 struct translated_address t = translate_address_linear_ram(addr);
357 memcpy(&previous_content[addr], t.memory, t.memory_size);
358 addr += t.memory_size;
360 candidates = linearram;
364 * \brief Native-value search function for trivial true function
366 struct search_update
369 * \brief The underlying numeric type
371 typedef uint8_t value_type;
374 * \brief Condition function.
375 * \param oldv The old value
376 * \param newv The new value
377 * \return True if new value satisfies condition, false otherwise.
379 bool operator()(uint8_t oldv, uint8_t newv) const throw()
381 return true;
386 * \brief Native-value search function for specific value
388 template<typename T>
389 struct search_value
392 * \brief The underlying numeric type
394 typedef T value_type;
397 * \brief Create new search object
399 * \param v The value to search for.
401 search_value(T v) throw()
403 val = v;
407 * \brief Condition function.
408 * \param oldv The old value
409 * \param newv The new value
410 * \return True if new value satisfies condition, false otherwise.
412 bool operator()(T oldv, T newv) const throw()
414 return (newv == val);
418 * \brief The value to look for
420 T val;
424 * \brief Native-value search function for less-than function.
426 template<typename T>
427 struct search_lt
430 * \brief The underlying numeric type
432 typedef T value_type;
435 * \brief Condition function.
436 * \param oldv The old value
437 * \param newv The new value
438 * \return True if new value satisfies condition, false otherwise.
440 bool operator()(T oldv, T newv) const throw()
442 return (newv < oldv);
447 * \brief Native-value search function for less-or-equal-to function.
449 template<typename T>
450 struct search_le
453 * \brief The underlying numeric type
455 typedef T value_type;
458 * \brief Condition function.
459 * \param oldv The old value
460 * \param newv The new value
461 * \return True if new value satisfies condition, false otherwise.
463 bool operator()(T oldv, T newv) const throw()
465 return (newv <= oldv);
470 * \brief Native-value search function for equals function.
472 template<typename T>
473 struct search_eq
476 * \brief The underlying numeric type
478 typedef T value_type;
481 * \brief Condition function.
482 * \param oldv The old value
483 * \param newv The new value
484 * \return True if new value satisfies condition, false otherwise.
486 bool operator()(T oldv, T newv) const throw()
488 return (newv == oldv);
493 * \brief Native-value search function for not-equal function.
495 template<typename T>
496 struct search_ne
499 * \brief The underlying numeric type
501 typedef T value_type;
504 * \brief Condition function.
505 * \param oldv The old value
506 * \param newv The new value
507 * \return True if new value satisfies condition, false otherwise.
509 bool operator()(T oldv, T newv) const throw()
511 return (newv != oldv);
516 * \brief Native-value search function for greater-or-equal-to function.
518 template<typename T>
519 struct search_ge
522 * \brief The underlying numeric type
524 typedef T value_type;
527 * \brief Condition function.
528 * \param oldv The old value
529 * \param newv The new value
530 * \return True if new value satisfies condition, false otherwise.
532 bool operator()(T oldv, T newv) const throw()
534 return (newv >= oldv);
539 * \brief Native-value search function for greater-than function.
541 template<typename T>
542 struct search_gt
545 * \brief The underlying numeric type
547 typedef T value_type;
550 * \brief Condition function.
551 * \param oldv The old value
552 * \param newv The new value
553 * \return True if new value satisfies condition, false otherwise.
555 bool operator()(T oldv, T newv) const throw()
557 return (newv > oldv);
562 * \brief Helper class to decode arguments to search functions
564 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
565 * expected for the search function.
567 template<typename T>
568 struct search_value_helper
571 * \brief The underlying numeric type
573 typedef typename T::value_type value_type;
576 * \brief Constructor constructing condition object
578 * This constructor takes in condition object with the native-value interface and makes condition object with
579 * interface used by search().
581 * \param v The condition object to wrap.
583 search_value_helper(const T& v) throw()
584 : val(v)
589 * \brief Condition function
591 * This function is search()-compatible condition function calling the underlying condition.
593 bool operator()(const uint8_t* newv, const uint8_t* oldv, uint64_t left, bool nativeendian) const throw()
595 if(left < sizeof(value_type))
596 return false;
597 value_type v1 = 0;
598 value_type v2 = 0;
599 if(nativeendian) {
600 v1 = *reinterpret_cast<const value_type*>(oldv);
601 v2 = *reinterpret_cast<const value_type*>(newv);
602 } else
603 for(size_t i = 0; i < sizeof(value_type); i++) {
604 v1 |= static_cast<value_type>(oldv[i]) << (8 * i);
605 v2 |= static_cast<value_type>(newv[i]) << (8 * i);
607 return val(v1, v2);
611 * \brief The underlying condition.
613 const T& val;
616 template<class T> void memorysearch::search(const T& obj) throw()
618 search_value_helper<T> helper(obj);
619 struct translated_address t = translate_address_linear_ram(0);
620 uint64_t switch_at = t.memory_size;
621 uint64_t base = 0;
622 uint64_t size = previous_content.size();
623 for(uint64_t i = 0; i < size; i++) {
624 if(still_in[i / 64] == 0) {
625 i = (i + 64) >> 6 << 6;
626 i--;
627 continue;
629 //t.memory_size == 0 can happen if cart changes.
630 while(i >= switch_at && t.memory_size > 0) {
631 t = translate_address_linear_ram(switch_at);
632 base = switch_at;
633 switch_at += t.memory_size;
635 if(t.memory_size == 0 || !helper(t.memory + i - base, &previous_content[i],
636 t.memory_size - (i - base), t.native_endian)) {
637 if((still_in[i / 64] >> (i % 64)) & 1) {
638 still_in[i / 64] &= ~(1ULL << (i % 64));
639 candidates--;
643 t = translate_address_linear_ram(0);
644 base = 0;
645 size = previous_content.size();
646 while(base < size) {
647 size_t m = t.memory_size;
648 if(m > (size - base))
649 m = size - base;
650 memcpy(&previous_content[base], t.memory, m);
651 base += t.memory_size;
652 t = translate_address_linear_ram(base);
656 void memorysearch::byte_value(uint8_t value) throw() { search(search_value<uint8_t>(value)); }
657 void memorysearch::byte_slt() throw() { search(search_lt<int8_t>()); }
658 void memorysearch::byte_sle() throw() { search(search_le<int8_t>()); }
659 void memorysearch::byte_seq() throw() { search(search_eq<int8_t>()); }
660 void memorysearch::byte_sne() throw() { search(search_ne<int8_t>()); }
661 void memorysearch::byte_sge() throw() { search(search_ge<int8_t>()); }
662 void memorysearch::byte_sgt() throw() { search(search_gt<int8_t>()); }
663 void memorysearch::byte_ult() throw() { search(search_lt<uint8_t>()); }
664 void memorysearch::byte_ule() throw() { search(search_le<uint8_t>()); }
665 void memorysearch::byte_ueq() throw() { search(search_eq<uint8_t>()); }
666 void memorysearch::byte_une() throw() { search(search_ne<uint8_t>()); }
667 void memorysearch::byte_uge() throw() { search(search_ge<uint8_t>()); }
668 void memorysearch::byte_ugt() throw() { search(search_gt<uint8_t>()); }
670 void memorysearch::word_value(uint16_t value) throw() { search(search_value<uint16_t>(value)); }
671 void memorysearch::word_slt() throw() { search(search_lt<int16_t>()); }
672 void memorysearch::word_sle() throw() { search(search_le<int16_t>()); }
673 void memorysearch::word_seq() throw() { search(search_eq<int16_t>()); }
674 void memorysearch::word_sne() throw() { search(search_ne<int16_t>()); }
675 void memorysearch::word_sge() throw() { search(search_ge<int16_t>()); }
676 void memorysearch::word_sgt() throw() { search(search_gt<int16_t>()); }
677 void memorysearch::word_ult() throw() { search(search_lt<uint16_t>()); }
678 void memorysearch::word_ule() throw() { search(search_le<uint16_t>()); }
679 void memorysearch::word_ueq() throw() { search(search_eq<uint16_t>()); }
680 void memorysearch::word_une() throw() { search(search_ne<uint16_t>()); }
681 void memorysearch::word_uge() throw() { search(search_ge<uint16_t>()); }
682 void memorysearch::word_ugt() throw() { search(search_gt<uint16_t>()); }
684 void memorysearch::dword_value(uint32_t value) throw() { search(search_value<uint32_t>(value)); }
685 void memorysearch::dword_slt() throw() { search(search_lt<int32_t>()); }
686 void memorysearch::dword_sle() throw() { search(search_le<int32_t>()); }
687 void memorysearch::dword_seq() throw() { search(search_eq<int32_t>()); }
688 void memorysearch::dword_sne() throw() { search(search_ne<int32_t>()); }
689 void memorysearch::dword_sge() throw() { search(search_ge<int32_t>()); }
690 void memorysearch::dword_sgt() throw() { search(search_gt<int32_t>()); }
691 void memorysearch::dword_ult() throw() { search(search_lt<uint32_t>()); }
692 void memorysearch::dword_ule() throw() { search(search_le<uint32_t>()); }
693 void memorysearch::dword_ueq() throw() { search(search_eq<uint32_t>()); }
694 void memorysearch::dword_une() throw() { search(search_ne<uint32_t>()); }
695 void memorysearch::dword_uge() throw() { search(search_ge<uint32_t>()); }
696 void memorysearch::dword_ugt() throw() { search(search_gt<uint32_t>()); }
698 void memorysearch::qword_value(uint64_t value) throw() { search(search_value<uint64_t>(value)); }
699 void memorysearch::qword_slt() throw() { search(search_lt<int64_t>()); }
700 void memorysearch::qword_sle() throw() { search(search_le<int64_t>()); }
701 void memorysearch::qword_seq() throw() { search(search_eq<int64_t>()); }
702 void memorysearch::qword_sne() throw() { search(search_ne<int64_t>()); }
703 void memorysearch::qword_sge() throw() { search(search_ge<int64_t>()); }
704 void memorysearch::qword_sgt() throw() { search(search_gt<int64_t>()); }
705 void memorysearch::qword_ult() throw() { search(search_lt<uint64_t>()); }
706 void memorysearch::qword_ule() throw() { search(search_le<uint64_t>()); }
707 void memorysearch::qword_ueq() throw() { search(search_eq<uint64_t>()); }
708 void memorysearch::qword_une() throw() { search(search_ne<uint64_t>()); }
709 void memorysearch::qword_uge() throw() { search(search_ge<uint64_t>()); }
710 void memorysearch::qword_ugt() throw() { search(search_gt<uint64_t>()); }
712 void memorysearch::update() throw() { search(search_update()); }
714 uint64_t memorysearch::get_candidate_count() throw()
716 return candidates;
719 std::list<uint64_t> memorysearch::get_candidates() throw(std::bad_alloc)
721 struct translated_address t = translate_address_linear_ram(0);
722 uint64_t switch_at = t.memory_size;
723 uint64_t base = 0;
724 uint64_t rbase = t.raw_addr;
725 uint64_t size = previous_content.size();
726 std::list<uint64_t> out;
728 for(uint64_t i = 0; i < size; i++) {
729 if(still_in[i / 64] == 0) {
730 i = (i + 64) >> 6 << 6;
731 i--;
732 continue;
734 while(i >= switch_at && t.memory_size > 0) {
735 t = translate_address_linear_ram(switch_at);
736 base = switch_at;
737 rbase = t.raw_addr - t.rel_addr;
738 switch_at += t.memory_size;
740 if((still_in[i / 64] >> (i % 64)) & 1)
741 out.push_back(i - base + rbase);
743 std::cout << "out=" << out.size() << " candidates=" << candidates << std::endl;
744 return out;
747 namespace
749 memorysearch* isrch;
751 std::string tokenize1(const std::string& command, const std::string& syntax);
752 std::pair<std::string, std::string> tokenize2(const std::string& command, const std::string& syntax);
753 std::pair<std::string, std::string> tokenize12(const std::string& command, const std::string& syntax);
755 unsigned char hex(char ch)
757 switch(ch) {
758 case '0': return 0;
759 case '1': return 1;
760 case '2': return 2;
761 case '3': return 3;
762 case '4': return 4;
763 case '5': return 5;
764 case '6': return 6;
765 case '7': return 7;
766 case '8': return 8;
767 case '9': return 9;
768 case 'a': case 'A': return 10;
769 case 'b': case 'B': return 11;
770 case 'c': case 'C': return 12;
771 case 'd': case 'D': return 13;
772 case 'e': case 'E': return 14;
773 case 'f': case 'F': return 15;
775 throw std::runtime_error("Bad hex character");
778 class memorymanip_command : public command
780 public:
781 memorymanip_command(const std::string& cmd) throw(std::bad_alloc)
782 : command(cmd)
784 _command = cmd;
786 ~memorymanip_command() throw() {}
787 void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error)
789 regex_results t = regex("(([^ \t]+)([ \t]+([^ \t]+)([ \t]+([^ \t].*)?)?)?)?", args);
790 firstword = t[2];
791 secondword = t[4];
792 has_tail = (t[6] != "");
793 address_bad = true;
794 value_bad = true;
795 has_value = (secondword != "");
796 try {
797 if(t = regex("0x(.+)", firstword)) {
798 if(t[1].length() > 8)
799 throw 42;
800 address = 0;
801 for(unsigned i = 0; i < t[1].length(); i++)
802 address = 16 * address + hex(t[1][i]);
803 } else {
804 address = parse_value<uint64_t>(firstword);
806 address_bad = false;
807 } catch(...) {
809 try {
810 if(t = regex("0x(.+)", secondword)) {
811 if(t[1].length() > 16)
812 throw 42;
813 value = 0;
814 for(unsigned i = 0; i < t[1].length(); i++)
815 value = 16 * value + hex(t[1][i]);
816 } else if(regex("-.*", secondword)) {
817 value = static_cast<uint64_t>(parse_value<int64_t>(secondword));
818 } else {
819 value = parse_value<uint64_t>(secondword);
821 value_bad = false;
822 } catch(...) {
824 invoke2();
826 virtual void invoke2() throw(std::bad_alloc, std::runtime_error) = 0;
827 std::string firstword;
828 std::string secondword;
829 uint64_t address;
830 uint64_t value;
831 bool has_tail;
832 bool address_bad;
833 bool value_bad;
834 bool has_value;
835 std::string _command;
838 template<typename outer, typename inner, typename ret>
839 class read_command : public memorymanip_command
841 public:
842 read_command(const std::string& cmd, ret (*_rfn)(uint64_t addr)) throw(std::bad_alloc)
843 : memorymanip_command(cmd)
845 rfn = _rfn;
847 ~read_command() throw() {}
848 void invoke2() throw(std::bad_alloc, std::runtime_error)
850 if(address_bad || has_value || has_tail)
851 throw std::runtime_error("Syntax: " + _command + " <address>");
853 std::ostringstream x;
854 x << "0x" << std::hex << address << " -> " << std::dec
855 << static_cast<outer>(static_cast<inner>(rfn(address)));
856 messages << x.str() << std::endl;
859 std::string get_short_help() throw(std::bad_alloc) { return "Read memory"; }
860 std::string get_long_help() throw(std::bad_alloc)
862 return "Syntax: " + _command + " <address>\n"
863 "Reads data from memory.\n";
866 ret (*rfn)(uint64_t addr);
869 template<typename arg, int64_t low, uint64_t high>
870 class write_command : public memorymanip_command
872 public:
873 write_command(const std::string& cmd, bool (*_wfn)(uint64_t addr, arg a)) throw(std::bad_alloc)
874 : memorymanip_command(cmd)
876 wfn = _wfn;
878 ~write_command() throw() {}
879 void invoke2() throw(std::bad_alloc, std::runtime_error)
881 if(address_bad || value_bad || has_tail)
882 throw std::runtime_error("Syntax: " + _command + " <address> <value>");
883 int64_t value2 = static_cast<int64_t>(value);
884 if(value2 < low || (value > high && value2 >= 0))
885 throw std::runtime_error("Value to write out of range");
886 wfn(address, value & high);
888 std::string get_short_help() throw(std::bad_alloc) { return "Write memory"; }
889 std::string get_long_help() throw(std::bad_alloc)
891 return "Syntax: " + _command + " <address> <value>\n"
892 "Writes data to memory.\n";
894 bool (*wfn)(uint64_t addr, arg a);
897 class memorysearch_command : public memorymanip_command
899 public:
900 memorysearch_command() throw(std::bad_alloc) : memorymanip_command("search-memory") {}
901 void invoke2() throw(std::bad_alloc, std::runtime_error)
903 if(!isrch)
904 isrch = new memorysearch();
905 if(firstword == "sblt" && !has_value)
906 isrch->byte_slt();
907 else if(firstword == "sble" && !has_value)
908 isrch->byte_sle();
909 else if(firstword == "sbeq" && !has_value)
910 isrch->byte_seq();
911 else if(firstword == "sbne" && !has_value)
912 isrch->byte_sne();
913 else if(firstword == "sbge" && !has_value)
914 isrch->byte_sge();
915 else if(firstword == "sbgt" && !has_value)
916 isrch->byte_sgt();
917 else if(firstword == "ublt" && !has_value)
918 isrch->byte_ult();
919 else if(firstword == "uble" && !has_value)
920 isrch->byte_ule();
921 else if(firstword == "ubeq" && !has_value)
922 isrch->byte_ueq();
923 else if(firstword == "ubne" && !has_value)
924 isrch->byte_une();
925 else if(firstword == "ubge" && !has_value)
926 isrch->byte_uge();
927 else if(firstword == "ubgt" && !has_value)
928 isrch->byte_ugt();
929 else if(firstword == "b" && has_value) {
930 if(static_cast<int64_t>(value) < -128 || value > 255)
931 throw std::runtime_error("Value to compare out of range");
932 isrch->byte_value(value & 0xFF);
933 } else if(firstword == "swlt" && !has_value)
934 isrch->word_slt();
935 else if(firstword == "swle" && !has_value)
936 isrch->word_sle();
937 else if(firstword == "sweq" && !has_value)
938 isrch->word_seq();
939 else if(firstword == "swne" && !has_value)
940 isrch->word_sne();
941 else if(firstword == "swge" && !has_value)
942 isrch->word_sge();
943 else if(firstword == "swgt" && !has_value)
944 isrch->word_sgt();
945 else if(firstword == "uwlt" && !has_value)
946 isrch->word_ult();
947 else if(firstword == "uwle" && !has_value)
948 isrch->word_ule();
949 else if(firstword == "uweq" && !has_value)
950 isrch->word_ueq();
951 else if(firstword == "uwne" && !has_value)
952 isrch->word_une();
953 else if(firstword == "uwge" && !has_value)
954 isrch->word_uge();
955 else if(firstword == "uwgt" && !has_value)
956 isrch->word_ugt();
957 else if(firstword == "w" && has_value) {
958 if(static_cast<int64_t>(value) < -32768 || value > 65535)
959 throw std::runtime_error("Value to compare out of range");
960 isrch->word_value(value & 0xFFFF);
961 } else if(firstword == "sdlt" && !has_value)
962 isrch->dword_slt();
963 else if(firstword == "sdle" && !has_value)
964 isrch->dword_sle();
965 else if(firstword == "sdeq" && !has_value)
966 isrch->dword_seq();
967 else if(firstword == "sdne" && !has_value)
968 isrch->dword_sne();
969 else if(firstword == "sdge" && !has_value)
970 isrch->dword_sge();
971 else if(firstword == "sdgt" && !has_value)
972 isrch->dword_sgt();
973 else if(firstword == "udlt" && !has_value)
974 isrch->dword_ult();
975 else if(firstword == "udle" && !has_value)
976 isrch->dword_ule();
977 else if(firstword == "udeq" && !has_value)
978 isrch->dword_ueq();
979 else if(firstword == "udne" && !has_value)
980 isrch->dword_une();
981 else if(firstword == "udge" && !has_value)
982 isrch->dword_uge();
983 else if(firstword == "udgt" && !has_value)
984 isrch->dword_ugt();
985 else if(firstword == "d" && has_value) {
986 if(static_cast<int64_t>(value) < -2147483648LL || value > 4294967295ULL)
987 throw std::runtime_error("Value to compare out of range");
988 isrch->dword_value(value & 0xFFFFFFFFULL);
989 } else if(firstword == "sqlt" && !has_value)
990 isrch->qword_slt();
991 else if(firstword == "sqle" && !has_value)
992 isrch->qword_sle();
993 else if(firstword == "sqeq" && !has_value)
994 isrch->qword_seq();
995 else if(firstword == "sqne" && !has_value)
996 isrch->qword_sne();
997 else if(firstword == "sqge" && !has_value)
998 isrch->qword_sge();
999 else if(firstword == "sqgt" && !has_value)
1000 isrch->qword_sgt();
1001 else if(firstword == "uqlt" && !has_value)
1002 isrch->qword_ult();
1003 else if(firstword == "uqle" && !has_value)
1004 isrch->qword_ule();
1005 else if(firstword == "uqeq" && !has_value)
1006 isrch->qword_ueq();
1007 else if(firstword == "uqne" && !has_value)
1008 isrch->qword_une();
1009 else if(firstword == "uqge" && !has_value)
1010 isrch->qword_uge();
1011 else if(firstword == "uqgt" && !has_value)
1012 isrch->qword_ugt();
1013 else if(firstword == "q" && has_value)
1014 isrch->qword_value(value);
1015 else if(firstword == "update" && !has_value)
1016 isrch->update();
1017 else if(firstword == "reset" && !has_value)
1018 isrch->reset();
1019 else if(firstword == "count" && !has_value)
1021 else if(firstword == "print" && !has_value) {
1022 auto c = isrch->get_candidates();
1023 for(auto ci : c) {
1024 std::ostringstream x;
1025 x << "0x" << std::hex << std::setw(8) << std::setfill('0') << ci;
1026 messages << x.str() << std::endl;
1028 } else
1029 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword + "'");
1030 messages << isrch->get_candidate_count() << " candidates remain." << std::endl;
1032 std::string get_short_help() throw(std::bad_alloc) { return "Search memory addresses"; }
1033 std::string get_long_help() throw(std::bad_alloc)
1035 return "Syntax: " + _command + " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
1036 "Syntax: " + _command + " {b,w,d,q} <value>\n"
1037 "Syntax: " + _command + " update\n"
1038 "Syntax: " + _command + " reset\n"
1039 "Syntax: " + _command + " count\n"
1040 "Syntax: " + _command + " print\n"
1041 "Searches addresses from memory.\n";
1043 } memorysearch_o;
1045 read_command<uint64_t, uint8_t, uint8_t> ru1("read-byte", memory_read_byte);
1046 read_command<uint64_t, uint16_t, uint16_t> ru2("read-word", memory_read_word);
1047 read_command<uint64_t, uint32_t, uint32_t> ru4("read-dword", memory_read_dword);
1048 read_command<uint64_t, uint64_t, uint64_t> ru8("read-qword", memory_read_qword);
1049 read_command<uint64_t, int8_t, uint8_t> rs1("read-sbyte", memory_read_byte);
1050 read_command<uint64_t, int16_t, uint16_t> rs2("read-sword", memory_read_word);
1051 read_command<uint64_t, int32_t, uint32_t> rs4("read-sdword", memory_read_dword);
1052 read_command<uint64_t, int64_t, uint64_t> rs8("read-sqword", memory_read_qword);
1053 write_command<uint8_t, -128, 0xFF> w1("write-byte", memory_write_byte);
1054 write_command<uint16_t, -32768, 0xFFFF> w2("write-word", memory_write_word);
1055 write_command<uint32_t, -2147483648LL, 0xFFFFFFFFULL> w4("write-dword", memory_write_dword);
1056 write_command<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL> w8("write-qword", memory_write_qword);