1 #include "core/emucore.hpp"
3 #include "core/command.hpp"
4 #include "core/memorymanip.hpp"
5 #include "core/moviedata.hpp"
6 #include "core/misc.hpp"
7 #include "core/rom.hpp"
8 #include "core/rrdata.hpp"
9 #include "library/string.hpp"
10 #include "library/minmax.hpp"
21 struct translated_address
29 uint8_t (*iospace_rw
)(uint64_t offset
, uint8_t data
, bool write
);
40 uint8_t (*iospace_rw
)(uint64_t offset
, uint8_t data
, bool write
);
43 std::vector
<region
> memory_regions
;
44 uint64_t linear_ram_size
= 0;
45 bool system_little_endian
= true;
47 uint8_t lsnes_mmio_iospace_handler(uint64_t offset
, uint8_t data
, bool write
)
49 if(offset
>= 0 && offset
< 8 && !write
) {
51 uint64_t x
= get_movie().get_current_frame();
52 return x
>> (8 * (offset
& 7));
53 } else if(offset
>= 8 && offset
< 16 && !write
) {
55 uint64_t x
= get_movie().get_frame_count();
56 return x
>> (8 * (offset
& 7));
57 } else if(offset
>= 16 && offset
< 24 && !write
) {
59 uint64_t x
= get_movie().get_lag_frames();
60 return x
>> (8 * (offset
& 7));
61 } else if(offset
>= 24 && offset
< 32 && !write
) {
63 uint64_t x
= rrdata::count();
64 return x
>> (8 * (offset
& 7));
69 struct translated_address
translate_address(uint64_t rawaddr
) throw()
71 struct translated_address t
;
76 t
.not_writable
= true;
77 if((rawaddr
>> 32) == 0xFFFFFFFFULL
) {
79 t
.rel_addr
= rawaddr
& 0xFFFFFFFFULL
;
82 t
.memory_size
= 0x100000000ULL
;
83 t
.not_writable
= false;
84 t
.native_endian
= false;
85 t
.iospace_rw
= lsnes_mmio_iospace_handler
;
88 for(auto i
: memory_regions
) {
89 if(i
.base
> rawaddr
|| i
.base
+ i
.size
<= rawaddr
)
91 t
.rel_addr
= rawaddr
- i
.base
;
94 t
.memory_size
= i
.size
;
95 t
.not_writable
= i
.not_writable
;
96 t
.native_endian
= i
.native_endian
;
97 t
.iospace_rw
= i
.iospace_rw
;
103 struct translated_address
translate_address_linear_ram(uint64_t ramlinaddr
) throw()
105 struct translated_address t
;
110 t
.not_writable
= true;
111 for(auto i
: memory_regions
) {
112 if(i
.not_writable
|| i
.iospace_rw
)
114 if(ramlinaddr
>= i
.size
) {
115 ramlinaddr
-= i
.size
;
118 t
.rel_addr
= ramlinaddr
;
119 t
.raw_addr
= i
.base
+ ramlinaddr
;
121 t
.memory_size
= i
.size
;
122 t
.not_writable
= i
.not_writable
;
123 t
.native_endian
= i
.native_endian
;
129 uint64_t get_linear_ram_size() throw()
131 return linear_ram_size
;
134 uint64_t create_region(const std::string
& name
, uint64_t base
, uint64_t size
,
135 uint8_t (*iospace_rw
)(uint64_t offset
, uint8_t data
, bool write
)) throw(std::bad_alloc
)
144 r
.not_writable
= false;
145 r
.native_endian
= false;
146 r
.iospace_rw
= iospace_rw
;
147 memory_regions
.push_back(r
);
151 uint64_t create_region(const std::string
& name
, uint64_t base
, uint8_t* memory
, uint64_t size
, bool readonly
,
152 bool native_endian
= false) throw(std::bad_alloc
)
161 r
.not_writable
= readonly
;
162 r
.native_endian
= native_endian
;
165 linear_ram_size
+= size
;
166 memory_regions
.push_back(r
);
170 uint8_t native_littleendian_convert(uint8_t x
) throw()
175 uint16_t native_littleendian_convert(uint16_t x
) throw()
177 if(!system_little_endian
)
178 return (((x
>> 8) & 0xFF) | ((x
<< 8) & 0xFF00));
183 uint32_t native_littleendian_convert(uint32_t x
) throw()
185 if(!system_little_endian
)
186 return (((x
>> 24) & 0xFF) | ((x
>> 8) & 0xFF00) |
187 ((x
<< 8) & 0xFF0000) | ((x
<< 24) & 0xFF000000));
192 uint64_t native_littleendian_convert(uint64_t x
) throw()
194 if(!system_little_endian
)
195 return (((x
>> 56) & 0xFF) | ((x
>> 40) & 0xFF00) |
196 ((x
>> 24) & 0xFF0000) | ((x
>> 8) & 0xFF000000) |
197 ((x
<< 8) & 0xFF00000000ULL
) | ((x
<< 24) & 0xFF0000000000ULL
) |
198 ((x
<< 40) & 0xFF000000000000ULL
) | ((x
<< 56) & 0xFF00000000000000ULL
));
204 inline T
memory_read_generic(uint64_t addr
) throw()
206 struct translated_address laddr
= translate_address(addr
);
208 if(laddr
.iospace_rw
) {
209 for(size_t i
= 0; i
< sizeof(T
); i
++)
210 if(laddr
.rel_addr
< laddr
.memory_size
)
211 value
|= laddr
.iospace_rw(laddr
.rel_addr
++, 0, false) << (8 * i
);
213 for(size_t i
= 0; i
< sizeof(T
); i
++)
214 if(laddr
.rel_addr
< laddr
.memory_size
)
215 value
|= laddr
.memory
[laddr
.rel_addr
++] << (8 * i
);
217 if(laddr
.native_endian
)
218 value
= native_littleendian_convert(value
);
223 inline bool memory_write_generic(uint64_t addr
, T data
) throw()
225 struct translated_address laddr
= translate_address(addr
);
226 if(laddr
.native_endian
)
227 data
= native_littleendian_convert(data
);
228 if(laddr
.rel_addr
>= laddr
.memory_size
- (sizeof(T
) - 1) || laddr
.not_writable
)
230 if(laddr
.iospace_rw
) {
231 for(size_t i
= 0; i
< sizeof(T
); i
++)
232 laddr
.iospace_rw(laddr
.rel_addr
++, static_cast<uint8_t>(data
>> (8 * i
)), true);
234 for(size_t i
= 0; i
< sizeof(T
); i
++)
235 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> (8 * i
));
241 void refresh_cart_mappings() throw(std::bad_alloc
)
244 memory_regions
.clear();
245 if(!get_current_rom_info().first
)
247 auto vmalist
= get_vma_list();
248 for(auto i
: vmalist
) {
250 create_region(i
.name
, i
.base
, i
.size
, i
.iospace_rw
);
252 create_region(i
.name
, i
.base
, reinterpret_cast<uint8_t*>(i
.backing_ram
), i
.size
, i
.readonly
,
257 std::vector
<struct memory_region
> get_regions() throw(std::bad_alloc
)
259 std::vector
<struct memory_region
> out
;
260 for(auto i
: memory_regions
) {
261 struct memory_region r
;
262 r
.region_name
= i
.name
;
265 r
.lastaddr
= i
.base
+ i
.size
- 1;
266 r
.readonly
= i
.not_writable
;
267 r
.iospace
= (i
.iospace_rw
!= NULL
);
268 r
.native_endian
= i
.native_endian
;
274 uint8_t memory_read_byte(uint64_t addr
) throw()
276 return memory_read_generic
<uint8_t>(addr
);
279 void memory_read_bytes(uint64_t addr
, uint64_t size
, char* buffer
) throw()
281 struct translated_address laddr
= translate_address(addr
);
282 size_t ssize
= min(static_cast<uint64_t>(size
), laddr
.memory_size
- laddr
.rel_addr
);
284 if(laddr
.iospace_rw
) {
285 for(size_t i
= 0; i
< ssize
; i
++)
286 buffer
[i
] = laddr
.iospace_rw(laddr
.rel_addr
++, 0, false);
288 memcpy(buffer
, laddr
.memory
+ laddr
.rel_addr
, ssize
);
290 memset(buffer
+ ssize
, 0, size
- ssize
);
293 uint16_t memory_read_word(uint64_t addr
) throw()
295 return memory_read_generic
<uint16_t>(addr
);
298 uint32_t memory_read_dword(uint64_t addr
) throw()
300 return memory_read_generic
<uint32_t>(addr
);
303 uint64_t memory_read_qword(uint64_t addr
) throw()
305 return memory_read_generic
<uint64_t>(addr
);
308 //Byte write to address (false if failed).
309 bool memory_write_byte(uint64_t addr
, uint8_t data
) throw()
311 return memory_write_generic
<uint8_t>(addr
, data
);
314 void memory_write_bytes(uint64_t addr
, uint64_t size
, const char* buffer
) throw()
316 struct translated_address laddr
= translate_address(addr
);
317 if(laddr
.not_writable
)
319 size_t ssize
= min(static_cast<uint64_t>(size
), laddr
.memory_size
- laddr
.rel_addr
);
321 if(laddr
.iospace_rw
) {
322 for(size_t i
= 0; i
< ssize
; i
++)
323 laddr
.iospace_rw(laddr
.rel_addr
++, buffer
[i
], true);
325 memcpy(laddr
.memory
+ laddr
.rel_addr
, buffer
, ssize
);
329 bool memory_write_word(uint64_t addr
, uint16_t data
) throw()
331 return memory_write_generic
<uint16_t>(addr
, data
);
334 bool memory_write_dword(uint64_t addr
, uint32_t data
) throw()
336 return memory_write_generic
<uint32_t>(addr
, data
);
339 bool memory_write_qword(uint64_t addr
, uint64_t data
) throw()
341 return memory_write_generic
<uint64_t>(addr
, data
);
344 memorysearch::memorysearch() throw(std::bad_alloc
)
349 void memorysearch::reset() throw(std::bad_alloc
)
351 uint64_t linearram
= get_linear_ram_size();
352 previous_content
.resize(linearram
);
353 still_in
.resize((linearram
+ 63) / 64);
354 for(uint64_t i
= 0; i
< linearram
/ 64; i
++)
355 still_in
[i
] = 0xFFFFFFFFFFFFFFFFULL
;
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 specific difference
431 struct search_difference
434 * \brief The underlying numeric type
436 typedef T value_type
;
439 * \brief Create new search object
441 * \param v The value to search for.
443 search_difference(T v
) throw()
449 * \brief Condition function.
450 * \param oldv The old value
451 * \param newv The new value
452 * \return True if new value satisfies condition, false otherwise.
454 bool operator()(T oldv
, T newv
) const throw()
456 return ((newv
- oldv
) == val
);
460 * \brief The value to look for
466 * \brief Native-value search function for less-than function.
472 * \brief The underlying numeric type
474 typedef T value_type
;
477 * \brief Condition function.
478 * \param oldv The old value
479 * \param newv The new value
480 * \return True if new value satisfies condition, false otherwise.
482 bool operator()(T oldv
, T newv
) const throw()
484 return (newv
< oldv
);
489 * \brief Native-value search function for less-or-equal-to function.
495 * \brief The underlying numeric type
497 typedef T value_type
;
500 * \brief Condition function.
501 * \param oldv The old value
502 * \param newv The new value
503 * \return True if new value satisfies condition, false otherwise.
505 bool operator()(T oldv
, T newv
) const throw()
507 return (newv
<= oldv
);
512 * \brief Native-value search function for equals function.
518 * \brief The underlying numeric type
520 typedef T value_type
;
523 * \brief Condition function.
524 * \param oldv The old value
525 * \param newv The new value
526 * \return True if new value satisfies condition, false otherwise.
528 bool operator()(T oldv
, T newv
) const throw()
530 return (newv
== oldv
);
535 * \brief Native-value search function for not-equal function.
541 * \brief The underlying numeric type
543 typedef T value_type
;
546 * \brief Condition function.
547 * \param oldv The old value
548 * \param newv The new value
549 * \return True if new value satisfies condition, false otherwise.
551 bool operator()(T oldv
, T newv
) const throw()
553 return (newv
!= oldv
);
558 * \brief Native-value search function for greater-or-equal-to function.
564 * \brief The underlying numeric type
566 typedef T value_type
;
569 * \brief Condition function.
570 * \param oldv The old value
571 * \param newv The new value
572 * \return True if new value satisfies condition, false otherwise.
574 bool operator()(T oldv
, T newv
) const throw()
576 return (newv
>= oldv
);
581 * \brief Native-value search function for greater-than function.
587 * \brief The underlying numeric type
589 typedef T value_type
;
592 * \brief Condition function.
593 * \param oldv The old value
594 * \param newv The new value
595 * \return True if new value satisfies condition, false otherwise.
597 bool operator()(T oldv
, T newv
) const throw()
599 return (newv
> oldv
);
604 * \brief Native-value search function for sequence less-than function.
610 * \brief The underlying numeric type
612 typedef T value_type
;
615 * \brief Condition function.
616 * \param oldv The old value
617 * \param newv The new value
618 * \return True if new value satisfies condition, false otherwise.
620 bool operator()(T oldv
, T newv
) const throw()
622 T mask
= (T
)1 << (sizeof(T
) * 8 - 1);
623 T diff
= newv
- oldv
;
624 return ((diff
& mask
) != 0);
629 * \brief Native-value search function for sequence less-or-equal function.
635 * \brief The underlying numeric type
637 typedef T value_type
;
640 * \brief Condition function.
641 * \param oldv The old value
642 * \param newv The new value
643 * \return True if new value satisfies condition, false otherwise.
645 bool operator()(T oldv
, T newv
) const throw()
647 T mask
= (T
)1 << (sizeof(T
) * 8 - 1);
648 T diff
= newv
- oldv
;
649 return ((diff
& mask
) != 0) || (diff
== 0);
654 * \brief Native-value search function for sequence greater-or-equal function.
660 * \brief The underlying numeric type
662 typedef T value_type
;
665 * \brief Condition function.
666 * \param oldv The old value
667 * \param newv The new value
668 * \return True if new value satisfies condition, false otherwise.
670 bool operator()(T oldv
, T newv
) const throw()
672 T mask
= (T
)1 << (sizeof(T
) * 8 - 1);
673 T diff
= newv
- oldv
;
674 return ((diff
& mask
) == 0);
679 * \brief Native-value search function for sequence greater-than function.
685 * \brief The underlying numeric type
687 typedef T value_type
;
690 * \brief Condition function.
691 * \param oldv The old value
692 * \param newv The new value
693 * \return True if new value satisfies condition, false otherwise.
695 bool operator()(T oldv
, T newv
) const throw()
697 T mask
= (T
)1 << (sizeof(T
) * 8 - 1);
698 T diff
= newv
- oldv
;
699 return ((diff
& mask
) == 0) && (diff
!= 0);
705 * \brief Helper class to decode arguments to search functions
707 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
708 * expected for the search function.
711 struct search_value_helper
714 * \brief The underlying numeric type
716 typedef typename
T::value_type value_type
;
719 * \brief Constructor constructing condition object
721 * This constructor takes in condition object with the native-value interface and makes condition object with
722 * interface used by search().
724 * \param v The condition object to wrap.
726 search_value_helper(const T
& v
) throw()
732 * \brief Condition function
734 * This function is search()-compatible condition function calling the underlying condition.
736 bool operator()(const uint8_t* newv
, const uint8_t* oldv
, uint64_t left
, bool nativeendian
) const throw()
738 if(left
< sizeof(value_type
))
743 v1
= *reinterpret_cast<const value_type
*>(oldv
);
744 v2
= *reinterpret_cast<const value_type
*>(newv
);
746 for(size_t i
= 0; i
< sizeof(value_type
); i
++) {
747 v1
|= static_cast<value_type
>(oldv
[i
]) << (8 * i
);
748 v2
|= static_cast<value_type
>(newv
[i
]) << (8 * i
);
754 * \brief The underlying condition.
759 void memorysearch::dq_range(uint64_t first
, uint64_t last
)
761 struct translated_address t
= translate_address_linear_ram(0);
762 uint64_t switch_at
= t
.memory_size
;
764 uint64_t size
= previous_content
.size();
765 for(uint64_t i
= 0; i
< size
; i
++) {
766 if(still_in
[i
/ 64] == 0) {
767 i
= (i
+ 64) >> 6 << 6;
771 //t.memory_size == 0 can happen if cart changes.
772 while(i
>= switch_at
&& t
.memory_size
> 0) {
773 t
= translate_address_linear_ram(switch_at
);
775 switch_at
+= t
.memory_size
;
777 uint64_t addr
= t
.raw_addr
+ (i
- base
);
778 if(t
.memory_size
== 0 || (addr
>= first
&& addr
<= last
)) {
779 if((still_in
[i
/ 64] >> (i
% 64)) & 1) {
780 still_in
[i
/ 64] &= ~(1ULL << (i
% 64));
788 template<class T
> void memorysearch::search(const T
& obj
) throw()
790 search_value_helper
<T
> helper(obj
);
791 struct translated_address t
= translate_address_linear_ram(0);
792 uint64_t switch_at
= t
.memory_size
;
794 uint64_t size
= previous_content
.size();
795 for(uint64_t i
= 0; i
< size
; i
++) {
796 if(still_in
[i
/ 64] == 0) {
797 i
= (i
+ 64) >> 6 << 6;
801 //t.memory_size == 0 can happen if cart changes.
802 while(i
>= switch_at
&& t
.memory_size
> 0) {
803 t
= translate_address_linear_ram(switch_at
);
805 switch_at
+= t
.memory_size
;
807 if(t
.memory_size
== 0 || !helper(t
.memory
+ i
- base
, &previous_content
[i
],
808 t
.memory_size
- (i
- base
), t
.native_endian
)) {
809 if((still_in
[i
/ 64] >> (i
% 64)) & 1) {
810 still_in
[i
/ 64] &= ~(1ULL << (i
% 64));
815 t
= translate_address_linear_ram(0);
817 size
= previous_content
.size();
819 size_t m
= t
.memory_size
;
820 if(m
> (size
- base
))
822 memcpy(&previous_content
[base
], t
.memory
, m
);
823 base
+= t
.memory_size
;
824 t
= translate_address_linear_ram(base
);
828 void memorysearch::byte_value(uint8_t value
) throw() { search(search_value
<uint8_t>(value
)); }
829 void memorysearch::byte_difference(uint8_t value
) throw() { search(search_difference
<uint8_t>(value
)); }
830 void memorysearch::byte_slt() throw() { search(search_lt
<int8_t>()); }
831 void memorysearch::byte_sle() throw() { search(search_le
<int8_t>()); }
832 void memorysearch::byte_seq() throw() { search(search_eq
<int8_t>()); }
833 void memorysearch::byte_sne() throw() { search(search_ne
<int8_t>()); }
834 void memorysearch::byte_sge() throw() { search(search_ge
<int8_t>()); }
835 void memorysearch::byte_sgt() throw() { search(search_gt
<int8_t>()); }
836 void memorysearch::byte_ult() throw() { search(search_lt
<uint8_t>()); }
837 void memorysearch::byte_ule() throw() { search(search_le
<uint8_t>()); }
838 void memorysearch::byte_ueq() throw() { search(search_eq
<uint8_t>()); }
839 void memorysearch::byte_une() throw() { search(search_ne
<uint8_t>()); }
840 void memorysearch::byte_uge() throw() { search(search_ge
<uint8_t>()); }
841 void memorysearch::byte_ugt() throw() { search(search_gt
<uint8_t>()); }
842 void memorysearch::byte_seqlt() throw() { search(search_seqlt
<uint8_t>()); }
843 void memorysearch::byte_seqle() throw() { search(search_seqle
<uint8_t>()); }
844 void memorysearch::byte_seqge() throw() { search(search_seqge
<uint8_t>()); }
845 void memorysearch::byte_seqgt() throw() { search(search_seqgt
<uint8_t>()); }
847 void memorysearch::word_value(uint16_t value
) throw() { search(search_value
<uint16_t>(value
)); }
848 void memorysearch::word_difference(uint16_t value
) throw() { search(search_difference
<uint16_t>(value
)); }
849 void memorysearch::word_slt() throw() { search(search_lt
<int16_t>()); }
850 void memorysearch::word_sle() throw() { search(search_le
<int16_t>()); }
851 void memorysearch::word_seq() throw() { search(search_eq
<int16_t>()); }
852 void memorysearch::word_sne() throw() { search(search_ne
<int16_t>()); }
853 void memorysearch::word_sge() throw() { search(search_ge
<int16_t>()); }
854 void memorysearch::word_sgt() throw() { search(search_gt
<int16_t>()); }
855 void memorysearch::word_ult() throw() { search(search_lt
<uint16_t>()); }
856 void memorysearch::word_ule() throw() { search(search_le
<uint16_t>()); }
857 void memorysearch::word_ueq() throw() { search(search_eq
<uint16_t>()); }
858 void memorysearch::word_une() throw() { search(search_ne
<uint16_t>()); }
859 void memorysearch::word_uge() throw() { search(search_ge
<uint16_t>()); }
860 void memorysearch::word_ugt() throw() { search(search_gt
<uint16_t>()); }
861 void memorysearch::word_seqlt() throw() { search(search_seqlt
<uint16_t>()); }
862 void memorysearch::word_seqle() throw() { search(search_seqle
<uint16_t>()); }
863 void memorysearch::word_seqge() throw() { search(search_seqge
<uint16_t>()); }
864 void memorysearch::word_seqgt() throw() { search(search_seqgt
<uint16_t>()); }
866 void memorysearch::dword_value(uint32_t value
) throw() { search(search_value
<uint32_t>(value
)); }
867 void memorysearch::dword_difference(uint32_t value
) throw() { search(search_difference
<uint32_t>(value
)); }
868 void memorysearch::dword_slt() throw() { search(search_lt
<int32_t>()); }
869 void memorysearch::dword_sle() throw() { search(search_le
<int32_t>()); }
870 void memorysearch::dword_seq() throw() { search(search_eq
<int32_t>()); }
871 void memorysearch::dword_sne() throw() { search(search_ne
<int32_t>()); }
872 void memorysearch::dword_sge() throw() { search(search_ge
<int32_t>()); }
873 void memorysearch::dword_sgt() throw() { search(search_gt
<int32_t>()); }
874 void memorysearch::dword_ult() throw() { search(search_lt
<uint32_t>()); }
875 void memorysearch::dword_ule() throw() { search(search_le
<uint32_t>()); }
876 void memorysearch::dword_ueq() throw() { search(search_eq
<uint32_t>()); }
877 void memorysearch::dword_une() throw() { search(search_ne
<uint32_t>()); }
878 void memorysearch::dword_uge() throw() { search(search_ge
<uint32_t>()); }
879 void memorysearch::dword_ugt() throw() { search(search_gt
<uint32_t>()); }
880 void memorysearch::dword_seqlt() throw() { search(search_seqlt
<uint32_t>()); }
881 void memorysearch::dword_seqle() throw() { search(search_seqle
<uint32_t>()); }
882 void memorysearch::dword_seqge() throw() { search(search_seqge
<uint32_t>()); }
883 void memorysearch::dword_seqgt() throw() { search(search_seqgt
<uint32_t>()); }
885 void memorysearch::qword_value(uint64_t value
) throw() { search(search_value
<uint64_t>(value
)); }
886 void memorysearch::qword_difference(uint64_t value
) throw() { search(search_difference
<uint64_t>(value
)); }
887 void memorysearch::qword_slt() throw() { search(search_lt
<int64_t>()); }
888 void memorysearch::qword_sle() throw() { search(search_le
<int64_t>()); }
889 void memorysearch::qword_seq() throw() { search(search_eq
<int64_t>()); }
890 void memorysearch::qword_sne() throw() { search(search_ne
<int64_t>()); }
891 void memorysearch::qword_sge() throw() { search(search_ge
<int64_t>()); }
892 void memorysearch::qword_sgt() throw() { search(search_gt
<int64_t>()); }
893 void memorysearch::qword_ult() throw() { search(search_lt
<uint64_t>()); }
894 void memorysearch::qword_ule() throw() { search(search_le
<uint64_t>()); }
895 void memorysearch::qword_ueq() throw() { search(search_eq
<uint64_t>()); }
896 void memorysearch::qword_une() throw() { search(search_ne
<uint64_t>()); }
897 void memorysearch::qword_uge() throw() { search(search_ge
<uint64_t>()); }
898 void memorysearch::qword_ugt() throw() { search(search_gt
<uint64_t>()); }
899 void memorysearch::qword_seqlt() throw() { search(search_seqlt
<uint64_t>()); }
900 void memorysearch::qword_seqle() throw() { search(search_seqle
<uint64_t>()); }
901 void memorysearch::qword_seqge() throw() { search(search_seqge
<uint64_t>()); }
902 void memorysearch::qword_seqgt() throw() { search(search_seqgt
<uint64_t>()); }
904 void memorysearch::update() throw() { search(search_update()); }
906 uint64_t memorysearch::get_candidate_count() throw()
911 std::list
<uint64_t> memorysearch::get_candidates() throw(std::bad_alloc
)
913 struct translated_address t
= translate_address_linear_ram(0);
914 uint64_t switch_at
= t
.memory_size
;
916 uint64_t rbase
= t
.raw_addr
;
917 uint64_t size
= previous_content
.size();
918 std::list
<uint64_t> out
;
920 for(uint64_t i
= 0; i
< size
; i
++) {
921 if(still_in
[i
/ 64] == 0) {
922 i
= (i
+ 64) >> 6 << 6;
926 while(i
>= switch_at
&& t
.memory_size
> 0) {
927 t
= translate_address_linear_ram(switch_at
);
929 rbase
= t
.raw_addr
- t
.rel_addr
;
930 switch_at
+= t
.memory_size
;
932 if((still_in
[i
/ 64] >> (i
% 64)) & 1)
933 out
.push_back(i
- base
+ rbase
);
935 std::cout
<< "out=" << out
.size() << " candidates=" << candidates
<< std::endl
;
943 std::string
tokenize1(const std::string
& command
, const std::string
& syntax
);
944 std::pair
<std::string
, std::string
> tokenize2(const std::string
& command
, const std::string
& syntax
);
945 std::pair
<std::string
, std::string
> tokenize12(const std::string
& command
, const std::string
& syntax
);
947 unsigned char hex(char ch
)
960 case 'a': case 'A': return 10;
961 case 'b': case 'B': return 11;
962 case 'c': case 'C': return 12;
963 case 'd': case 'D': return 13;
964 case 'e': case 'E': return 14;
965 case 'f': case 'F': return 15;
967 throw std::runtime_error("Bad hex character");
970 class memorymanip_command
: public command
973 memorymanip_command(const std::string
& cmd
) throw(std::bad_alloc
)
978 ~memorymanip_command() throw() {}
979 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
981 regex_results t
= regex("(([^ \t]+)([ \t]+([^ \t]+)([ \t]+([^ \t].*)?)?)?)?", args
);
984 has_tail
= (t
[6] != "");
987 has_value
= (secondword
!= "");
989 if(t
= regex("0x(.+)", firstword
)) {
990 if(t
[1].length() > 16)
993 for(unsigned i
= 0; i
< t
[1].length(); i
++)
994 address
= 16 * address
+ hex(t
[1][i
]);
996 address
= parse_value
<uint64_t>(firstword
);
1002 if(t
= regex("0x(.+)", secondword
)) {
1003 if(t
[1].length() > 16)
1006 for(unsigned i
= 0; i
< t
[1].length(); i
++)
1007 value
= 16 * value
+ hex(t
[1][i
]);
1008 } else if(regex("-.*", secondword
)) {
1009 value
= static_cast<uint64_t>(parse_value
<int64_t>(secondword
));
1011 value
= parse_value
<uint64_t>(secondword
);
1018 virtual void invoke2() throw(std::bad_alloc
, std::runtime_error
) = 0;
1019 std::string firstword
;
1020 std::string secondword
;
1027 std::string _command
;
1030 template<typename outer
, typename inner
, typename ret
>
1031 class read_command
: public memorymanip_command
1034 read_command(const std::string
& cmd
, ret (*_rfn
)(uint64_t addr
)) throw(std::bad_alloc
)
1035 : memorymanip_command(cmd
)
1039 ~read_command() throw() {}
1040 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
1042 if(address_bad
|| has_value
|| has_tail
)
1043 throw std::runtime_error("Syntax: " + _command
+ " <address>");
1045 std::ostringstream x
;
1046 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
1047 << static_cast<outer
>(static_cast<inner
>(rfn(address
)));
1048 messages
<< x
.str() << std::endl
;
1051 std::string
get_short_help() throw(std::bad_alloc
) { return "Read memory"; }
1052 std::string
get_long_help() throw(std::bad_alloc
)
1054 return "Syntax: " + _command
+ " <address>\n"
1055 "Reads data from memory.\n";
1058 ret (*rfn
)(uint64_t addr
);
1061 template<typename arg
, int64_t low
, uint64_t high
>
1062 class write_command
: public memorymanip_command
1065 write_command(const std::string
& cmd
, bool (*_wfn
)(uint64_t addr
, arg a
)) throw(std::bad_alloc
)
1066 : memorymanip_command(cmd
)
1070 ~write_command() throw() {}
1071 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
1073 if(address_bad
|| value_bad
|| has_tail
)
1074 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
1075 int64_t value2
= static_cast<int64_t>(value
);
1076 if(value2
< low
|| (value
> high
&& value2
>= 0))
1077 throw std::runtime_error("Value to write out of range");
1078 wfn(address
, value
& high
);
1080 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
1081 std::string
get_long_help() throw(std::bad_alloc
)
1083 return "Syntax: " + _command
+ " <address> <value>\n"
1084 "Writes data to memory.\n";
1086 bool (*wfn
)(uint64_t addr
, arg a
);
1089 class memorysearch_command
: public memorymanip_command
1092 memorysearch_command() throw(std::bad_alloc
) : memorymanip_command("search-memory") {}
1093 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
1096 isrch
= new memorysearch();
1097 if(firstword
== "sblt" && !has_value
)
1099 else if(firstword
== "sble" && !has_value
)
1101 else if(firstword
== "sbeq" && !has_value
)
1103 else if(firstword
== "sbne" && !has_value
)
1105 else if(firstword
== "sbge" && !has_value
)
1107 else if(firstword
== "sbgt" && !has_value
)
1109 else if(firstword
== "ublt" && !has_value
)
1111 else if(firstword
== "uble" && !has_value
)
1113 else if(firstword
== "ubeq" && !has_value
)
1115 else if(firstword
== "ubne" && !has_value
)
1117 else if(firstword
== "ubge" && !has_value
)
1119 else if(firstword
== "ubgt" && !has_value
)
1121 else if(firstword
== "bseqlt" && !has_value
)
1122 isrch
->byte_seqlt();
1123 else if(firstword
== "bseqle" && !has_value
)
1124 isrch
->byte_seqle();
1125 else if(firstword
== "bseqge" && !has_value
)
1126 isrch
->byte_seqge();
1127 else if(firstword
== "bseqgt" && !has_value
)
1128 isrch
->byte_seqgt();
1129 else if(firstword
== "b" && has_value
) {
1130 if(static_cast<int64_t>(value
) < -128 || value
> 255)
1131 throw std::runtime_error("Value to compare out of range");
1132 isrch
->byte_value(value
& 0xFF);
1133 } else if(firstword
== "bdiff" && has_value
) {
1134 if(static_cast<int64_t>(value
) < -128 || value
> 255)
1135 throw std::runtime_error("Value to compare out of range");
1136 isrch
->byte_difference(value
& 0xFF);
1137 } else if(firstword
== "swlt" && !has_value
)
1139 else if(firstword
== "swle" && !has_value
)
1141 else if(firstword
== "sweq" && !has_value
)
1143 else if(firstword
== "swne" && !has_value
)
1145 else if(firstword
== "swge" && !has_value
)
1147 else if(firstword
== "swgt" && !has_value
)
1149 else if(firstword
== "uwlt" && !has_value
)
1151 else if(firstword
== "uwle" && !has_value
)
1153 else if(firstword
== "uweq" && !has_value
)
1155 else if(firstword
== "uwne" && !has_value
)
1157 else if(firstword
== "uwge" && !has_value
)
1159 else if(firstword
== "uwgt" && !has_value
)
1161 else if(firstword
== "wseqlt" && !has_value
)
1162 isrch
->word_seqlt();
1163 else if(firstword
== "wseqle" && !has_value
)
1164 isrch
->word_seqle();
1165 else if(firstword
== "wseqge" && !has_value
)
1166 isrch
->word_seqge();
1167 else if(firstword
== "wseqgt" && !has_value
)
1168 isrch
->word_seqgt();
1169 else if(firstword
== "w" && has_value
) {
1170 if(static_cast<int64_t>(value
) < -32768 || value
> 65535)
1171 throw std::runtime_error("Value to compare out of range");
1172 isrch
->word_value(value
& 0xFFFF);
1173 } else if(firstword
== "wdiff" && has_value
) {
1174 if(static_cast<int64_t>(value
) < -32768 || value
> 65535)
1175 throw std::runtime_error("Value to compare out of range");
1176 isrch
->word_difference(value
& 0xFFFF);
1177 } else if(firstword
== "sdlt" && !has_value
)
1179 else if(firstword
== "sdle" && !has_value
)
1181 else if(firstword
== "sdeq" && !has_value
)
1183 else if(firstword
== "sdne" && !has_value
)
1185 else if(firstword
== "sdge" && !has_value
)
1187 else if(firstword
== "sdgt" && !has_value
)
1189 else if(firstword
== "udlt" && !has_value
)
1191 else if(firstword
== "udle" && !has_value
)
1193 else if(firstword
== "udeq" && !has_value
)
1195 else if(firstword
== "udne" && !has_value
)
1197 else if(firstword
== "udge" && !has_value
)
1199 else if(firstword
== "udgt" && !has_value
)
1201 else if(firstword
== "dseqlt" && !has_value
)
1202 isrch
->dword_seqlt();
1203 else if(firstword
== "dseqle" && !has_value
)
1204 isrch
->dword_seqle();
1205 else if(firstword
== "dseqge" && !has_value
)
1206 isrch
->dword_seqge();
1207 else if(firstword
== "dseqgt" && !has_value
)
1208 isrch
->dword_seqgt();
1209 else if(firstword
== "d" && has_value
) {
1210 if(static_cast<int64_t>(value
) < -2147483648LL || value
> 4294967295ULL)
1211 throw std::runtime_error("Value to compare out of range");
1212 isrch
->dword_value(value
& 0xFFFFFFFFULL
);
1213 } else if(firstword
== "ddiff" && has_value
) {
1214 if(static_cast<int64_t>(value
) < -2147483648LL || value
> 4294967295ULL)
1215 throw std::runtime_error("Value to compare out of range");
1216 isrch
->dword_difference(value
& 0xFFFFFFFFULL
);
1217 } else if(firstword
== "sqlt" && !has_value
)
1219 else if(firstword
== "sqle" && !has_value
)
1221 else if(firstword
== "sqeq" && !has_value
)
1223 else if(firstword
== "sqne" && !has_value
)
1225 else if(firstword
== "sqge" && !has_value
)
1227 else if(firstword
== "sqgt" && !has_value
)
1229 else if(firstword
== "uqlt" && !has_value
)
1231 else if(firstword
== "uqle" && !has_value
)
1233 else if(firstword
== "uqeq" && !has_value
)
1235 else if(firstword
== "uqne" && !has_value
)
1237 else if(firstword
== "uqge" && !has_value
)
1239 else if(firstword
== "uqgt" && !has_value
)
1241 else if(firstword
== "qseqlt" && !has_value
)
1242 isrch
->qword_seqlt();
1243 else if(firstword
== "qseqle" && !has_value
)
1244 isrch
->qword_seqle();
1245 else if(firstword
== "qseqge" && !has_value
)
1246 isrch
->qword_seqge();
1247 else if(firstword
== "qseqgt" && !has_value
)
1248 isrch
->qword_seqgt();
1249 else if(firstword
== "q" && has_value
)
1250 isrch
->qword_value(value
);
1251 else if(firstword
== "qdiff" && has_value
)
1252 isrch
->qword_difference(value
);
1253 else if(firstword
== "disqualify" && has_value
)
1254 isrch
->dq_range(value
, value
);
1255 else if(firstword
== "disqualify_vma" && has_value
) {
1256 auto r
= translate_address(value
);
1257 if(r
.memory_size
!= 0)
1258 isrch
->dq_range(r
.raw_addr
- r
.rel_addr
, r
.raw_addr
- r
.rel_addr
+
1260 } else if(firstword
== "update" && !has_value
)
1262 else if(firstword
== "reset" && !has_value
)
1264 else if(firstword
== "count" && !has_value
)
1266 else if(firstword
== "print" && !has_value
) {
1267 auto c
= isrch
->get_candidates();
1269 std::ostringstream x
;
1270 x
<< "0x" << std::hex
<< std::setw(8) << std::setfill('0') << ci
;
1271 messages
<< x
.str() << std::endl
;
1274 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword
+ "'");
1275 messages
<< isrch
->get_candidate_count() << " candidates remain." << std::endl
;
1277 std::string
get_short_help() throw(std::bad_alloc
) { return "Search memory addresses"; }
1278 std::string
get_long_help() throw(std::bad_alloc
)
1280 return "Syntax: " + _command
+ " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
1281 "Syntax: " + _command
+ " {b,w,d,q}seq{lt,le,ge,gt}\n"
1282 "Syntax: " + _command
+ " {b,w,d,q} <value>\n"
1283 "Syntax: " + _command
+ " {b,w,d,q}diff <value>\n"
1284 "Syntax: " + _command
+ " disqualify{,_vma} <address>\n"
1285 "Syntax: " + _command
+ " update\n"
1286 "Syntax: " + _command
+ " reset\n"
1287 "Syntax: " + _command
+ " count\n"
1288 "Syntax: " + _command
+ " print\n"
1289 "Searches addresses from memory.\n";
1293 read_command
<uint64_t, uint8_t, uint8_t> ru1("read-byte", memory_read_byte
);
1294 read_command
<uint64_t, uint16_t, uint16_t> ru2("read-word", memory_read_word
);
1295 read_command
<uint64_t, uint32_t, uint32_t> ru4("read-dword", memory_read_dword
);
1296 read_command
<uint64_t, uint64_t, uint64_t> ru8("read-qword", memory_read_qword
);
1297 read_command
<uint64_t, int8_t, uint8_t> rs1("read-sbyte", memory_read_byte
);
1298 read_command
<uint64_t, int16_t, uint16_t> rs2("read-sword", memory_read_word
);
1299 read_command
<uint64_t, int32_t, uint32_t> rs4("read-sdword", memory_read_dword
);
1300 read_command
<uint64_t, int64_t, uint64_t> rs8("read-sqword", memory_read_qword
);
1301 write_command
<uint8_t, -128, 0xFF> w1("write-byte", memory_write_byte
);
1302 write_command
<uint16_t, -32768, 0xFFFF> w2("write-word", memory_write_word
);
1303 write_command
<uint32_t, -2147483648LL, 0xFFFFFFFFULL
> w4("write-dword", memory_write_dword
);
1304 write_command
<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL
> w8("write-qword", memory_write_qword
);