Memory commands: Memory addresses are up to 16 hex digits, not up to 8
[lsnes.git] / src / core / memorymanip.cpp
blob8072d96a52e343a07413c377b305286855419e38
1 #include "core/emucore.hpp"
3 #include "core/command.hpp"
4 #include "core/memorymanip.hpp"
5 #include "core/moviedata.hpp"
6 #include "core/misc.hpp"
7 #include "core/rom.hpp"
8 #include "core/rrdata.hpp"
9 #include "library/string.hpp"
10 #include "library/minmax.hpp"
12 #include <iostream>
13 #include <limits>
14 #include <sstream>
15 #include <iomanip>
16 #include <cstdint>
17 #include <cstring>
19 namespace
21 struct translated_address
23 uint64_t rel_addr;
24 uint64_t raw_addr;
25 uint8_t* memory;
26 uint64_t memory_size;
27 bool not_writable;
28 bool native_endian;
29 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write);
32 struct region
34 std::string name;
35 uint64_t base;
36 uint64_t size;
37 uint8_t* memory;
38 bool not_writable;
39 bool native_endian;
40 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write);
43 std::vector<region> memory_regions;
44 uint64_t linear_ram_size = 0;
45 bool system_little_endian = true;
47 uint8_t lsnes_mmio_iospace_handler(uint64_t offset, uint8_t data, bool write)
49 if(offset >= 0 && offset < 8 && !write) {
50 //Frame counter.
51 uint64_t x = get_movie().get_current_frame();
52 return x >> (8 * (offset & 7));
53 } else if(offset >= 8 && offset < 16 && !write) {
54 //Movie length.
55 uint64_t x = get_movie().get_frame_count();
56 return x >> (8 * (offset & 7));
57 } else if(offset >= 16 && offset < 24 && !write) {
58 //Lag counter.
59 uint64_t x = get_movie().get_lag_frames();
60 return x >> (8 * (offset & 7));
61 } else if(offset >= 24 && offset < 32 && !write) {
62 //Rerecord counter.
63 uint64_t x = rrdata::count();
64 return x >> (8 * (offset & 7));
65 } else
66 return 0;
69 struct translated_address translate_address(uint64_t rawaddr) throw()
71 struct translated_address t;
72 t.rel_addr = 0;
73 t.raw_addr = 0;
74 t.memory = NULL;
75 t.memory_size = 0;
76 t.not_writable = true;
77 if((rawaddr >> 32) == 0xFFFFFFFFULL) {
78 //lsnes MMIO.
79 t.rel_addr = rawaddr & 0xFFFFFFFFULL;
80 t.raw_addr = rawaddr;
81 t.memory = NULL;
82 t.memory_size = 0x100000000ULL;
83 t.not_writable = false;
84 t.native_endian = false;
85 t.iospace_rw = lsnes_mmio_iospace_handler;
86 return t;
88 for(auto i : memory_regions) {
89 if(i.base > rawaddr || i.base + i.size <= rawaddr)
90 continue;
91 t.rel_addr = rawaddr - i.base;
92 t.raw_addr = rawaddr;
93 t.memory = i.memory;
94 t.memory_size = i.size;
95 t.not_writable = i.not_writable;
96 t.native_endian = i.native_endian;
97 t.iospace_rw = i.iospace_rw;
98 break;
100 return t;
103 struct translated_address translate_address_linear_ram(uint64_t ramlinaddr) throw()
105 struct translated_address t;
106 t.rel_addr = 0;
107 t.raw_addr = 0;
108 t.memory = NULL;
109 t.memory_size = 0;
110 t.not_writable = true;
111 for(auto i : memory_regions) {
112 if(i.not_writable || i.iospace_rw)
113 continue;
114 if(ramlinaddr >= i.size) {
115 ramlinaddr -= i.size;
116 continue;
118 t.rel_addr = ramlinaddr;
119 t.raw_addr = i.base + ramlinaddr;
120 t.memory = i.memory;
121 t.memory_size = i.size;
122 t.not_writable = i.not_writable;
123 t.native_endian = i.native_endian;
124 break;
126 return t;
129 uint64_t get_linear_ram_size() throw()
131 return linear_ram_size;
134 uint64_t create_region(const std::string& name, uint64_t base, uint64_t size,
135 uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write)) throw(std::bad_alloc)
137 if(size == 0)
138 return base;
139 struct region r;
140 r.name = name;
141 r.base = base;
142 r.memory = NULL;
143 r.size = size;
144 r.not_writable = false;
145 r.native_endian = false;
146 r.iospace_rw = iospace_rw;
147 memory_regions.push_back(r);
148 return base + size;
151 uint64_t create_region(const std::string& name, uint64_t base, uint8_t* memory, uint64_t size, bool readonly,
152 bool native_endian = false) throw(std::bad_alloc)
154 if(size == 0)
155 return base;
156 struct region r;
157 r.name = name;
158 r.base = base;
159 r.memory = memory;
160 r.size = size;
161 r.not_writable = readonly;
162 r.native_endian = native_endian;
163 r.iospace_rw = NULL;
164 if(!readonly)
165 linear_ram_size += size;
166 memory_regions.push_back(r);
167 return base + size;
170 uint8_t native_littleendian_convert(uint8_t x) throw()
172 return x;
175 uint16_t native_littleendian_convert(uint16_t x) throw()
177 if(!system_little_endian)
178 return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00));
179 else
180 return x;
183 uint32_t native_littleendian_convert(uint32_t x) throw()
185 if(!system_little_endian)
186 return (((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
187 ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000));
188 else
189 return x;
192 uint64_t native_littleendian_convert(uint64_t x) throw()
194 if(!system_little_endian)
195 return (((x >> 56) & 0xFF) | ((x >> 40) & 0xFF00) |
196 ((x >> 24) & 0xFF0000) | ((x >> 8) & 0xFF000000) |
197 ((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) |
198 ((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF00000000000000ULL));
199 else
200 return x;
203 template<typename T>
204 inline T memory_read_generic(uint64_t addr) throw()
206 struct translated_address laddr = translate_address(addr);
207 T value = 0;
208 if(laddr.iospace_rw) {
209 for(size_t i = 0; i < sizeof(T); i++)
210 if(laddr.rel_addr < laddr.memory_size)
211 value |= laddr.iospace_rw(laddr.rel_addr++, 0, false) << (8 * i);
212 } else {
213 for(size_t i = 0; i < sizeof(T); i++)
214 if(laddr.rel_addr < laddr.memory_size)
215 value |= laddr.memory[laddr.rel_addr++] << (8 * i);
217 if(laddr.native_endian)
218 value = native_littleendian_convert(value);
219 return value;
222 template<typename T>
223 inline bool memory_write_generic(uint64_t addr, T data) throw()
225 struct translated_address laddr = translate_address(addr);
226 if(laddr.native_endian)
227 data = native_littleendian_convert(data);
228 if(laddr.rel_addr >= laddr.memory_size - (sizeof(T) - 1) || laddr.not_writable)
229 return false;
230 if(laddr.iospace_rw) {
231 for(size_t i = 0; i < sizeof(T); i++)
232 laddr.iospace_rw(laddr.rel_addr++, static_cast<uint8_t>(data >> (8 * i)), true);
233 } else {
234 for(size_t i = 0; i < sizeof(T); i++)
235 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> (8 * i));
237 return true;
241 void refresh_cart_mappings() throw(std::bad_alloc)
243 linear_ram_size = 0;
244 memory_regions.clear();
245 if(!get_current_rom_info().first)
246 return;
247 auto vmalist = get_vma_list();
248 for(auto i : vmalist) {
249 if(i.iospace_rw)
250 create_region(i.name, i.base, i.size, i.iospace_rw);
251 else
252 create_region(i.name, i.base, reinterpret_cast<uint8_t*>(i.backing_ram), i.size, i.readonly,
253 i.native_endian);
257 std::vector<struct memory_region> get_regions() throw(std::bad_alloc)
259 std::vector<struct memory_region> out;
260 for(auto i : memory_regions) {
261 struct memory_region r;
262 r.region_name = i.name;
263 r.baseaddr = i.base;
264 r.size = i.size;
265 r.lastaddr = i.base + i.size - 1;
266 r.readonly = i.not_writable;
267 r.iospace = (i.iospace_rw != NULL);
268 r.native_endian = i.native_endian;
269 out.push_back(r);
271 return out;
274 uint8_t memory_read_byte(uint64_t addr) throw()
276 return memory_read_generic<uint8_t>(addr);
279 void memory_read_bytes(uint64_t addr, uint64_t size, char* buffer) throw()
281 struct translated_address laddr = translate_address(addr);
282 size_t ssize = min(static_cast<uint64_t>(size), laddr.memory_size - laddr.rel_addr);
283 if(ssize > 0) {
284 if(laddr.iospace_rw) {
285 for(size_t i = 0; i < ssize; i++)
286 buffer[i] = laddr.iospace_rw(laddr.rel_addr++, 0, false);
287 } else
288 memcpy(buffer, laddr.memory + laddr.rel_addr, ssize);
290 memset(buffer + ssize, 0, size - ssize);
293 uint16_t memory_read_word(uint64_t addr) throw()
295 return memory_read_generic<uint16_t>(addr);
298 uint32_t memory_read_dword(uint64_t addr) throw()
300 return memory_read_generic<uint32_t>(addr);
303 uint64_t memory_read_qword(uint64_t addr) throw()
305 return memory_read_generic<uint64_t>(addr);
308 //Byte write to address (false if failed).
309 bool memory_write_byte(uint64_t addr, uint8_t data) throw()
311 return memory_write_generic<uint8_t>(addr, data);
314 void memory_write_bytes(uint64_t addr, uint64_t size, const char* buffer) throw()
316 struct translated_address laddr = translate_address(addr);
317 if(laddr.not_writable)
318 return;
319 size_t ssize = min(static_cast<uint64_t>(size), laddr.memory_size - laddr.rel_addr);
320 if(ssize > 0) {
321 if(laddr.iospace_rw) {
322 for(size_t i = 0; i < ssize; i++)
323 laddr.iospace_rw(laddr.rel_addr++, buffer[i], true);
324 } else
325 memcpy(laddr.memory + laddr.rel_addr, buffer, ssize);
329 bool memory_write_word(uint64_t addr, uint16_t data) throw()
331 return memory_write_generic<uint16_t>(addr, data);
334 bool memory_write_dword(uint64_t addr, uint32_t data) throw()
336 return memory_write_generic<uint32_t>(addr, data);
339 bool memory_write_qword(uint64_t addr, uint64_t data) throw()
341 return memory_write_generic<uint64_t>(addr, data);
344 memorysearch::memorysearch() throw(std::bad_alloc)
346 reset();
349 void memorysearch::reset() throw(std::bad_alloc)
351 uint64_t linearram = get_linear_ram_size();
352 previous_content.resize(linearram);
353 still_in.resize((linearram + 63) / 64);
354 for(uint64_t i = 0; i < linearram / 64; i++)
355 still_in[i] = 0xFFFFFFFFFFFFFFFFULL;
356 if(linearram % 64)
357 still_in[linearram / 64] = (1ULL << (linearram % 64)) - 1;
358 uint64_t addr = 0;
359 while(addr < linearram) {
360 struct translated_address t = translate_address_linear_ram(addr);
361 memcpy(&previous_content[addr], t.memory, t.memory_size);
362 addr += t.memory_size;
364 candidates = linearram;
368 * \brief Native-value search function for trivial true function
370 struct search_update
373 * \brief The underlying numeric type
375 typedef uint8_t value_type;
378 * \brief Condition function.
379 * \param oldv The old value
380 * \param newv The new value
381 * \return True if new value satisfies condition, false otherwise.
383 bool operator()(uint8_t oldv, uint8_t newv) const throw()
385 return true;
390 * \brief Native-value search function for specific value
392 template<typename T>
393 struct search_value
396 * \brief The underlying numeric type
398 typedef T value_type;
401 * \brief Create new search object
403 * \param v The value to search for.
405 search_value(T v) throw()
407 val = v;
411 * \brief Condition function.
412 * \param oldv The old value
413 * \param newv The new value
414 * \return True if new value satisfies condition, false otherwise.
416 bool operator()(T oldv, T newv) const throw()
418 return (newv == val);
422 * \brief The value to look for
424 T val;
428 * \brief Native-value search function for specific difference
430 template<typename T>
431 struct search_difference
434 * \brief The underlying numeric type
436 typedef T value_type;
439 * \brief Create new search object
441 * \param v The value to search for.
443 search_difference(T v) throw()
445 val = v;
449 * \brief Condition function.
450 * \param oldv The old value
451 * \param newv The new value
452 * \return True if new value satisfies condition, false otherwise.
454 bool operator()(T oldv, T newv) const throw()
456 return ((newv - oldv) == val);
460 * \brief The value to look for
462 T val;
466 * \brief Native-value search function for less-than function.
468 template<typename T>
469 struct search_lt
472 * \brief The underlying numeric type
474 typedef T value_type;
477 * \brief Condition function.
478 * \param oldv The old value
479 * \param newv The new value
480 * \return True if new value satisfies condition, false otherwise.
482 bool operator()(T oldv, T newv) const throw()
484 return (newv < oldv);
489 * \brief Native-value search function for less-or-equal-to function.
491 template<typename T>
492 struct search_le
495 * \brief The underlying numeric type
497 typedef T value_type;
500 * \brief Condition function.
501 * \param oldv The old value
502 * \param newv The new value
503 * \return True if new value satisfies condition, false otherwise.
505 bool operator()(T oldv, T newv) const throw()
507 return (newv <= oldv);
512 * \brief Native-value search function for equals function.
514 template<typename T>
515 struct search_eq
518 * \brief The underlying numeric type
520 typedef T value_type;
523 * \brief Condition function.
524 * \param oldv The old value
525 * \param newv The new value
526 * \return True if new value satisfies condition, false otherwise.
528 bool operator()(T oldv, T newv) const throw()
530 return (newv == oldv);
535 * \brief Native-value search function for not-equal function.
537 template<typename T>
538 struct search_ne
541 * \brief The underlying numeric type
543 typedef T value_type;
546 * \brief Condition function.
547 * \param oldv The old value
548 * \param newv The new value
549 * \return True if new value satisfies condition, false otherwise.
551 bool operator()(T oldv, T newv) const throw()
553 return (newv != oldv);
558 * \brief Native-value search function for greater-or-equal-to function.
560 template<typename T>
561 struct search_ge
564 * \brief The underlying numeric type
566 typedef T value_type;
569 * \brief Condition function.
570 * \param oldv The old value
571 * \param newv The new value
572 * \return True if new value satisfies condition, false otherwise.
574 bool operator()(T oldv, T newv) const throw()
576 return (newv >= oldv);
581 * \brief Native-value search function for greater-than function.
583 template<typename T>
584 struct search_gt
587 * \brief The underlying numeric type
589 typedef T value_type;
592 * \brief Condition function.
593 * \param oldv The old value
594 * \param newv The new value
595 * \return True if new value satisfies condition, false otherwise.
597 bool operator()(T oldv, T newv) const throw()
599 return (newv > oldv);
604 * \brief Native-value search function for sequence less-than function.
606 template<typename T>
607 struct search_seqlt
610 * \brief The underlying numeric type
612 typedef T value_type;
615 * \brief Condition function.
616 * \param oldv The old value
617 * \param newv The new value
618 * \return True if new value satisfies condition, false otherwise.
620 bool operator()(T oldv, T newv) const throw()
622 T mask = (T)1 << (sizeof(T) * 8 - 1);
623 T diff = newv - oldv;
624 return ((diff & mask) != 0);
629 * \brief Native-value search function for sequence less-or-equal function.
631 template<typename T>
632 struct search_seqle
635 * \brief The underlying numeric type
637 typedef T value_type;
640 * \brief Condition function.
641 * \param oldv The old value
642 * \param newv The new value
643 * \return True if new value satisfies condition, false otherwise.
645 bool operator()(T oldv, T newv) const throw()
647 T mask = (T)1 << (sizeof(T) * 8 - 1);
648 T diff = newv - oldv;
649 return ((diff & mask) != 0) || (diff == 0);
654 * \brief Native-value search function for sequence greater-or-equal function.
656 template<typename T>
657 struct search_seqge
660 * \brief The underlying numeric type
662 typedef T value_type;
665 * \brief Condition function.
666 * \param oldv The old value
667 * \param newv The new value
668 * \return True if new value satisfies condition, false otherwise.
670 bool operator()(T oldv, T newv) const throw()
672 T mask = (T)1 << (sizeof(T) * 8 - 1);
673 T diff = newv - oldv;
674 return ((diff & mask) == 0);
679 * \brief Native-value search function for sequence greater-than function.
681 template<typename T>
682 struct search_seqgt
685 * \brief The underlying numeric type
687 typedef T value_type;
690 * \brief Condition function.
691 * \param oldv The old value
692 * \param newv The new value
693 * \return True if new value satisfies condition, false otherwise.
695 bool operator()(T oldv, T newv) const throw()
697 T mask = (T)1 << (sizeof(T) * 8 - 1);
698 T diff = newv - oldv;
699 return ((diff & mask) == 0) && (diff != 0);
705 * \brief Helper class to decode arguments to search functions
707 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
708 * expected for the search function.
710 template<typename T>
711 struct search_value_helper
714 * \brief The underlying numeric type
716 typedef typename T::value_type value_type;
719 * \brief Constructor constructing condition object
721 * This constructor takes in condition object with the native-value interface and makes condition object with
722 * interface used by search().
724 * \param v The condition object to wrap.
726 search_value_helper(const T& v) throw()
727 : val(v)
732 * \brief Condition function
734 * This function is search()-compatible condition function calling the underlying condition.
736 bool operator()(const uint8_t* newv, const uint8_t* oldv, uint64_t left, bool nativeendian) const throw()
738 if(left < sizeof(value_type))
739 return false;
740 value_type v1 = 0;
741 value_type v2 = 0;
742 if(nativeendian) {
743 v1 = *reinterpret_cast<const value_type*>(oldv);
744 v2 = *reinterpret_cast<const value_type*>(newv);
745 } else
746 for(size_t i = 0; i < sizeof(value_type); i++) {
747 v1 |= static_cast<value_type>(oldv[i]) << (8 * i);
748 v2 |= static_cast<value_type>(newv[i]) << (8 * i);
750 return val(v1, v2);
754 * \brief The underlying condition.
756 const T& val;
759 void memorysearch::dq_range(uint64_t first, uint64_t last)
761 struct translated_address t = translate_address_linear_ram(0);
762 uint64_t switch_at = t.memory_size;
763 uint64_t base = 0;
764 uint64_t size = previous_content.size();
765 for(uint64_t i = 0; i < size; i++) {
766 if(still_in[i / 64] == 0) {
767 i = (i + 64) >> 6 << 6;
768 i--;
769 continue;
771 //t.memory_size == 0 can happen if cart changes.
772 while(i >= switch_at && t.memory_size > 0) {
773 t = translate_address_linear_ram(switch_at);
774 base = switch_at;
775 switch_at += t.memory_size;
777 uint64_t addr = t.raw_addr + (i - base);
778 if(t.memory_size == 0 || (addr >= first && addr <= last)) {
779 if((still_in[i / 64] >> (i % 64)) & 1) {
780 still_in[i / 64] &= ~(1ULL << (i % 64));
781 candidates--;
788 template<class T> void memorysearch::search(const T& obj) throw()
790 search_value_helper<T> helper(obj);
791 struct translated_address t = translate_address_linear_ram(0);
792 uint64_t switch_at = t.memory_size;
793 uint64_t base = 0;
794 uint64_t size = previous_content.size();
795 for(uint64_t i = 0; i < size; i++) {
796 if(still_in[i / 64] == 0) {
797 i = (i + 64) >> 6 << 6;
798 i--;
799 continue;
801 //t.memory_size == 0 can happen if cart changes.
802 while(i >= switch_at && t.memory_size > 0) {
803 t = translate_address_linear_ram(switch_at);
804 base = switch_at;
805 switch_at += t.memory_size;
807 if(t.memory_size == 0 || !helper(t.memory + i - base, &previous_content[i],
808 t.memory_size - (i - base), t.native_endian)) {
809 if((still_in[i / 64] >> (i % 64)) & 1) {
810 still_in[i / 64] &= ~(1ULL << (i % 64));
811 candidates--;
815 t = translate_address_linear_ram(0);
816 base = 0;
817 size = previous_content.size();
818 while(base < size) {
819 size_t m = t.memory_size;
820 if(m > (size - base))
821 m = size - base;
822 memcpy(&previous_content[base], t.memory, m);
823 base += t.memory_size;
824 t = translate_address_linear_ram(base);
828 void memorysearch::byte_value(uint8_t value) throw() { search(search_value<uint8_t>(value)); }
829 void memorysearch::byte_difference(uint8_t value) throw() { search(search_difference<uint8_t>(value)); }
830 void memorysearch::byte_slt() throw() { search(search_lt<int8_t>()); }
831 void memorysearch::byte_sle() throw() { search(search_le<int8_t>()); }
832 void memorysearch::byte_seq() throw() { search(search_eq<int8_t>()); }
833 void memorysearch::byte_sne() throw() { search(search_ne<int8_t>()); }
834 void memorysearch::byte_sge() throw() { search(search_ge<int8_t>()); }
835 void memorysearch::byte_sgt() throw() { search(search_gt<int8_t>()); }
836 void memorysearch::byte_ult() throw() { search(search_lt<uint8_t>()); }
837 void memorysearch::byte_ule() throw() { search(search_le<uint8_t>()); }
838 void memorysearch::byte_ueq() throw() { search(search_eq<uint8_t>()); }
839 void memorysearch::byte_une() throw() { search(search_ne<uint8_t>()); }
840 void memorysearch::byte_uge() throw() { search(search_ge<uint8_t>()); }
841 void memorysearch::byte_ugt() throw() { search(search_gt<uint8_t>()); }
842 void memorysearch::byte_seqlt() throw() { search(search_seqlt<uint8_t>()); }
843 void memorysearch::byte_seqle() throw() { search(search_seqle<uint8_t>()); }
844 void memorysearch::byte_seqge() throw() { search(search_seqge<uint8_t>()); }
845 void memorysearch::byte_seqgt() throw() { search(search_seqgt<uint8_t>()); }
847 void memorysearch::word_value(uint16_t value) throw() { search(search_value<uint16_t>(value)); }
848 void memorysearch::word_difference(uint16_t value) throw() { search(search_difference<uint16_t>(value)); }
849 void memorysearch::word_slt() throw() { search(search_lt<int16_t>()); }
850 void memorysearch::word_sle() throw() { search(search_le<int16_t>()); }
851 void memorysearch::word_seq() throw() { search(search_eq<int16_t>()); }
852 void memorysearch::word_sne() throw() { search(search_ne<int16_t>()); }
853 void memorysearch::word_sge() throw() { search(search_ge<int16_t>()); }
854 void memorysearch::word_sgt() throw() { search(search_gt<int16_t>()); }
855 void memorysearch::word_ult() throw() { search(search_lt<uint16_t>()); }
856 void memorysearch::word_ule() throw() { search(search_le<uint16_t>()); }
857 void memorysearch::word_ueq() throw() { search(search_eq<uint16_t>()); }
858 void memorysearch::word_une() throw() { search(search_ne<uint16_t>()); }
859 void memorysearch::word_uge() throw() { search(search_ge<uint16_t>()); }
860 void memorysearch::word_ugt() throw() { search(search_gt<uint16_t>()); }
861 void memorysearch::word_seqlt() throw() { search(search_seqlt<uint16_t>()); }
862 void memorysearch::word_seqle() throw() { search(search_seqle<uint16_t>()); }
863 void memorysearch::word_seqge() throw() { search(search_seqge<uint16_t>()); }
864 void memorysearch::word_seqgt() throw() { search(search_seqgt<uint16_t>()); }
866 void memorysearch::dword_value(uint32_t value) throw() { search(search_value<uint32_t>(value)); }
867 void memorysearch::dword_difference(uint32_t value) throw() { search(search_difference<uint32_t>(value)); }
868 void memorysearch::dword_slt() throw() { search(search_lt<int32_t>()); }
869 void memorysearch::dword_sle() throw() { search(search_le<int32_t>()); }
870 void memorysearch::dword_seq() throw() { search(search_eq<int32_t>()); }
871 void memorysearch::dword_sne() throw() { search(search_ne<int32_t>()); }
872 void memorysearch::dword_sge() throw() { search(search_ge<int32_t>()); }
873 void memorysearch::dword_sgt() throw() { search(search_gt<int32_t>()); }
874 void memorysearch::dword_ult() throw() { search(search_lt<uint32_t>()); }
875 void memorysearch::dword_ule() throw() { search(search_le<uint32_t>()); }
876 void memorysearch::dword_ueq() throw() { search(search_eq<uint32_t>()); }
877 void memorysearch::dword_une() throw() { search(search_ne<uint32_t>()); }
878 void memorysearch::dword_uge() throw() { search(search_ge<uint32_t>()); }
879 void memorysearch::dword_ugt() throw() { search(search_gt<uint32_t>()); }
880 void memorysearch::dword_seqlt() throw() { search(search_seqlt<uint32_t>()); }
881 void memorysearch::dword_seqle() throw() { search(search_seqle<uint32_t>()); }
882 void memorysearch::dword_seqge() throw() { search(search_seqge<uint32_t>()); }
883 void memorysearch::dword_seqgt() throw() { search(search_seqgt<uint32_t>()); }
885 void memorysearch::qword_value(uint64_t value) throw() { search(search_value<uint64_t>(value)); }
886 void memorysearch::qword_difference(uint64_t value) throw() { search(search_difference<uint64_t>(value)); }
887 void memorysearch::qword_slt() throw() { search(search_lt<int64_t>()); }
888 void memorysearch::qword_sle() throw() { search(search_le<int64_t>()); }
889 void memorysearch::qword_seq() throw() { search(search_eq<int64_t>()); }
890 void memorysearch::qword_sne() throw() { search(search_ne<int64_t>()); }
891 void memorysearch::qword_sge() throw() { search(search_ge<int64_t>()); }
892 void memorysearch::qword_sgt() throw() { search(search_gt<int64_t>()); }
893 void memorysearch::qword_ult() throw() { search(search_lt<uint64_t>()); }
894 void memorysearch::qword_ule() throw() { search(search_le<uint64_t>()); }
895 void memorysearch::qword_ueq() throw() { search(search_eq<uint64_t>()); }
896 void memorysearch::qword_une() throw() { search(search_ne<uint64_t>()); }
897 void memorysearch::qword_uge() throw() { search(search_ge<uint64_t>()); }
898 void memorysearch::qword_ugt() throw() { search(search_gt<uint64_t>()); }
899 void memorysearch::qword_seqlt() throw() { search(search_seqlt<uint64_t>()); }
900 void memorysearch::qword_seqle() throw() { search(search_seqle<uint64_t>()); }
901 void memorysearch::qword_seqge() throw() { search(search_seqge<uint64_t>()); }
902 void memorysearch::qword_seqgt() throw() { search(search_seqgt<uint64_t>()); }
904 void memorysearch::update() throw() { search(search_update()); }
906 uint64_t memorysearch::get_candidate_count() throw()
908 return candidates;
911 std::list<uint64_t> memorysearch::get_candidates() throw(std::bad_alloc)
913 struct translated_address t = translate_address_linear_ram(0);
914 uint64_t switch_at = t.memory_size;
915 uint64_t base = 0;
916 uint64_t rbase = t.raw_addr;
917 uint64_t size = previous_content.size();
918 std::list<uint64_t> out;
920 for(uint64_t i = 0; i < size; i++) {
921 if(still_in[i / 64] == 0) {
922 i = (i + 64) >> 6 << 6;
923 i--;
924 continue;
926 while(i >= switch_at && t.memory_size > 0) {
927 t = translate_address_linear_ram(switch_at);
928 base = switch_at;
929 rbase = t.raw_addr - t.rel_addr;
930 switch_at += t.memory_size;
932 if((still_in[i / 64] >> (i % 64)) & 1)
933 out.push_back(i - base + rbase);
935 std::cout << "out=" << out.size() << " candidates=" << candidates << std::endl;
936 return out;
939 namespace
941 memorysearch* isrch;
943 std::string tokenize1(const std::string& command, const std::string& syntax);
944 std::pair<std::string, std::string> tokenize2(const std::string& command, const std::string& syntax);
945 std::pair<std::string, std::string> tokenize12(const std::string& command, const std::string& syntax);
947 unsigned char hex(char ch)
949 switch(ch) {
950 case '0': return 0;
951 case '1': return 1;
952 case '2': return 2;
953 case '3': return 3;
954 case '4': return 4;
955 case '5': return 5;
956 case '6': return 6;
957 case '7': return 7;
958 case '8': return 8;
959 case '9': return 9;
960 case 'a': case 'A': return 10;
961 case 'b': case 'B': return 11;
962 case 'c': case 'C': return 12;
963 case 'd': case 'D': return 13;
964 case 'e': case 'E': return 14;
965 case 'f': case 'F': return 15;
967 throw std::runtime_error("Bad hex character");
970 class memorymanip_command : public command
972 public:
973 memorymanip_command(const std::string& cmd) throw(std::bad_alloc)
974 : command(cmd)
976 _command = cmd;
978 ~memorymanip_command() throw() {}
979 void invoke(const std::string& args) throw(std::bad_alloc, std::runtime_error)
981 regex_results t = regex("(([^ \t]+)([ \t]+([^ \t]+)([ \t]+([^ \t].*)?)?)?)?", args);
982 firstword = t[2];
983 secondword = t[4];
984 has_tail = (t[6] != "");
985 address_bad = true;
986 value_bad = true;
987 has_value = (secondword != "");
988 try {
989 if(t = regex("0x(.+)", firstword)) {
990 if(t[1].length() > 16)
991 throw 42;
992 address = 0;
993 for(unsigned i = 0; i < t[1].length(); i++)
994 address = 16 * address + hex(t[1][i]);
995 } else {
996 address = parse_value<uint64_t>(firstword);
998 address_bad = false;
999 } catch(...) {
1001 try {
1002 if(t = regex("0x(.+)", secondword)) {
1003 if(t[1].length() > 16)
1004 throw 42;
1005 value = 0;
1006 for(unsigned i = 0; i < t[1].length(); i++)
1007 value = 16 * value + hex(t[1][i]);
1008 } else if(regex("-.*", secondword)) {
1009 value = static_cast<uint64_t>(parse_value<int64_t>(secondword));
1010 } else {
1011 value = parse_value<uint64_t>(secondword);
1013 value_bad = false;
1014 } catch(...) {
1016 invoke2();
1018 virtual void invoke2() throw(std::bad_alloc, std::runtime_error) = 0;
1019 std::string firstword;
1020 std::string secondword;
1021 uint64_t address;
1022 uint64_t value;
1023 bool has_tail;
1024 bool address_bad;
1025 bool value_bad;
1026 bool has_value;
1027 std::string _command;
1030 template<typename outer, typename inner, typename ret>
1031 class read_command : public memorymanip_command
1033 public:
1034 read_command(const std::string& cmd, ret (*_rfn)(uint64_t addr)) throw(std::bad_alloc)
1035 : memorymanip_command(cmd)
1037 rfn = _rfn;
1039 ~read_command() throw() {}
1040 void invoke2() throw(std::bad_alloc, std::runtime_error)
1042 if(address_bad || has_value || has_tail)
1043 throw std::runtime_error("Syntax: " + _command + " <address>");
1045 std::ostringstream x;
1046 x << "0x" << std::hex << address << " -> " << std::dec
1047 << static_cast<outer>(static_cast<inner>(rfn(address)));
1048 messages << x.str() << std::endl;
1051 std::string get_short_help() throw(std::bad_alloc) { return "Read memory"; }
1052 std::string get_long_help() throw(std::bad_alloc)
1054 return "Syntax: " + _command + " <address>\n"
1055 "Reads data from memory.\n";
1058 ret (*rfn)(uint64_t addr);
1061 template<typename arg, int64_t low, uint64_t high>
1062 class write_command : public memorymanip_command
1064 public:
1065 write_command(const std::string& cmd, bool (*_wfn)(uint64_t addr, arg a)) throw(std::bad_alloc)
1066 : memorymanip_command(cmd)
1068 wfn = _wfn;
1070 ~write_command() throw() {}
1071 void invoke2() throw(std::bad_alloc, std::runtime_error)
1073 if(address_bad || value_bad || has_tail)
1074 throw std::runtime_error("Syntax: " + _command + " <address> <value>");
1075 int64_t value2 = static_cast<int64_t>(value);
1076 if(value2 < low || (value > high && value2 >= 0))
1077 throw std::runtime_error("Value to write out of range");
1078 wfn(address, value & high);
1080 std::string get_short_help() throw(std::bad_alloc) { return "Write memory"; }
1081 std::string get_long_help() throw(std::bad_alloc)
1083 return "Syntax: " + _command + " <address> <value>\n"
1084 "Writes data to memory.\n";
1086 bool (*wfn)(uint64_t addr, arg a);
1089 class memorysearch_command : public memorymanip_command
1091 public:
1092 memorysearch_command() throw(std::bad_alloc) : memorymanip_command("search-memory") {}
1093 void invoke2() throw(std::bad_alloc, std::runtime_error)
1095 if(!isrch)
1096 isrch = new memorysearch();
1097 if(firstword == "sblt" && !has_value)
1098 isrch->byte_slt();
1099 else if(firstword == "sble" && !has_value)
1100 isrch->byte_sle();
1101 else if(firstword == "sbeq" && !has_value)
1102 isrch->byte_seq();
1103 else if(firstword == "sbne" && !has_value)
1104 isrch->byte_sne();
1105 else if(firstword == "sbge" && !has_value)
1106 isrch->byte_sge();
1107 else if(firstword == "sbgt" && !has_value)
1108 isrch->byte_sgt();
1109 else if(firstword == "ublt" && !has_value)
1110 isrch->byte_ult();
1111 else if(firstword == "uble" && !has_value)
1112 isrch->byte_ule();
1113 else if(firstword == "ubeq" && !has_value)
1114 isrch->byte_ueq();
1115 else if(firstword == "ubne" && !has_value)
1116 isrch->byte_une();
1117 else if(firstword == "ubge" && !has_value)
1118 isrch->byte_uge();
1119 else if(firstword == "ubgt" && !has_value)
1120 isrch->byte_ugt();
1121 else if(firstword == "bseqlt" && !has_value)
1122 isrch->byte_seqlt();
1123 else if(firstword == "bseqle" && !has_value)
1124 isrch->byte_seqle();
1125 else if(firstword == "bseqge" && !has_value)
1126 isrch->byte_seqge();
1127 else if(firstword == "bseqgt" && !has_value)
1128 isrch->byte_seqgt();
1129 else if(firstword == "b" && has_value) {
1130 if(static_cast<int64_t>(value) < -128 || value > 255)
1131 throw std::runtime_error("Value to compare out of range");
1132 isrch->byte_value(value & 0xFF);
1133 } else if(firstword == "bdiff" && has_value) {
1134 if(static_cast<int64_t>(value) < -128 || value > 255)
1135 throw std::runtime_error("Value to compare out of range");
1136 isrch->byte_difference(value & 0xFF);
1137 } else if(firstword == "swlt" && !has_value)
1138 isrch->word_slt();
1139 else if(firstword == "swle" && !has_value)
1140 isrch->word_sle();
1141 else if(firstword == "sweq" && !has_value)
1142 isrch->word_seq();
1143 else if(firstword == "swne" && !has_value)
1144 isrch->word_sne();
1145 else if(firstword == "swge" && !has_value)
1146 isrch->word_sge();
1147 else if(firstword == "swgt" && !has_value)
1148 isrch->word_sgt();
1149 else if(firstword == "uwlt" && !has_value)
1150 isrch->word_ult();
1151 else if(firstword == "uwle" && !has_value)
1152 isrch->word_ule();
1153 else if(firstword == "uweq" && !has_value)
1154 isrch->word_ueq();
1155 else if(firstword == "uwne" && !has_value)
1156 isrch->word_une();
1157 else if(firstword == "uwge" && !has_value)
1158 isrch->word_uge();
1159 else if(firstword == "uwgt" && !has_value)
1160 isrch->word_ugt();
1161 else if(firstword == "wseqlt" && !has_value)
1162 isrch->word_seqlt();
1163 else if(firstword == "wseqle" && !has_value)
1164 isrch->word_seqle();
1165 else if(firstword == "wseqge" && !has_value)
1166 isrch->word_seqge();
1167 else if(firstword == "wseqgt" && !has_value)
1168 isrch->word_seqgt();
1169 else if(firstword == "w" && has_value) {
1170 if(static_cast<int64_t>(value) < -32768 || value > 65535)
1171 throw std::runtime_error("Value to compare out of range");
1172 isrch->word_value(value & 0xFFFF);
1173 } else if(firstword == "wdiff" && has_value) {
1174 if(static_cast<int64_t>(value) < -32768 || value > 65535)
1175 throw std::runtime_error("Value to compare out of range");
1176 isrch->word_difference(value & 0xFFFF);
1177 } else if(firstword == "sdlt" && !has_value)
1178 isrch->dword_slt();
1179 else if(firstword == "sdle" && !has_value)
1180 isrch->dword_sle();
1181 else if(firstword == "sdeq" && !has_value)
1182 isrch->dword_seq();
1183 else if(firstword == "sdne" && !has_value)
1184 isrch->dword_sne();
1185 else if(firstword == "sdge" && !has_value)
1186 isrch->dword_sge();
1187 else if(firstword == "sdgt" && !has_value)
1188 isrch->dword_sgt();
1189 else if(firstword == "udlt" && !has_value)
1190 isrch->dword_ult();
1191 else if(firstword == "udle" && !has_value)
1192 isrch->dword_ule();
1193 else if(firstword == "udeq" && !has_value)
1194 isrch->dword_ueq();
1195 else if(firstword == "udne" && !has_value)
1196 isrch->dword_une();
1197 else if(firstword == "udge" && !has_value)
1198 isrch->dword_uge();
1199 else if(firstword == "udgt" && !has_value)
1200 isrch->dword_ugt();
1201 else if(firstword == "dseqlt" && !has_value)
1202 isrch->dword_seqlt();
1203 else if(firstword == "dseqle" && !has_value)
1204 isrch->dword_seqle();
1205 else if(firstword == "dseqge" && !has_value)
1206 isrch->dword_seqge();
1207 else if(firstword == "dseqgt" && !has_value)
1208 isrch->dword_seqgt();
1209 else if(firstword == "d" && has_value) {
1210 if(static_cast<int64_t>(value) < -2147483648LL || value > 4294967295ULL)
1211 throw std::runtime_error("Value to compare out of range");
1212 isrch->dword_value(value & 0xFFFFFFFFULL);
1213 } else if(firstword == "ddiff" && has_value) {
1214 if(static_cast<int64_t>(value) < -2147483648LL || value > 4294967295ULL)
1215 throw std::runtime_error("Value to compare out of range");
1216 isrch->dword_difference(value & 0xFFFFFFFFULL);
1217 } else if(firstword == "sqlt" && !has_value)
1218 isrch->qword_slt();
1219 else if(firstword == "sqle" && !has_value)
1220 isrch->qword_sle();
1221 else if(firstword == "sqeq" && !has_value)
1222 isrch->qword_seq();
1223 else if(firstword == "sqne" && !has_value)
1224 isrch->qword_sne();
1225 else if(firstword == "sqge" && !has_value)
1226 isrch->qword_sge();
1227 else if(firstword == "sqgt" && !has_value)
1228 isrch->qword_sgt();
1229 else if(firstword == "uqlt" && !has_value)
1230 isrch->qword_ult();
1231 else if(firstword == "uqle" && !has_value)
1232 isrch->qword_ule();
1233 else if(firstword == "uqeq" && !has_value)
1234 isrch->qword_ueq();
1235 else if(firstword == "uqne" && !has_value)
1236 isrch->qword_une();
1237 else if(firstword == "uqge" && !has_value)
1238 isrch->qword_uge();
1239 else if(firstword == "uqgt" && !has_value)
1240 isrch->qword_ugt();
1241 else if(firstword == "qseqlt" && !has_value)
1242 isrch->qword_seqlt();
1243 else if(firstword == "qseqle" && !has_value)
1244 isrch->qword_seqle();
1245 else if(firstword == "qseqge" && !has_value)
1246 isrch->qword_seqge();
1247 else if(firstword == "qseqgt" && !has_value)
1248 isrch->qword_seqgt();
1249 else if(firstword == "q" && has_value)
1250 isrch->qword_value(value);
1251 else if(firstword == "qdiff" && has_value)
1252 isrch->qword_difference(value);
1253 else if(firstword == "disqualify" && has_value)
1254 isrch->dq_range(value, value);
1255 else if(firstword == "disqualify_vma" && has_value) {
1256 auto r = translate_address(value);
1257 if(r.memory_size != 0)
1258 isrch->dq_range(r.raw_addr - r.rel_addr, r.raw_addr - r.rel_addr +
1259 r.memory_size - 1);
1260 } else if(firstword == "update" && !has_value)
1261 isrch->update();
1262 else if(firstword == "reset" && !has_value)
1263 isrch->reset();
1264 else if(firstword == "count" && !has_value)
1266 else if(firstword == "print" && !has_value) {
1267 auto c = isrch->get_candidates();
1268 for(auto ci : c) {
1269 std::ostringstream x;
1270 x << "0x" << std::hex << std::setw(8) << std::setfill('0') << ci;
1271 messages << x.str() << std::endl;
1273 } else
1274 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword + "'");
1275 messages << isrch->get_candidate_count() << " candidates remain." << std::endl;
1277 std::string get_short_help() throw(std::bad_alloc) { return "Search memory addresses"; }
1278 std::string get_long_help() throw(std::bad_alloc)
1280 return "Syntax: " + _command + " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
1281 "Syntax: " + _command + " {b,w,d,q}seq{lt,le,ge,gt}\n"
1282 "Syntax: " + _command + " {b,w,d,q} <value>\n"
1283 "Syntax: " + _command + " {b,w,d,q}diff <value>\n"
1284 "Syntax: " + _command + " disqualify{,_vma} <address>\n"
1285 "Syntax: " + _command + " update\n"
1286 "Syntax: " + _command + " reset\n"
1287 "Syntax: " + _command + " count\n"
1288 "Syntax: " + _command + " print\n"
1289 "Searches addresses from memory.\n";
1291 } memorysearch_o;
1293 read_command<uint64_t, uint8_t, uint8_t> ru1("read-byte", memory_read_byte);
1294 read_command<uint64_t, uint16_t, uint16_t> ru2("read-word", memory_read_word);
1295 read_command<uint64_t, uint32_t, uint32_t> ru4("read-dword", memory_read_dword);
1296 read_command<uint64_t, uint64_t, uint64_t> ru8("read-qword", memory_read_qword);
1297 read_command<uint64_t, int8_t, uint8_t> rs1("read-sbyte", memory_read_byte);
1298 read_command<uint64_t, int16_t, uint16_t> rs2("read-sword", memory_read_word);
1299 read_command<uint64_t, int32_t, uint32_t> rs4("read-sdword", memory_read_dword);
1300 read_command<uint64_t, int64_t, uint64_t> rs8("read-sqword", memory_read_qword);
1301 write_command<uint8_t, -128, 0xFF> w1("write-byte", memory_write_byte);
1302 write_command<uint16_t, -32768, 0xFFFF> w2("write-word", memory_write_word);
1303 write_command<uint32_t, -2147483648LL, 0xFFFFFFFFULL> w4("write-dword", memory_write_dword);
1304 write_command<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL> w8("write-qword", memory_write_qword);