2 #include <snes/snes.hpp>
3 #include <ui-libsnes/libsnes.hpp>
5 #include "core/command.hpp"
6 #include "core/memorymanip.hpp"
7 #include "core/misc.hpp"
8 #include "core/rom.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
54 std::vector
<region
> memory_regions
;
55 uint32_t linear_ram_size
= 0;
56 bool system_little_endian
= true;
58 struct translated_address
translate_address(uint32_t rawaddr
) throw()
60 struct translated_address t
;
65 t
.not_writable
= true;
66 for(auto i
: memory_regions
) {
67 if(i
.base
> rawaddr
|| i
.base
+ i
.size
<= rawaddr
)
69 t
.rel_addr
= rawaddr
- i
.base
;
72 t
.memory_size
= i
.size
;
73 t
.not_writable
= i
.not_writable
;
74 t
.native_endian
= i
.native_endian
;
80 struct translated_address
translate_address_linear_ram(uint32_t ramlinaddr
) throw()
82 struct translated_address t
;
87 t
.not_writable
= true;
88 for(auto i
: memory_regions
) {
91 if(ramlinaddr
>= i
.size
) {
95 t
.rel_addr
= ramlinaddr
;
96 t
.raw_addr
= i
.base
+ ramlinaddr
;
98 t
.memory_size
= i
.size
;
99 t
.not_writable
= i
.not_writable
;
100 t
.native_endian
= i
.native_endian
;
106 uint32_t get_linear_ram_size() throw()
108 return linear_ram_size
;
111 uint32_t create_region(const std::string
& name
, uint32_t base
, uint8_t* memory
, uint32_t size
, bool readonly
,
112 bool native_endian
= false) throw(std::bad_alloc
)
121 r
.not_writable
= readonly
;
122 r
.native_endian
= native_endian
;
124 linear_ram_size
+= size
;
125 memory_regions
.push_back(r
);
129 uint32_t create_region(const std::string
& name
, uint32_t base
, SNES::MappedRAM
& memory
, bool readonly
,
130 bool native_endian
= false) throw(std::bad_alloc
)
132 return create_region(name
, base
, memory
.data(), memory
.size(), readonly
, native_endian
);
135 uint16_t native_littleendian_convert(uint16_t x
) throw()
137 if(!system_little_endian
)
138 return (((x
>> 8) & 0xFF) | ((x
<< 8) & 0xFF00));
143 uint32_t native_littleendian_convert(uint32_t x
) throw()
145 if(!system_little_endian
)
146 return (((x
>> 24) & 0xFF) | ((x
>> 8) & 0xFF00) |
147 ((x
<< 8) & 0xFF0000) | ((x
<< 24) & 0xFF000000));
152 uint64_t native_littleendian_convert(uint64_t x
) throw()
154 if(!system_little_endian
)
155 return (((x
>> 56) & 0xFF) | ((x
>> 40) & 0xFF00) |
156 ((x
>> 24) & 0xFF0000) | ((x
>> 8) & 0xFF000000) |
157 ((x
<< 8) & 0xFF00000000ULL
) | ((x
<< 24) & 0xFF0000000000ULL
) |
158 ((x
<< 40) & 0xFF000000000000ULL
) | ((x
<< 56) & 0xFF00000000000000ULL
));
164 void refresh_cart_mappings() throw(std::bad_alloc
)
167 memory_regions
.clear();
168 if(get_current_rom_info().first
== ROMTYPE_NONE
)
170 create_region("WRAM", 0x007E0000, SNES::cpu
.wram
, 131072, false);
171 create_region("APURAM", 0x00000000, SNES::smp
.apuram
, 65536, false);
172 create_region("VRAM", 0x00010000, SNES::ppu
.vram
, 65536, false);
173 create_region("OAM", 0x00020000, SNES::ppu
.oam
, 544, false);
174 create_region("CGRAM", 0x00021000, SNES::ppu
.cgram
, 512, false);
175 if(SNES::cartridge
.has_srtc()) create_region("RTC", 0x00022000, SNES::srtc
.rtc
, 20, false);
176 if(SNES::cartridge
.has_spc7110rtc()) create_region("RTC", 0x00022000, SNES::spc7110
.rtc
, 20, false);
177 if(SNES::cartridge
.has_necdsp()) {
178 create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp
.dataRAM
), 4096, false,
180 create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp
.programROM
), 65536, true,
182 create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp
.dataROM
), 4096, true,
185 create_region("SRAM", 0x10000000, SNES::cartridge
.ram
, false);
186 create_region("ROM", 0x80000000, SNES::cartridge
.rom
, true);
187 switch(get_current_rom_info().first
) {
189 case ROMTYPE_BSXSLOTTED
:
190 create_region("BSXFLASH", 0x90000000, SNES::bsxflash
.memory
, true);
191 create_region("BSX_RAM", 0x20000000, SNES::bsxcartridge
.sram
, false);
192 create_region("BSX_PRAM", 0x30000000, SNES::bsxcartridge
.psram
, false);
194 case ROMTYPE_SUFAMITURBO
:
195 create_region("SLOTA_ROM", 0x90000000, SNES::sufamiturbo
.slotA
.rom
, true);
196 create_region("SLOTB_ROM", 0xA0000000, SNES::sufamiturbo
.slotB
.rom
, true);
197 create_region("SLOTA_RAM", 0x20000000, SNES::sufamiturbo
.slotA
.ram
, false);
198 create_region("SLOTB_RAM", 0x30000000, SNES::sufamiturbo
.slotB
.ram
, false);
201 create_region("GBROM", 0x90000000, GameBoy::cartridge
.romdata
, GameBoy::cartridge
.romsize
, true);
202 create_region("GBRAM", 0x20000000, GameBoy::cartridge
.ramdata
, GameBoy::cartridge
.ramsize
, false);
210 std::vector
<struct memory_region
> get_regions() throw(std::bad_alloc
)
212 std::vector
<struct memory_region
> out
;
213 for(auto i
: memory_regions
) {
214 struct memory_region r
;
215 r
.region_name
= i
.name
;
218 r
.lastaddr
= i
.base
+ i
.size
- 1;
219 r
.readonly
= i
.not_writable
;
220 r
.native_endian
= i
.native_endian
;
226 uint8_t memory_read_byte(uint32_t addr
) throw()
228 struct translated_address laddr
= translate_address(addr
);
230 if(laddr
.rel_addr
< laddr
.memory_size
)
231 value
|= laddr
.memory
[laddr
.rel_addr
++];
235 uint16_t memory_read_word(uint32_t addr
) throw()
237 struct translated_address laddr
= translate_address(addr
);
239 if(laddr
.rel_addr
< laddr
.memory_size
)
240 value
|= (static_cast<uint16_t>(laddr
.memory
[laddr
.rel_addr
++]));
241 if(laddr
.rel_addr
< laddr
.memory_size
)
242 value
|= (static_cast<uint16_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
243 if(laddr
.native_endian
)
244 value
= native_littleendian_convert(value
);
248 uint32_t memory_read_dword(uint32_t addr
) throw()
250 struct translated_address laddr
= translate_address(addr
);
252 if(laddr
.rel_addr
< laddr
.memory_size
)
253 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]));
254 if(laddr
.rel_addr
< laddr
.memory_size
)
255 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
256 if(laddr
.rel_addr
< laddr
.memory_size
)
257 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 16);
258 if(laddr
.rel_addr
< laddr
.memory_size
)
259 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 24);
260 if(laddr
.native_endian
)
261 value
= native_littleendian_convert(value
);
265 uint64_t memory_read_qword(uint32_t addr
) throw()
267 struct translated_address laddr
= translate_address(addr
);
269 if(laddr
.rel_addr
< laddr
.memory_size
)
270 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]));
271 if(laddr
.rel_addr
< laddr
.memory_size
)
272 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
273 if(laddr
.rel_addr
< laddr
.memory_size
)
274 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 16);
275 if(laddr
.rel_addr
< laddr
.memory_size
)
276 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 24);
277 if(laddr
.rel_addr
< laddr
.memory_size
)
278 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 32);
279 if(laddr
.rel_addr
< laddr
.memory_size
)
280 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 40);
281 if(laddr
.rel_addr
< laddr
.memory_size
)
282 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 48);
283 if(laddr
.rel_addr
< laddr
.memory_size
)
284 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 56);
285 if(laddr
.native_endian
)
286 value
= native_littleendian_convert(value
);
290 //Byte write to address (false if failed).
291 bool memory_write_byte(uint32_t addr
, uint8_t data
) throw()
293 struct translated_address laddr
= translate_address(addr
);
294 if(laddr
.rel_addr
>= laddr
.memory_size
|| laddr
.not_writable
)
296 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
300 bool memory_write_word(uint32_t addr
, uint16_t data
) throw()
302 struct translated_address laddr
= translate_address(addr
);
303 if(laddr
.native_endian
)
304 data
= native_littleendian_convert(data
);
305 if(laddr
.rel_addr
>= laddr
.memory_size
- 1 || laddr
.not_writable
)
307 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
308 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
312 bool memory_write_dword(uint32_t addr
, uint32_t data
) throw()
314 struct translated_address laddr
= translate_address(addr
);
315 if(laddr
.native_endian
)
316 data
= native_littleendian_convert(data
);
317 if(laddr
.rel_addr
>= laddr
.memory_size
- 3 || laddr
.not_writable
)
319 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
320 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
321 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 16);
322 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 24);
326 bool memory_write_qword(uint32_t addr
, uint64_t data
) throw()
328 struct translated_address laddr
= translate_address(addr
);
329 if(laddr
.native_endian
)
330 data
= native_littleendian_convert(data
);
331 if(laddr
.rel_addr
>= laddr
.memory_size
- 7 || laddr
.not_writable
)
333 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
334 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
335 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 16);
336 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 24);
337 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 32);
338 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 40);
339 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 48);
340 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 56);
344 memorysearch::memorysearch() throw(std::bad_alloc
)
349 void memorysearch::reset() throw(std::bad_alloc
)
351 uint32_t linearram
= get_linear_ram_size();
352 previous_content
.resize(linearram
);
353 still_in
.resize((linearram
+ 63) / 64);
354 for(uint32_t i
= 0; i
< linearram
/ 64; i
++)
355 still_in
[i
] = 0xFFFFFFFFFFFFFFFFULL
;
357 still_in
[linearram
/ 64] = (1ULL << (linearram
% 64)) - 1;
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
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()
390 * \brief Native-value search function for specific 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()
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
428 * \brief Native-value search function for less-than function.
434 * \brief The underlying numeric type
436 typedef T value_type
;
439 * \brief Condition function.
440 * \param oldv The old value
441 * \param newv The new value
442 * \return True if new value satisfies condition, false otherwise.
444 bool operator()(T oldv
, T newv
) const throw()
446 return (newv
< oldv
);
451 * \brief Native-value search function for less-or-equal-to function.
457 * \brief The underlying numeric type
459 typedef T value_type
;
462 * \brief Condition function.
463 * \param oldv The old value
464 * \param newv The new value
465 * \return True if new value satisfies condition, false otherwise.
467 bool operator()(T oldv
, T newv
) const throw()
469 return (newv
<= oldv
);
474 * \brief Native-value search function for equals function.
480 * \brief The underlying numeric type
482 typedef T value_type
;
485 * \brief Condition function.
486 * \param oldv The old value
487 * \param newv The new value
488 * \return True if new value satisfies condition, false otherwise.
490 bool operator()(T oldv
, T newv
) const throw()
492 return (newv
== oldv
);
497 * \brief Native-value search function for not-equal function.
503 * \brief The underlying numeric type
505 typedef T value_type
;
508 * \brief Condition function.
509 * \param oldv The old value
510 * \param newv The new value
511 * \return True if new value satisfies condition, false otherwise.
513 bool operator()(T oldv
, T newv
) const throw()
515 return (newv
!= oldv
);
520 * \brief Native-value search function for greater-or-equal-to function.
526 * \brief The underlying numeric type
528 typedef T value_type
;
531 * \brief Condition function.
532 * \param oldv The old value
533 * \param newv The new value
534 * \return True if new value satisfies condition, false otherwise.
536 bool operator()(T oldv
, T newv
) const throw()
538 return (newv
>= oldv
);
543 * \brief Native-value search function for greater-than function.
549 * \brief The underlying numeric type
551 typedef T value_type
;
554 * \brief Condition function.
555 * \param oldv The old value
556 * \param newv The new value
557 * \return True if new value satisfies condition, false otherwise.
559 bool operator()(T oldv
, T newv
) const throw()
561 return (newv
> oldv
);
566 * \brief Helper class to decode arguments to search functions
568 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
569 * expected for the search function.
572 struct search_value_helper
575 * \brief The underlying numeric type
577 typedef typename
T::value_type value_type
;
580 * \brief Constructor constructing condition object
582 * This constructor takes in condition object with the native-value interface and makes condition object with
583 * interface used by search().
585 * \param v The condition object to wrap.
587 search_value_helper(const T
& v
) throw()
593 * \brief Condition function
595 * This function is search()-compatible condition function calling the underlying condition.
597 bool operator()(const uint8_t* newv
, const uint8_t* oldv
, uint32_t left
, bool nativeendian
) const throw()
599 if(left
< sizeof(value_type
))
604 v1
= *reinterpret_cast<const value_type
*>(oldv
);
605 v2
= *reinterpret_cast<const value_type
*>(newv
);
607 for(size_t i
= 0; i
< sizeof(value_type
); i
++) {
608 v1
|= static_cast<value_type
>(oldv
[i
]) << (8 * i
);
609 v2
|= static_cast<value_type
>(newv
[i
]) << (8 * i
);
615 * \brief The underlying condition.
620 template<class T
> void memorysearch::search(const T
& obj
) throw()
622 search_value_helper
<T
> helper(obj
);
623 struct translated_address t
= translate_address_linear_ram(0);
624 uint32_t switch_at
= t
.memory_size
;
626 uint32_t size
= previous_content
.size();
627 for(uint32_t i
= 0; i
< size
; i
++) {
628 if(still_in
[i
/ 64] == 0) {
629 i
= (i
+ 64) >> 6 << 6;
633 //t.memory_size == 0 can happen if cart changes.
634 while(i
>= switch_at
&& t
.memory_size
> 0) {
635 t
= translate_address_linear_ram(switch_at
);
637 switch_at
+= t
.memory_size
;
639 if(t
.memory_size
== 0 || !helper(t
.memory
+ i
- base
, &previous_content
[i
],
640 t
.memory_size
- (i
- base
), t
.native_endian
)) {
641 if((still_in
[i
/ 64] >> (i
% 64)) & 1) {
642 still_in
[i
/ 64] &= ~(1ULL << (i
% 64));
647 t
= translate_address_linear_ram(0);
649 size
= previous_content
.size();
651 size_t m
= t
.memory_size
;
652 if(m
> (size
- base
))
654 memcpy(&previous_content
[base
], t
.memory
, m
);
655 base
+= t
.memory_size
;
656 t
= translate_address_linear_ram(base
);
660 void memorysearch::byte_value(uint8_t value
) throw() { search(search_value
<uint8_t>(value
)); }
661 void memorysearch::byte_slt() throw() { search(search_lt
<int8_t>()); }
662 void memorysearch::byte_sle() throw() { search(search_le
<int8_t>()); }
663 void memorysearch::byte_seq() throw() { search(search_eq
<int8_t>()); }
664 void memorysearch::byte_sne() throw() { search(search_ne
<int8_t>()); }
665 void memorysearch::byte_sge() throw() { search(search_ge
<int8_t>()); }
666 void memorysearch::byte_sgt() throw() { search(search_gt
<int8_t>()); }
667 void memorysearch::byte_ult() throw() { search(search_lt
<uint8_t>()); }
668 void memorysearch::byte_ule() throw() { search(search_le
<uint8_t>()); }
669 void memorysearch::byte_ueq() throw() { search(search_eq
<uint8_t>()); }
670 void memorysearch::byte_une() throw() { search(search_ne
<uint8_t>()); }
671 void memorysearch::byte_uge() throw() { search(search_ge
<uint8_t>()); }
672 void memorysearch::byte_ugt() throw() { search(search_gt
<uint8_t>()); }
674 void memorysearch::word_value(uint16_t value
) throw() { search(search_value
<uint16_t>(value
)); }
675 void memorysearch::word_slt() throw() { search(search_lt
<int16_t>()); }
676 void memorysearch::word_sle() throw() { search(search_le
<int16_t>()); }
677 void memorysearch::word_seq() throw() { search(search_eq
<int16_t>()); }
678 void memorysearch::word_sne() throw() { search(search_ne
<int16_t>()); }
679 void memorysearch::word_sge() throw() { search(search_ge
<int16_t>()); }
680 void memorysearch::word_sgt() throw() { search(search_gt
<int16_t>()); }
681 void memorysearch::word_ult() throw() { search(search_lt
<uint16_t>()); }
682 void memorysearch::word_ule() throw() { search(search_le
<uint16_t>()); }
683 void memorysearch::word_ueq() throw() { search(search_eq
<uint16_t>()); }
684 void memorysearch::word_une() throw() { search(search_ne
<uint16_t>()); }
685 void memorysearch::word_uge() throw() { search(search_ge
<uint16_t>()); }
686 void memorysearch::word_ugt() throw() { search(search_gt
<uint16_t>()); }
688 void memorysearch::dword_value(uint32_t value
) throw() { search(search_value
<uint32_t>(value
)); }
689 void memorysearch::dword_slt() throw() { search(search_lt
<int32_t>()); }
690 void memorysearch::dword_sle() throw() { search(search_le
<int32_t>()); }
691 void memorysearch::dword_seq() throw() { search(search_eq
<int32_t>()); }
692 void memorysearch::dword_sne() throw() { search(search_ne
<int32_t>()); }
693 void memorysearch::dword_sge() throw() { search(search_ge
<int32_t>()); }
694 void memorysearch::dword_sgt() throw() { search(search_gt
<int32_t>()); }
695 void memorysearch::dword_ult() throw() { search(search_lt
<uint32_t>()); }
696 void memorysearch::dword_ule() throw() { search(search_le
<uint32_t>()); }
697 void memorysearch::dword_ueq() throw() { search(search_eq
<uint32_t>()); }
698 void memorysearch::dword_une() throw() { search(search_ne
<uint32_t>()); }
699 void memorysearch::dword_uge() throw() { search(search_ge
<uint32_t>()); }
700 void memorysearch::dword_ugt() throw() { search(search_gt
<uint32_t>()); }
702 void memorysearch::qword_value(uint64_t value
) throw() { search(search_value
<uint64_t>(value
)); }
703 void memorysearch::qword_slt() throw() { search(search_lt
<int64_t>()); }
704 void memorysearch::qword_sle() throw() { search(search_le
<int64_t>()); }
705 void memorysearch::qword_seq() throw() { search(search_eq
<int64_t>()); }
706 void memorysearch::qword_sne() throw() { search(search_ne
<int64_t>()); }
707 void memorysearch::qword_sge() throw() { search(search_ge
<int64_t>()); }
708 void memorysearch::qword_sgt() throw() { search(search_gt
<int64_t>()); }
709 void memorysearch::qword_ult() throw() { search(search_lt
<uint64_t>()); }
710 void memorysearch::qword_ule() throw() { search(search_le
<uint64_t>()); }
711 void memorysearch::qword_ueq() throw() { search(search_eq
<uint64_t>()); }
712 void memorysearch::qword_une() throw() { search(search_ne
<uint64_t>()); }
713 void memorysearch::qword_uge() throw() { search(search_ge
<uint64_t>()); }
714 void memorysearch::qword_ugt() throw() { search(search_gt
<uint64_t>()); }
716 void memorysearch::update() throw() { search(search_update()); }
718 uint32_t memorysearch::get_candidate_count() throw()
723 std::list
<uint32_t> memorysearch::get_candidates() throw(std::bad_alloc
)
725 struct translated_address t
= translate_address_linear_ram(0);
726 uint32_t switch_at
= t
.memory_size
;
728 uint32_t rbase
= t
.raw_addr
;
729 uint32_t size
= previous_content
.size();
730 std::list
<uint32_t> out
;
732 for(uint32_t i
= 0; i
< size
; i
++) {
733 if(still_in
[i
/ 64] == 0) {
734 i
= (i
+ 64) >> 6 << 6;
738 while(i
>= switch_at
&& t
.memory_size
> 0) {
739 t
= translate_address_linear_ram(switch_at
);
741 rbase
= t
.raw_addr
- t
.rel_addr
;
742 switch_at
+= t
.memory_size
;
744 if((still_in
[i
/ 64] >> (i
% 64)) & 1)
745 out
.push_back(i
- base
+ rbase
);
747 std::cout
<< "out=" << out
.size() << " candidates=" << candidates
<< std::endl
;
755 std::string
tokenize1(const std::string
& command
, const std::string
& syntax
);
756 std::pair
<std::string
, std::string
> tokenize2(const std::string
& command
, const std::string
& syntax
);
757 std::pair
<std::string
, std::string
> tokenize12(const std::string
& command
, const std::string
& syntax
);
759 unsigned char hex(char ch
)
772 case 'a': case 'A': return 10;
773 case 'b': case 'B': return 11;
774 case 'c': case 'C': return 12;
775 case 'd': case 'D': return 13;
776 case 'e': case 'E': return 14;
777 case 'f': case 'F': return 15;
779 throw std::runtime_error("Bad hex character");
782 class memorymanip_command
: public command
785 memorymanip_command(const std::string
& cmd
) throw(std::bad_alloc
)
790 ~memorymanip_command() throw() {}
791 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
793 tokensplitter
t(args
);
794 firstword
= static_cast<std::string
>(t
);
795 secondword
= static_cast<std::string
>(t
);
799 has_value
= (secondword
!= "");
801 if(firstword
.length() >= 2 && firstword
.substr(0, 2) == "0x") {
802 if(firstword
.length() > 10)
805 for(unsigned i
= 2; i
< firstword
.length(); i
++)
806 address
= 16 * address
+ hex(firstword
[i
]);
808 address
= parse_value
<uint32_t>(firstword
);
814 if(secondword
.length() >= 2 && secondword
.substr(0, 2) == "0x") {
815 if(secondword
.length() > 18)
818 for(unsigned i
= 2; i
< secondword
.length(); i
++)
819 value
= 16 * value
+ hex(secondword
[i
]);
820 } else if(secondword
.length() > 0 && secondword
[0] == '-') {
821 value
= static_cast<uint64_t>(parse_value
<int64_t>(secondword
));
823 value
= parse_value
<uint64_t>(secondword
);
830 virtual void invoke2() throw(std::bad_alloc
, std::runtime_error
) = 0;
831 std::string firstword
;
832 std::string secondword
;
839 std::string _command
;
842 template<typename outer
, typename inner
, typename ret
>
843 class read_command
: public memorymanip_command
846 read_command(const std::string
& cmd
, ret (*_rfn
)(uint32_t addr
)) throw(std::bad_alloc
)
847 : memorymanip_command(cmd
)
851 ~read_command() throw() {}
852 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
854 if(address_bad
|| has_value
|| has_tail
)
855 throw std::runtime_error("Syntax: " + _command
+ " <address>");
857 std::ostringstream x
;
858 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
859 << static_cast<outer
>(static_cast<inner
>(rfn(address
)));
860 messages
<< x
.str() << std::endl
;
863 std::string
get_short_help() throw(std::bad_alloc
) { return "Read memory"; }
864 std::string
get_long_help() throw(std::bad_alloc
)
866 return "Syntax: " + _command
+ " <address>\n"
867 "Reads data from memory.\n";
870 ret (*rfn
)(uint32_t addr
);
873 template<typename arg
, int64_t low
, uint64_t high
>
874 class write_command
: public memorymanip_command
877 write_command(const std::string
& cmd
, bool (*_wfn
)(uint32_t addr
, arg a
)) throw(std::bad_alloc
)
878 : memorymanip_command(cmd
)
882 ~write_command() throw() {}
883 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
885 if(address_bad
|| value_bad
|| has_tail
)
886 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
887 if(static_cast<int64_t>(value
) < low
|| value
> high
)
888 throw std::runtime_error("Value to write out of range");
889 wfn(address
, value
& high
);
891 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
892 std::string
get_long_help() throw(std::bad_alloc
)
894 return "Syntax: " + _command
+ " <address> <value>\n"
895 "Writes data to memory.\n";
897 bool (*wfn
)(uint32_t addr
, arg a
);
900 class memorysearch_command
: public memorymanip_command
903 memorysearch_command() throw(std::bad_alloc
) : memorymanip_command("search-memory") {}
904 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
907 isrch
= new memorysearch();
908 if(firstword
== "sblt" && !has_value
)
910 else if(firstword
== "sble" && !has_value
)
912 else if(firstword
== "sbeq" && !has_value
)
914 else if(firstword
== "sbne" && !has_value
)
916 else if(firstword
== "sbge" && !has_value
)
918 else if(firstword
== "sbgt" && !has_value
)
920 else if(firstword
== "ublt" && !has_value
)
922 else if(firstword
== "uble" && !has_value
)
924 else if(firstword
== "ubeq" && !has_value
)
926 else if(firstword
== "ubne" && !has_value
)
928 else if(firstword
== "ubge" && !has_value
)
930 else if(firstword
== "ubgt" && !has_value
)
932 else if(firstword
== "b" && has_value
) {
933 if(static_cast<int64_t>(value
) < -128 || value
> 255)
934 throw std::runtime_error("Value to compare out of range");
935 isrch
->byte_value(value
& 0xFF);
936 } else if(firstword
== "swlt" && !has_value
)
938 else if(firstword
== "swle" && !has_value
)
940 else if(firstword
== "sweq" && !has_value
)
942 else if(firstword
== "swne" && !has_value
)
944 else if(firstword
== "swge" && !has_value
)
946 else if(firstword
== "swgt" && !has_value
)
948 else if(firstword
== "uwlt" && !has_value
)
950 else if(firstword
== "uwle" && !has_value
)
952 else if(firstword
== "uweq" && !has_value
)
954 else if(firstword
== "uwne" && !has_value
)
956 else if(firstword
== "uwge" && !has_value
)
958 else if(firstword
== "uwgt" && !has_value
)
960 else if(firstword
== "w" && has_value
) {
961 if(static_cast<int64_t>(value
) < -32768 || value
> 65535)
962 throw std::runtime_error("Value to compare out of range");
963 isrch
->word_value(value
& 0xFF);
964 } else if(firstword
== "sdlt" && !has_value
)
966 else if(firstword
== "sdle" && !has_value
)
968 else if(firstword
== "sdeq" && !has_value
)
970 else if(firstword
== "sdne" && !has_value
)
972 else if(firstword
== "sdge" && !has_value
)
974 else if(firstword
== "sdgt" && !has_value
)
976 else if(firstword
== "udlt" && !has_value
)
978 else if(firstword
== "udle" && !has_value
)
980 else if(firstword
== "udeq" && !has_value
)
982 else if(firstword
== "udne" && !has_value
)
984 else if(firstword
== "udge" && !has_value
)
986 else if(firstword
== "udgt" && !has_value
)
988 else if(firstword
== "d" && has_value
) {
989 if(static_cast<int64_t>(value
) < -2147483648LL || value
> 4294967295ULL)
990 throw std::runtime_error("Value to compare out of range");
991 isrch
->dword_value(value
& 0xFF);
992 } else if(firstword
== "sqlt" && !has_value
)
994 else if(firstword
== "sqle" && !has_value
)
996 else if(firstword
== "sqeq" && !has_value
)
998 else if(firstword
== "sqne" && !has_value
)
1000 else if(firstword
== "sqge" && !has_value
)
1002 else if(firstword
== "sqgt" && !has_value
)
1004 else if(firstword
== "uqlt" && !has_value
)
1006 else if(firstword
== "uqle" && !has_value
)
1008 else if(firstword
== "uqeq" && !has_value
)
1010 else if(firstword
== "uqne" && !has_value
)
1012 else if(firstword
== "uqge" && !has_value
)
1014 else if(firstword
== "uqgt" && !has_value
)
1016 else if(firstword
== "q" && has_value
)
1017 isrch
->qword_value(value
& 0xFF);
1018 else if(firstword
== "update" && !has_value
)
1020 else if(firstword
== "reset" && !has_value
)
1022 else if(firstword
== "count" && !has_value
)
1024 else if(firstword
== "print" && !has_value
) {
1025 auto c
= isrch
->get_candidates();
1027 std::ostringstream x
;
1028 x
<< "0x" << std::hex
<< std::setw(8) << std::setfill('0') << ci
;
1029 messages
<< x
.str() << std::endl
;
1032 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword
+ "'");
1033 messages
<< isrch
->get_candidate_count() << " candidates remain." << std::endl
;
1035 std::string
get_short_help() throw(std::bad_alloc
) { return "Search memory addresses"; }
1036 std::string
get_long_help() throw(std::bad_alloc
)
1038 return "Syntax: " + _command
+ " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
1039 "Syntax: " + _command
+ " {b,w,d,q} <value>\n"
1040 "Syntax: " + _command
+ " update\n"
1041 "Syntax: " + _command
+ " reset\n"
1042 "Syntax: " + _command
+ " count\n"
1043 "Syntax: " + _command
+ " print\n"
1044 "Searches addresses from memory.\n";
1048 read_command
<uint64_t, uint8_t, uint8_t> ru1("read-byte", memory_read_byte
);
1049 read_command
<uint64_t, uint16_t, uint16_t> ru2("read-word", memory_read_word
);
1050 read_command
<uint64_t, uint32_t, uint32_t> ru4("read-dword", memory_read_dword
);
1051 read_command
<uint64_t, uint64_t, uint64_t> ru8("read-qword", memory_read_qword
);
1052 read_command
<uint64_t, int8_t, uint8_t> rs1("read-sbyte", memory_read_byte
);
1053 read_command
<uint64_t, int16_t, uint16_t> rs2("read-sword", memory_read_word
);
1054 read_command
<uint64_t, int32_t, uint32_t> rs4("read-sdword", memory_read_dword
);
1055 read_command
<uint64_t, int64_t, uint64_t> rs8("read-sqword", memory_read_qword
);
1056 write_command
<uint8_t, -128, 0xFF> w1("write-byte", memory_write_byte
);
1057 write_command
<uint16_t, -32768, 0xFFFF> w2("write-word", memory_write_word
);
1058 write_command
<uint32_t, -2147483648LL, 0xFFFFFFFFULL
> w4("write-dword", memory_write_dword
);
1059 write_command
<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL
> w8("write-qword", memory_write_qword
);