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