Fix all warnings -Wall spews
[lsnes.git] / memorymanip.cpp
blob39b535d51370d1c1bb01fffe9011da1913e9b483
1 #include "lsnes.hpp"
2 #include "window.hpp"
3 #include <iostream>
4 #include <snes/snes.hpp>
5 #include "rom.hpp"
6 #include "memorymanip.hpp"
7 #include "fieldsplit.hpp"
8 #include <sstream>
9 #include <iomanip>
10 #include <cstdint>
11 typedef uint8_t uint8;
12 typedef uint16_t uint16;
13 typedef uint32_t uint32;
14 typedef int8_t int8;
15 typedef int16_t int16;
16 typedef int32_t int32;
17 #include <nall/platform.hpp>
18 #include <nall/endian.hpp>
19 #include <nall/varint.hpp>
20 #include <nall/bit.hpp>
21 #include <nall/serializer.hpp>
22 #include <nall/property.hpp>
23 using namespace nall;
24 #include <ui-libsnes/libsnes.hpp>
25 using namespace SNES;
28 namespace
30 struct translated_address
32 uint32_t rel_addr;
33 uint32_t raw_addr;
34 uint8_t* memory;
35 uint32_t memory_size;
36 bool not_writable;
37 bool native_endian;
40 struct region
42 std::string name;
43 uint32_t base;
44 uint32_t size;
45 uint8_t* memory;
46 bool not_writable;
47 bool native_endian;
50 std::vector<region> memory_regions;
51 uint32_t linear_ram_size = 0;
52 bool system_little_endian = true;
54 struct translated_address translate_address(uint32_t rawaddr) throw()
56 struct translated_address t;
57 t.rel_addr = 0;
58 t.raw_addr = 0;
59 t.memory = NULL;
60 t.memory_size = 0;
61 t.not_writable = true;
62 for(auto i = memory_regions.begin(); i != memory_regions.end(); ++i) {
63 if(i->base > rawaddr || i->base + i->size <= rawaddr)
64 continue;
65 t.rel_addr = rawaddr - i->base;
66 t.raw_addr = rawaddr;
67 t.memory = i->memory;
68 t.memory_size = i->size;
69 t.not_writable = i->not_writable;
70 t.native_endian = i->native_endian;
71 break;
73 return t;
76 struct translated_address translate_address_linear_ram(uint32_t ramlinaddr) throw()
78 struct translated_address t;
79 t.rel_addr = 0;
80 t.raw_addr = 0;
81 t.memory = NULL;
82 t.memory_size = 0;
83 t.not_writable = true;
84 for(auto i = memory_regions.begin(); i != memory_regions.end(); ++i) {
85 if(i->not_writable)
86 continue;
87 if(ramlinaddr >= i->size) {
88 ramlinaddr -= i->size;
89 continue;
91 t.rel_addr = ramlinaddr;
92 t.raw_addr = i->base + ramlinaddr;
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 break;
99 return t;
102 uint32_t get_linear_ram_size() throw()
104 return linear_ram_size;
107 uint32_t create_region(const std::string& name, uint32_t base, uint8_t* memory, uint32_t size, bool readonly,
108 bool native_endian = false) throw(std::bad_alloc)
110 if(size == 0)
111 return base;
112 struct region r;
113 r.name = name;
114 r.base = base;
115 r.memory = memory;
116 r.size = size;
117 r.not_writable = readonly;
118 r.native_endian = native_endian;
119 if(!readonly)
120 linear_ram_size += size;
121 memory_regions.push_back(r);
122 return base + size;
125 uint32_t create_region(const std::string& name, uint32_t base, MappedRAM& memory, bool readonly,
126 bool native_endian = false) throw(std::bad_alloc)
128 return create_region(name, base, memory.data(), memory.size(), readonly, native_endian);
131 uint16_t native_bigendian_convert(uint16_t x) throw()
133 if(system_little_endian)
134 return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00));
135 else
136 return x;
139 uint32_t native_bigendian_convert(uint32_t x) throw()
141 if(system_little_endian)
142 return (((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
143 ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000));
144 else
145 return x;
148 uint64_t native_bigendian_convert(uint64_t x) throw()
150 if(system_little_endian)
151 return (((x >> 56) & 0xFF) | ((x >> 40) & 0xFF00) |
152 ((x >> 24) & 0xFF0000) | ((x >> 8) & 0xFF000000) |
153 ((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) |
154 ((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF00000000000000ULL));
155 else
156 return x;
161 void refresh_cart_mappings() throw(std::bad_alloc)
163 linear_ram_size = 0;
164 memory_regions.clear();
165 if(get_current_rom_info().first == ROMTYPE_NONE)
166 return;
167 create_region("WRAM", 0x007E0000, cpu.wram, 131072, false);
168 create_region("APURAM", 0x00000000, smp.apuram, 65536, false);
169 create_region("VRAM", 0x00010000, ppu.vram, 65536, false);
170 create_region("OAM", 0x00020000, ppu.oam, 544, false);
171 create_region("CGRAM", 0x00021000, ppu.cgram, 512, false);
172 if(cartridge.has_srtc()) create_region("RTC", 0x00022000, srtc.rtc, 20, false);
173 if(cartridge.has_spc7110rtc()) create_region("RTC", 0x00022000, spc7110.rtc, 20, false);
174 if(cartridge.has_necdsp()) {
175 create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(necdsp.dataRAM), 4096, false, true);
176 create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(necdsp.programROM), 65536, true,
177 true);
178 create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(necdsp.dataROM), 4096, true, true);
180 create_region("SRAM", 0x10000000, cartridge.ram, false);
181 create_region("ROM", 0x80000000, cartridge.rom, true);
182 switch(get_current_rom_info().first) {
183 case ROMTYPE_BSX:
184 case ROMTYPE_BSXSLOTTED:
185 create_region("BSXFLASH", 0x90000000, bsxflash.memory, true);
186 create_region("BSX_RAM", 0x20000000, bsxcartridge.sram, false);
187 create_region("BSX_PRAM", 0x30000000, bsxcartridge.psram, false);
188 break;
189 case ROMTYPE_SUFAMITURBO:
190 create_region("SLOTA_ROM", 0x90000000, sufamiturbo.slotA.rom, true);
191 create_region("SLOTB_ROM", 0xA0000000, sufamiturbo.slotB.rom, true);
192 create_region("SLOTA_RAM", 0x20000000, sufamiturbo.slotA.ram, false);
193 create_region("SLOTB_RAM", 0x30000000, sufamiturbo.slotB.ram, false);
194 break;
195 case ROMTYPE_SGB:
196 create_region("GBROM", 0x90000000, GameBoy::cartridge.romdata, GameBoy::cartridge.romsize, true);
197 create_region("GBRAM", 0x20000000, GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize, false);
198 break;
199 case ROMTYPE_SNES:
200 case ROMTYPE_NONE:
201 break;
205 std::vector<struct memory_region> get_regions() throw(std::bad_alloc)
207 std::vector<struct memory_region> out;
208 for(auto i = memory_regions.begin(); i != memory_regions.end(); ++i) {
209 struct memory_region r;
210 r.region_name = i->name;
211 r.baseaddr = i->base;
212 r.size = i->size;
213 r.lastaddr = i->base + i->size - 1;
214 r.readonly = i->not_writable;
215 r.native_endian = i->native_endian;
216 out.push_back(r);
218 return out;
221 uint8_t memory_read_byte(uint32_t addr) throw()
223 struct translated_address laddr = translate_address(addr);
224 uint8_t value = 0;
225 if(laddr.rel_addr < laddr.memory_size)
226 value |= laddr.memory[laddr.rel_addr++];
227 return value;
230 uint16_t memory_read_word(uint32_t addr) throw()
232 struct translated_address laddr = translate_address(addr);
233 uint16_t value = 0;
234 if(laddr.rel_addr < laddr.memory_size)
235 value |= (static_cast<uint16_t>(laddr.memory[laddr.rel_addr++]) << 8);
236 if(laddr.rel_addr < laddr.memory_size)
237 value |= (static_cast<uint16_t>(laddr.memory[laddr.rel_addr++]));
238 if(laddr.native_endian)
239 value = native_bigendian_convert(value);
240 return value;
243 uint32_t memory_read_dword(uint32_t addr) throw()
245 struct translated_address laddr = translate_address(addr);
246 uint32_t value = 0;
247 if(laddr.rel_addr < laddr.memory_size)
248 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 24);
249 if(laddr.rel_addr < laddr.memory_size)
250 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 16);
251 if(laddr.rel_addr < laddr.memory_size)
252 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 8);
253 if(laddr.rel_addr < laddr.memory_size)
254 value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]));
255 if(laddr.native_endian)
256 value = native_bigendian_convert(value);
257 return value;
260 uint64_t memory_read_qword(uint32_t addr) throw()
262 struct translated_address laddr = translate_address(addr);
263 uint64_t value = 0;
264 if(laddr.rel_addr < laddr.memory_size)
265 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 56);
266 if(laddr.rel_addr < laddr.memory_size)
267 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 48);
268 if(laddr.rel_addr < laddr.memory_size)
269 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 40);
270 if(laddr.rel_addr < laddr.memory_size)
271 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 32);
272 if(laddr.rel_addr < laddr.memory_size)
273 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 24);
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++]) << 8);
278 if(laddr.rel_addr < laddr.memory_size)
279 value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]));
280 if(laddr.native_endian)
281 value = native_bigendian_convert(value);
282 return value;
285 //Byte write to address (false if failed).
286 bool memory_write_byte(uint32_t addr, uint8_t data) throw()
288 struct translated_address laddr = translate_address(addr);
289 if(laddr.rel_addr >= laddr.memory_size || laddr.not_writable)
290 return false;
291 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
292 return true;
295 bool memory_write_word(uint32_t addr, uint16_t data) throw()
297 struct translated_address laddr = translate_address(addr);
298 if(laddr.native_endian)
299 data = native_bigendian_convert(data);
300 if(laddr.rel_addr >= laddr.memory_size - 1 || laddr.not_writable)
301 return false;
302 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
303 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
304 return true;
307 bool memory_write_dword(uint32_t addr, uint32_t data) throw()
309 struct translated_address laddr = translate_address(addr);
310 if(laddr.native_endian)
311 data = native_bigendian_convert(data);
312 if(laddr.rel_addr >= laddr.memory_size - 3 || laddr.not_writable)
313 return false;
314 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 24);
315 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 16);
316 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
317 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
318 return true;
321 bool memory_write_qword(uint32_t addr, uint64_t data) throw()
323 struct translated_address laddr = translate_address(addr);
324 if(laddr.native_endian)
325 data = native_bigendian_convert(data);
326 if(laddr.rel_addr >= laddr.memory_size - 7 || laddr.not_writable)
327 return false;
328 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 56);
329 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 48);
330 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 40);
331 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 32);
332 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 24);
333 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 16);
334 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
335 laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
336 return true;
339 memorysearch::memorysearch() throw(std::bad_alloc)
341 reset();
344 void memorysearch::reset() throw(std::bad_alloc)
346 uint32_t linearram = get_linear_ram_size();
347 previous_content.resize(linearram);
348 still_in.resize((linearram + 63) / 64);
349 for(uint32_t i = 0; i < linearram / 64; i++)
350 still_in[i] = 0xFFFFFFFFFFFFFFFFULL;
351 if(linearram % 64)
352 still_in[linearram / 64] = (1ULL << (linearram % 64)) - 1;
353 uint32_t addr = 0;
354 while(addr < linearram) {
355 struct translated_address t = translate_address_linear_ram(addr);
356 memcpy(&previous_content[addr], t.memory, t.memory_size);
357 addr += t.memory_size;
359 candidates = linearram;
363 * \brief Native-value search function for specific value
365 template<typename T>
366 struct search_value
369 * \brief The underlying numeric type
371 typedef T value_type;
374 * \brief Create new search object
376 * \param v The value to search for.
378 search_value(T v) throw()
380 val = v;
384 * \brief Condition function.
385 * \param oldv The old value
386 * \param newv The new value
387 * \return True if new value satisfies condition, false otherwise.
389 bool operator()(T oldv, T newv) const throw()
391 return (newv == val);
395 * \brief The value to look for
397 T val;
401 * \brief Native-value search function for less-than function.
403 template<typename T>
404 struct search_lt
407 * \brief The underlying numeric type
409 typedef T value_type;
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 < oldv);
424 * \brief Native-value search function for less-or-equal-to function.
426 template<typename T>
427 struct search_le
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 equals function.
449 template<typename T>
450 struct search_eq
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 not-equal function.
472 template<typename T>
473 struct search_ne
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 greater-or-equal-to function.
495 template<typename T>
496 struct search_ge
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-than function.
518 template<typename T>
519 struct search_gt
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 Helper class to decode arguments to search functions
541 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
542 * expected for the search function.
544 template<typename T>
545 struct search_value_helper
548 * \brief The underlying numeric type
550 typedef typename T::value_type value_type;
553 * \brief Constructor constructing condition object
555 * This constructor takes in condition object with the native-value interface and makes condition object with
556 * interface used by search().
558 * \param v The condition object to wrap.
560 search_value_helper(const T& v) throw()
561 : val(v)
566 * \brief Condition function
568 * This function is search()-compatible condition function calling the underlying condition.
570 bool operator()(const uint8_t* newv, const uint8_t* oldv, uint32_t left, bool nativeendian) const throw()
572 if(left < sizeof(value_type))
573 return false;
574 value_type v1 = 0;
575 value_type v2 = 0;
576 if(nativeendian) {
577 v1 = *reinterpret_cast<const value_type*>(oldv);
578 v2 = *reinterpret_cast<const value_type*>(newv);
579 } else
580 for(size_t i = 0; i < sizeof(value_type); i++) {
581 v1 |= static_cast<value_type>(oldv[i]) << (8 * (sizeof(value_type) - i));
582 v2 |= static_cast<value_type>(newv[i]) << (8 * (sizeof(value_type) - i));
584 return val(v1, v2);
588 * \brief The underlying condition.
590 const T& val;
593 template<class T> void memorysearch::search(const T& obj) throw()
595 search_value_helper<T> helper(obj);
596 struct translated_address t = translate_address_linear_ram(0);
597 uint32_t switch_at = t.memory_size;
598 uint32_t base = 0;
599 uint32_t size = previous_content.size();
600 for(uint32_t i = 0; i < size; i++) {
601 if(still_in[i / 64] == 0) {
602 i = (i + 64) >> 6 << 6;
603 i--;
604 continue;
606 //t.memory_size == 0 can happen if cart changes.
607 while(i >= switch_at && t.memory_size > 0) {
608 t = translate_address_linear_ram(switch_at);
609 base = switch_at;
610 switch_at += t.memory_size;
612 if(t.memory_size == 0 || !helper(t.memory + i - base, &previous_content[i],
613 t.memory_size - (i - base), t.native_endian)) {
614 if((still_in[i / 64] >> (i % 64)) & 1) {
615 still_in[i / 64] &= ~(1ULL << (i % 64));
616 candidates--;
620 t = translate_address_linear_ram(0);
621 base = 0;
622 size = previous_content.size();
623 while(base < size) {
624 size_t m = t.memory_size;
625 if(m > (size - base))
626 m = size - base;
627 memcpy(&previous_content[base], t.memory, m);
628 base += t.memory_size;
629 t = translate_address_linear_ram(base);
633 void memorysearch::byte_value(uint8_t value) throw() { search(search_value<uint8_t>(value)); }
634 void memorysearch::byte_slt() throw() { search(search_lt<int8_t>()); }
635 void memorysearch::byte_sle() throw() { search(search_le<int8_t>()); }
636 void memorysearch::byte_seq() throw() { search(search_eq<int8_t>()); }
637 void memorysearch::byte_sne() throw() { search(search_ne<int8_t>()); }
638 void memorysearch::byte_sge() throw() { search(search_ge<int8_t>()); }
639 void memorysearch::byte_sgt() throw() { search(search_gt<int8_t>()); }
640 void memorysearch::byte_ult() throw() { search(search_lt<uint8_t>()); }
641 void memorysearch::byte_ule() throw() { search(search_le<uint8_t>()); }
642 void memorysearch::byte_ueq() throw() { search(search_eq<uint8_t>()); }
643 void memorysearch::byte_une() throw() { search(search_ne<uint8_t>()); }
644 void memorysearch::byte_uge() throw() { search(search_ge<uint8_t>()); }
645 void memorysearch::byte_ugt() throw() { search(search_gt<uint8_t>()); }
647 void memorysearch::word_value(uint16_t value) throw() { search(search_value<uint16_t>(value)); }
648 void memorysearch::word_slt() throw() { search(search_lt<int16_t>()); }
649 void memorysearch::word_sle() throw() { search(search_le<int16_t>()); }
650 void memorysearch::word_seq() throw() { search(search_eq<int16_t>()); }
651 void memorysearch::word_sne() throw() { search(search_ne<int16_t>()); }
652 void memorysearch::word_sge() throw() { search(search_ge<int16_t>()); }
653 void memorysearch::word_sgt() throw() { search(search_gt<int16_t>()); }
654 void memorysearch::word_ult() throw() { search(search_lt<uint16_t>()); }
655 void memorysearch::word_ule() throw() { search(search_le<uint16_t>()); }
656 void memorysearch::word_ueq() throw() { search(search_eq<uint16_t>()); }
657 void memorysearch::word_une() throw() { search(search_ne<uint16_t>()); }
658 void memorysearch::word_uge() throw() { search(search_ge<uint16_t>()); }
659 void memorysearch::word_ugt() throw() { search(search_gt<uint16_t>()); }
661 void memorysearch::dword_value(uint32_t value) throw() { search(search_value<uint32_t>(value)); }
662 void memorysearch::dword_slt() throw() { search(search_lt<int32_t>()); }
663 void memorysearch::dword_sle() throw() { search(search_le<int32_t>()); }
664 void memorysearch::dword_seq() throw() { search(search_eq<int32_t>()); }
665 void memorysearch::dword_sne() throw() { search(search_ne<int32_t>()); }
666 void memorysearch::dword_sge() throw() { search(search_ge<int32_t>()); }
667 void memorysearch::dword_sgt() throw() { search(search_gt<int32_t>()); }
668 void memorysearch::dword_ult() throw() { search(search_lt<uint32_t>()); }
669 void memorysearch::dword_ule() throw() { search(search_le<uint32_t>()); }
670 void memorysearch::dword_ueq() throw() { search(search_eq<uint32_t>()); }
671 void memorysearch::dword_une() throw() { search(search_ne<uint32_t>()); }
672 void memorysearch::dword_uge() throw() { search(search_ge<uint32_t>()); }
673 void memorysearch::dword_ugt() throw() { search(search_gt<uint32_t>()); }
675 void memorysearch::qword_value(uint64_t value) throw() { search(search_value<uint64_t>(value)); }
676 void memorysearch::qword_slt() throw() { search(search_lt<int64_t>()); }
677 void memorysearch::qword_sle() throw() { search(search_le<int64_t>()); }
678 void memorysearch::qword_seq() throw() { search(search_eq<int64_t>()); }
679 void memorysearch::qword_sne() throw() { search(search_ne<int64_t>()); }
680 void memorysearch::qword_sge() throw() { search(search_ge<int64_t>()); }
681 void memorysearch::qword_sgt() throw() { search(search_gt<int64_t>()); }
682 void memorysearch::qword_ult() throw() { search(search_lt<uint64_t>()); }
683 void memorysearch::qword_ule() throw() { search(search_le<uint64_t>()); }
684 void memorysearch::qword_ueq() throw() { search(search_eq<uint64_t>()); }
685 void memorysearch::qword_une() throw() { search(search_ne<uint64_t>()); }
686 void memorysearch::qword_uge() throw() { search(search_ge<uint64_t>()); }
687 void memorysearch::qword_ugt() throw() { search(search_gt<uint64_t>()); }
689 uint32_t memorysearch::get_candidate_count() throw()
691 return candidates;
694 std::list<uint32_t> memorysearch::get_candidates() throw(std::bad_alloc)
696 struct translated_address t = translate_address_linear_ram(0);
697 uint32_t switch_at = t.memory_size;
698 uint32_t base = 0;
699 uint32_t rbase = t.raw_addr;
700 uint32_t size = previous_content.size();
701 std::list<uint32_t> out;
703 for(uint32_t i = 0; i < size; i++) {
704 if(still_in[i / 64] == 0) {
705 i = (i + 64) >> 6 << 6;
706 i--;
707 continue;
709 while(i >= switch_at && t.memory_size > 0) {
710 t = translate_address_linear_ram(switch_at);
711 base = switch_at;
712 rbase = t.raw_addr - t.rel_addr;
713 switch_at += t.memory_size;
715 if((still_in[i / 64] >> (i % 64)) & 1)
716 out.push_back(i - base + rbase);
718 std::cout << "out=" << out.size() << " candidates=" << candidates << std::endl;
719 return out;
722 namespace
724 memorysearch* isrch;
726 std::string tokenize1(const std::string& command, const std::string& syntax);
727 std::pair<std::string, std::string> tokenize2(const std::string& command, const std::string& syntax);
728 std::pair<std::string, std::string> tokenize12(const std::string& command, const std::string& syntax);
730 unsigned char hex(char ch)
732 switch(ch) {
733 case '0': return 0;
734 case '1': return 1;
735 case '2': return 2;
736 case '3': return 3;
737 case '4': return 4;
738 case '5': return 5;
739 case '6': return 6;
740 case '7': return 7;
741 case '8': return 8;
742 case '9': return 9;
743 case 'a': case 'A': return 10;
744 case 'b': case 'B': return 11;
745 case 'c': case 'C': return 12;
746 case 'd': case 'D': return 13;
747 case 'e': case 'E': return 14;
748 case 'f': case 'F': return 15;
750 throw std::runtime_error("Bad hex character");
755 bool memorymanip_command(const std::string& cmd, window* win) throw(std::bad_alloc, std::runtime_error)
757 tokensplitter t(cmd);
758 std::string command = t;
759 std::string firstword = t;
760 std::string secondword = t;
761 uint32_t address;
762 uint64_t value;
763 bool has_tail = (t.tail() != "");
764 bool address_bad = true;
765 bool value_bad = true;
766 bool has_value = (secondword != "");
767 try {
768 if(firstword.length() >= 2 && firstword.substr(0, 2) == "0x") {
769 if(firstword.length() > 10)
770 throw 42;
771 address = 0;
772 for(unsigned i = 2; i < firstword.length(); i++)
773 address = 16 * address + hex(firstword[i]);
774 } else {
775 address = parse_value<uint32_t>(firstword);
777 address_bad = false;
778 } catch(...) {
780 try {
781 if(secondword.length() >= 2 && secondword.substr(0, 2) == "0x") {
782 if(secondword.length() > 18)
783 throw 42;
784 value = 0;
785 for(unsigned i = 2; i < secondword.length(); i++)
786 value = 16 * value + hex(secondword[i]);
787 } else if(secondword.length() > 0 && secondword[0] == '-') {
788 value = static_cast<uint64_t>(parse_value<int64_t>(secondword));
789 } else {
790 value = parse_value<uint64_t>(secondword);
792 value_bad = false;
793 } catch(...) {
795 if(command == "read-byte") {
796 if(address_bad || has_value || has_tail)
797 throw std::runtime_error("Syntax: " + command + " <address>");
799 std::ostringstream x;
800 x << "0x" << std::hex << address << " -> " << std::dec
801 << static_cast<uint64_t>(memory_read_byte(address));
802 out(win) << x.str() << std::endl;
804 return true;
806 if(command == "read-word") {
807 if(address_bad || has_value || has_tail)
808 throw std::runtime_error("Syntax: " + command + " <address>");
810 std::ostringstream x;
811 x << "0x" << std::hex << address << " -> " << std::dec
812 << static_cast<uint64_t>(memory_read_word(address));
813 out(win) << x.str() << std::endl;
815 return true;
817 if(command == "read-dword") {
818 if(address_bad || has_value || has_tail)
819 throw std::runtime_error("Syntax: " + command + " <address>");
821 std::ostringstream x;
822 x << "0x" << std::hex << address << " -> " << std::dec
823 << static_cast<uint64_t>(memory_read_dword(address));
824 out(win) << x.str() << std::endl;
826 return true;
828 if(command == "read-qword") {
829 if(address_bad || has_value || has_tail)
830 throw std::runtime_error("Syntax: " + command + " <address>");
832 std::ostringstream x;
833 x << "0x" << std::hex << address << " -> " << std::dec
834 << static_cast<uint64_t>(memory_read_qword(address));
835 out(win) << x.str() << std::endl;
837 return true;
839 if(command == "read-sbyte") {
840 if(address_bad || has_value || has_tail)
841 throw std::runtime_error("Syntax: " + command + " <address>");
843 std::ostringstream x;
844 x << "0x" << std::hex << address << " -> " << std::dec
845 << static_cast<int64_t>(static_cast<int8_t>(memory_read_byte(address)));
846 out(win) << x.str() << std::endl;
848 return true;
850 if(command == "read-sword") {
851 if(address_bad || has_value || has_tail)
852 throw std::runtime_error("Syntax: " + command + " <address>");
854 std::ostringstream x;
855 x << "0x" << std::hex << address << " -> " << std::dec
856 << static_cast<int64_t>(static_cast<int16_t>(memory_read_word(address)));
857 out(win) << x.str() << std::endl;
859 return true;
861 if(command == "read-sdword") {
862 if(address_bad || has_value || has_tail)
863 throw std::runtime_error("Syntax: " + command + " <address>");
865 std::ostringstream x;
866 x << "0x" << std::hex << address << " -> " << std::dec
867 << static_cast<int64_t>(static_cast<int32_t>(memory_read_dword(address)));
868 out(win) << x.str() << std::endl;
870 return true;
872 if(command == "read-sqword") {
873 if(address_bad || has_value || has_tail)
874 throw std::runtime_error("Syntax: " + command + " <address>");
876 std::ostringstream x;
877 x << "0x" << std::hex << address << " -> " << std::dec
878 << static_cast<int64_t>(static_cast<int64_t>(memory_read_qword(address)));
879 out(win) << x.str() << std::endl;
881 return true;
883 if(command == "write-byte") {
884 if(address_bad || value_bad || has_tail)
885 throw std::runtime_error("Syntax: " + command + " <address> <value>");
886 if(static_cast<int64_t>(value) < -128 || value > 255)
887 throw std::runtime_error("Value to write out of range");
888 memory_write_byte(address, value & 0xFF);
889 return true;
891 if(command == "write-word") {
892 if(address_bad || value_bad || has_tail)
893 throw std::runtime_error("Syntax: " + command + " <address> <value>");
894 if(static_cast<int64_t>(value) < -32768 || value > 65535)
895 throw std::runtime_error("Value to write out of range");
896 memory_write_word(address, value & 0xFFFF);
897 return true;
899 if(command == "write-dword") {
900 if(address_bad || value_bad || has_tail)
901 throw std::runtime_error("Syntax: " + command + " <address> <value>");
902 if(static_cast<int64_t>(value) < -2147483648 || value > 4294967295ULL)
903 throw std::runtime_error("Value to write out of range");
904 memory_write_dword(address, value & 0xFFFF);
905 return true;
907 if(command == "write-qword") {
908 if(address_bad || value_bad || has_tail)
909 throw std::runtime_error("Syntax: " + command + " <address> <value>");
910 memory_write_dword(address, value & 0xFFFF);
911 return true;
913 if(command == "search-memory") {
914 if(!isrch)
915 isrch = new memorysearch();
916 if(firstword == "sblt" && !has_value)
917 isrch->byte_slt();
918 else if(firstword == "sble" && !has_value)
919 isrch->byte_sle();
920 else if(firstword == "sbeq" && !has_value)
921 isrch->byte_seq();
922 else if(firstword == "sbne" && !has_value)
923 isrch->byte_sne();
924 else if(firstword == "sbge" && !has_value)
925 isrch->byte_sge();
926 else if(firstword == "sbgt" && !has_value)
927 isrch->byte_sgt();
928 else if(firstword == "ublt" && !has_value)
929 isrch->byte_ult();
930 else if(firstword == "uble" && !has_value)
931 isrch->byte_ule();
932 else if(firstword == "ubeq" && !has_value)
933 isrch->byte_ueq();
934 else if(firstword == "ubne" && !has_value)
935 isrch->byte_une();
936 else if(firstword == "ubge" && !has_value)
937 isrch->byte_uge();
938 else if(firstword == "ubgt" && !has_value)
939 isrch->byte_ugt();
940 else if(firstword == "b" && has_value) {
941 if(static_cast<int64_t>(value) < -128 || value > 255)
942 throw std::runtime_error("Value to compare out of range");
943 isrch->byte_value(value & 0xFF);
944 } else if(firstword == "swlt" && !has_value)
945 isrch->word_slt();
946 else if(firstword == "swle" && !has_value)
947 isrch->word_sle();
948 else if(firstword == "sweq" && !has_value)
949 isrch->word_seq();
950 else if(firstword == "swne" && !has_value)
951 isrch->word_sne();
952 else if(firstword == "swge" && !has_value)
953 isrch->word_sge();
954 else if(firstword == "swgt" && !has_value)
955 isrch->word_sgt();
956 else if(firstword == "uwlt" && !has_value)
957 isrch->word_ult();
958 else if(firstword == "uwle" && !has_value)
959 isrch->word_ule();
960 else if(firstword == "uweq" && !has_value)
961 isrch->word_ueq();
962 else if(firstword == "uwne" && !has_value)
963 isrch->word_une();
964 else if(firstword == "uwge" && !has_value)
965 isrch->word_uge();
966 else if(firstword == "uwgt" && !has_value)
967 isrch->word_ugt();
968 else if(firstword == "w" && has_value) {
969 if(static_cast<int64_t>(value) < -32768 || value > 65535)
970 throw std::runtime_error("Value to compare out of range");
971 isrch->word_value(value & 0xFF);
972 } else if(firstword == "sdlt" && !has_value)
973 isrch->dword_slt();
974 else if(firstword == "sdle" && !has_value)
975 isrch->dword_sle();
976 else if(firstword == "sdeq" && !has_value)
977 isrch->dword_seq();
978 else if(firstword == "sdne" && !has_value)
979 isrch->dword_sne();
980 else if(firstword == "sdge" && !has_value)
981 isrch->dword_sge();
982 else if(firstword == "sdgt" && !has_value)
983 isrch->dword_sgt();
984 else if(firstword == "udlt" && !has_value)
985 isrch->dword_ult();
986 else if(firstword == "udle" && !has_value)
987 isrch->dword_ule();
988 else if(firstword == "udeq" && !has_value)
989 isrch->dword_ueq();
990 else if(firstword == "udne" && !has_value)
991 isrch->dword_une();
992 else if(firstword == "udge" && !has_value)
993 isrch->dword_uge();
994 else if(firstword == "udgt" && !has_value)
995 isrch->dword_ugt();
996 else if(firstword == "d" && has_value) {
997 if(static_cast<int64_t>(value) < -2147483648 || value > 4294967295ULL)
998 throw std::runtime_error("Value to compare out of range");
999 isrch->dword_value(value & 0xFF);
1000 } else if(firstword == "sqlt" && !has_value)
1001 isrch->qword_slt();
1002 else if(firstword == "sqle" && !has_value)
1003 isrch->qword_sle();
1004 else if(firstword == "sqeq" && !has_value)
1005 isrch->qword_seq();
1006 else if(firstword == "sqne" && !has_value)
1007 isrch->qword_sne();
1008 else if(firstword == "sqge" && !has_value)
1009 isrch->qword_sge();
1010 else if(firstword == "sqgt" && !has_value)
1011 isrch->qword_sgt();
1012 else if(firstword == "uqlt" && !has_value)
1013 isrch->qword_ult();
1014 else if(firstword == "uqle" && !has_value)
1015 isrch->qword_ule();
1016 else if(firstword == "uqeq" && !has_value)
1017 isrch->qword_ueq();
1018 else if(firstword == "uqne" && !has_value)
1019 isrch->qword_une();
1020 else if(firstword == "uqge" && !has_value)
1021 isrch->qword_uge();
1022 else if(firstword == "uqgt" && !has_value)
1023 isrch->qword_ugt();
1024 else if(firstword == "q" && has_value) {
1025 isrch->qword_value(value & 0xFF);
1026 } else if(firstword == "reset" && !has_value)
1027 isrch->reset();
1028 else if(firstword == "count" && !has_value)
1030 else if(firstword == "print" && !has_value) {
1031 auto c = isrch->get_candidates();
1032 for(auto ci = c.begin(); ci != c.end(); ci++) {
1033 std::ostringstream x;
1034 x << "0x" << std::hex << std::setw(8) << std::setfill('0') << *ci;
1035 out(win) << x.str() << std::endl;
1037 } else
1038 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword + "'");
1039 out(win) << isrch->get_candidate_count() << " candidates remain." << std::endl;
1040 return true;
1042 return false;