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