6 #include <snes/snes.hpp>
8 #include "memorymanip.hpp"
9 #include "fieldsplit.hpp"
13 typedef uint8_t uint8
;
14 typedef uint16_t uint16
;
15 typedef uint32_t uint32
;
17 typedef int16_t int16
;
18 typedef int32_t int32
;
19 #include <nall/platform.hpp>
20 #include <nall/endian.hpp>
21 #include <nall/varint.hpp>
22 #include <nall/bit.hpp>
23 #include <nall/serializer.hpp>
24 #include <nall/property.hpp>
26 #include <ui-libsnes/libsnes.hpp>
32 struct translated_address
52 std::vector
<region
> memory_regions
;
53 uint32_t linear_ram_size
= 0;
54 bool system_little_endian
= true;
56 struct translated_address
translate_address(uint32_t rawaddr
) throw()
58 struct translated_address t
;
63 t
.not_writable
= true;
64 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
65 if(i
->base
> rawaddr
|| i
->base
+ i
->size
<= rawaddr
)
67 t
.rel_addr
= rawaddr
- i
->base
;
70 t
.memory_size
= i
->size
;
71 t
.not_writable
= i
->not_writable
;
72 t
.native_endian
= i
->native_endian
;
78 struct translated_address
translate_address_linear_ram(uint32_t ramlinaddr
) throw()
80 struct translated_address t
;
85 t
.not_writable
= true;
86 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
89 if(ramlinaddr
>= i
->size
) {
90 ramlinaddr
-= i
->size
;
93 t
.rel_addr
= ramlinaddr
;
94 t
.raw_addr
= i
->base
+ ramlinaddr
;
96 t
.memory_size
= i
->size
;
97 t
.not_writable
= i
->not_writable
;
98 t
.native_endian
= i
->native_endian
;
104 uint32_t get_linear_ram_size() throw()
106 return linear_ram_size
;
109 uint32_t create_region(const std::string
& name
, uint32_t base
, uint8_t* memory
, uint32_t size
, bool readonly
,
110 bool native_endian
= false) throw(std::bad_alloc
)
119 r
.not_writable
= readonly
;
120 r
.native_endian
= native_endian
;
122 linear_ram_size
+= size
;
123 memory_regions
.push_back(r
);
127 uint32_t create_region(const std::string
& name
, uint32_t base
, MappedRAM
& memory
, bool readonly
,
128 bool native_endian
= false) throw(std::bad_alloc
)
130 return create_region(name
, base
, memory
.data(), memory
.size(), readonly
, native_endian
);
133 uint16_t native_bigendian_convert(uint16_t x
) throw()
135 if(system_little_endian
)
136 return (((x
>> 8) & 0xFF) | ((x
<< 8) & 0xFF00));
141 uint32_t native_bigendian_convert(uint32_t x
) throw()
143 if(system_little_endian
)
144 return (((x
>> 24) & 0xFF) | ((x
>> 8) & 0xFF00) |
145 ((x
<< 8) & 0xFF0000) | ((x
<< 24) & 0xFF000000));
150 uint64_t native_bigendian_convert(uint64_t x
) throw()
152 if(system_little_endian
)
153 return (((x
>> 56) & 0xFF) | ((x
>> 40) & 0xFF00) |
154 ((x
>> 24) & 0xFF0000) | ((x
>> 8) & 0xFF000000) |
155 ((x
<< 8) & 0xFF00000000ULL
) | ((x
<< 24) & 0xFF0000000000ULL
) |
156 ((x
<< 40) & 0xFF000000000000ULL
) | ((x
<< 56) & 0xFF00000000000000ULL
));
163 void refresh_cart_mappings() throw(std::bad_alloc
)
166 memory_regions
.clear();
167 if(get_current_rom_info().first
== ROMTYPE_NONE
)
169 create_region("WRAM", 0x007E0000, cpu
.wram
, 131072, false);
170 create_region("APURAM", 0x00000000, smp
.apuram
, 65536, false);
171 create_region("VRAM", 0x00010000, ppu
.vram
, 65536, false);
172 create_region("OAM", 0x00020000, ppu
.oam
, 544, false);
173 create_region("CGRAM", 0x00021000, ppu
.cgram
, 512, false);
174 if(cartridge
.has_srtc()) create_region("RTC", 0x00022000, srtc
.rtc
, 20, false);
175 if(cartridge
.has_spc7110rtc()) create_region("RTC", 0x00022000, spc7110
.rtc
, 20, false);
176 if(cartridge
.has_necdsp()) {
177 create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(necdsp
.dataRAM
), 4096, false, true);
178 create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(necdsp
.programROM
), 65536, true,
180 create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(necdsp
.dataROM
), 4096, true, true);
182 create_region("SRAM", 0x10000000, cartridge
.ram
, false);
183 create_region("ROM", 0x80000000, cartridge
.rom
, true);
184 switch(get_current_rom_info().first
) {
186 case ROMTYPE_BSXSLOTTED
:
187 create_region("BSXFLASH", 0x90000000, bsxflash
.memory
, true);
188 create_region("BSX_RAM", 0x20000000, bsxcartridge
.sram
, false);
189 create_region("BSX_PRAM", 0x30000000, bsxcartridge
.psram
, false);
191 case ROMTYPE_SUFAMITURBO
:
192 create_region("SLOTA_ROM", 0x90000000, sufamiturbo
.slotA
.rom
, true);
193 create_region("SLOTB_ROM", 0xA0000000, sufamiturbo
.slotB
.rom
, true);
194 create_region("SLOTA_RAM", 0x20000000, sufamiturbo
.slotA
.ram
, false);
195 create_region("SLOTB_RAM", 0x30000000, sufamiturbo
.slotB
.ram
, false);
198 create_region("GBROM", 0x90000000, GameBoy::cartridge
.romdata
, GameBoy::cartridge
.romsize
, true);
199 create_region("GBRAM", 0x20000000, GameBoy::cartridge
.ramdata
, GameBoy::cartridge
.ramsize
, false);
207 std::vector
<struct memory_region
> get_regions() throw(std::bad_alloc
)
209 std::vector
<struct memory_region
> out
;
210 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
211 struct memory_region r
;
212 r
.region_name
= i
->name
;
213 r
.baseaddr
= i
->base
;
215 r
.lastaddr
= i
->base
+ i
->size
- 1;
216 r
.readonly
= i
->not_writable
;
217 r
.native_endian
= i
->native_endian
;
223 uint8_t memory_read_byte(uint32_t addr
) throw()
225 struct translated_address laddr
= translate_address(addr
);
227 if(laddr
.rel_addr
< laddr
.memory_size
)
228 value
|= laddr
.memory
[laddr
.rel_addr
++];
232 uint16_t memory_read_word(uint32_t addr
) throw()
234 struct translated_address laddr
= translate_address(addr
);
236 if(laddr
.rel_addr
< laddr
.memory_size
)
237 value
|= (static_cast<uint16_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
238 if(laddr
.rel_addr
< laddr
.memory_size
)
239 value
|= (static_cast<uint16_t>(laddr
.memory
[laddr
.rel_addr
++]));
240 if(laddr
.native_endian
)
241 value
= native_bigendian_convert(value
);
245 uint32_t memory_read_dword(uint32_t addr
) throw()
247 struct translated_address laddr
= translate_address(addr
);
249 if(laddr
.rel_addr
< laddr
.memory_size
)
250 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 24);
251 if(laddr
.rel_addr
< laddr
.memory_size
)
252 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 16);
253 if(laddr
.rel_addr
< laddr
.memory_size
)
254 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
255 if(laddr
.rel_addr
< laddr
.memory_size
)
256 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]));
257 if(laddr
.native_endian
)
258 value
= native_bigendian_convert(value
);
262 uint64_t memory_read_qword(uint32_t addr
) throw()
264 struct translated_address laddr
= translate_address(addr
);
266 if(laddr
.rel_addr
< laddr
.memory_size
)
267 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 56);
268 if(laddr
.rel_addr
< laddr
.memory_size
)
269 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 48);
270 if(laddr
.rel_addr
< laddr
.memory_size
)
271 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 40);
272 if(laddr
.rel_addr
< laddr
.memory_size
)
273 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 32);
274 if(laddr
.rel_addr
< laddr
.memory_size
)
275 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 24);
276 if(laddr
.rel_addr
< laddr
.memory_size
)
277 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 16);
278 if(laddr
.rel_addr
< laddr
.memory_size
)
279 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
280 if(laddr
.rel_addr
< laddr
.memory_size
)
281 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]));
282 if(laddr
.native_endian
)
283 value
= native_bigendian_convert(value
);
287 //Byte write to address (false if failed).
288 bool memory_write_byte(uint32_t addr
, uint8_t data
) throw()
290 struct translated_address laddr
= translate_address(addr
);
291 if(laddr
.rel_addr
>= laddr
.memory_size
|| laddr
.not_writable
)
293 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
297 bool memory_write_word(uint32_t addr
, uint16_t data
) throw()
299 struct translated_address laddr
= translate_address(addr
);
300 if(laddr
.native_endian
)
301 data
= native_bigendian_convert(data
);
302 if(laddr
.rel_addr
>= laddr
.memory_size
- 1 || laddr
.not_writable
)
304 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
305 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
309 bool memory_write_dword(uint32_t addr
, uint32_t data
) throw()
311 struct translated_address laddr
= translate_address(addr
);
312 if(laddr
.native_endian
)
313 data
= native_bigendian_convert(data
);
314 if(laddr
.rel_addr
>= laddr
.memory_size
- 3 || laddr
.not_writable
)
316 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 24);
317 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 16);
318 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
319 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
323 bool memory_write_qword(uint32_t addr
, uint64_t data
) throw()
325 struct translated_address laddr
= translate_address(addr
);
326 if(laddr
.native_endian
)
327 data
= native_bigendian_convert(data
);
328 if(laddr
.rel_addr
>= laddr
.memory_size
- 7 || laddr
.not_writable
)
330 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 56);
331 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 48);
332 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 40);
333 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 32);
334 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 24);
335 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 16);
336 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
337 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
341 memorysearch::memorysearch() throw(std::bad_alloc
)
346 void memorysearch::reset() throw(std::bad_alloc
)
348 uint32_t linearram
= get_linear_ram_size();
349 previous_content
.resize(linearram
);
350 still_in
.resize((linearram
+ 63) / 64);
351 for(uint32_t i
= 0; i
< linearram
/ 64; i
++)
352 still_in
[i
] = 0xFFFFFFFFFFFFFFFFULL
;
354 still_in
[linearram
/ 64] = (1ULL << (linearram
% 64)) - 1;
356 while(addr
< linearram
) {
357 struct translated_address t
= translate_address_linear_ram(addr
);
358 memcpy(&previous_content
[addr
], t
.memory
, t
.memory_size
);
359 addr
+= t
.memory_size
;
361 candidates
= linearram
;
365 * \brief Native-value search function for specific value
371 * \brief The underlying numeric type
373 typedef T value_type
;
376 * \brief Create new search object
378 * \param v The value to search for.
380 search_value(T v
) throw()
386 * \brief Condition function.
387 * \param oldv The old value
388 * \param newv The new value
389 * \return True if new value satisfies condition, false otherwise.
391 bool operator()(T oldv
, T newv
) const throw()
393 return (newv
== val
);
397 * \brief The value to look for
403 * \brief Native-value search function for less-than function.
409 * \brief The underlying numeric type
411 typedef T value_type
;
414 * \brief Condition function.
415 * \param oldv The old value
416 * \param newv The new value
417 * \return True if new value satisfies condition, false otherwise.
419 bool operator()(T oldv
, T newv
) const throw()
421 return (newv
< oldv
);
426 * \brief Native-value search function for less-or-equal-to function.
432 * \brief The underlying numeric type
434 typedef T value_type
;
437 * \brief Condition function.
438 * \param oldv The old value
439 * \param newv The new value
440 * \return True if new value satisfies condition, false otherwise.
442 bool operator()(T oldv
, T newv
) const throw()
444 return (newv
<= oldv
);
449 * \brief Native-value search function for equals function.
455 * \brief The underlying numeric type
457 typedef T value_type
;
460 * \brief Condition function.
461 * \param oldv The old value
462 * \param newv The new value
463 * \return True if new value satisfies condition, false otherwise.
465 bool operator()(T oldv
, T newv
) const throw()
467 return (newv
== oldv
);
472 * \brief Native-value search function for not-equal function.
478 * \brief The underlying numeric type
480 typedef T value_type
;
483 * \brief Condition function.
484 * \param oldv The old value
485 * \param newv The new value
486 * \return True if new value satisfies condition, false otherwise.
488 bool operator()(T oldv
, T newv
) const throw()
490 return (newv
!= oldv
);
495 * \brief Native-value search function for greater-or-equal-to function.
501 * \brief The underlying numeric type
503 typedef T value_type
;
506 * \brief Condition function.
507 * \param oldv The old value
508 * \param newv The new value
509 * \return True if new value satisfies condition, false otherwise.
511 bool operator()(T oldv
, T newv
) const throw()
513 return (newv
>= oldv
);
518 * \brief Native-value search function for greater-than function.
524 * \brief The underlying numeric type
526 typedef T value_type
;
529 * \brief Condition function.
530 * \param oldv The old value
531 * \param newv The new value
532 * \return True if new value satisfies condition, false otherwise.
534 bool operator()(T oldv
, T newv
) const throw()
536 return (newv
> oldv
);
541 * \brief Helper class to decode arguments to search functions
543 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
544 * expected for the search function.
547 struct search_value_helper
550 * \brief The underlying numeric type
552 typedef typename
T::value_type value_type
;
555 * \brief Constructor constructing condition object
557 * This constructor takes in condition object with the native-value interface and makes condition object with
558 * interface used by search().
560 * \param v The condition object to wrap.
562 search_value_helper(const T
& v
) throw()
568 * \brief Condition function
570 * This function is search()-compatible condition function calling the underlying condition.
572 bool operator()(const uint8_t* newv
, const uint8_t* oldv
, uint32_t left
, bool nativeendian
) const throw()
574 if(left
< sizeof(value_type
))
579 v1
= *reinterpret_cast<const value_type
*>(oldv
);
580 v2
= *reinterpret_cast<const value_type
*>(newv
);
582 for(size_t i
= 0; i
< sizeof(value_type
); i
++) {
583 v1
|= static_cast<value_type
>(oldv
[i
]) << (8 * (sizeof(value_type
) - i
));
584 v2
|= static_cast<value_type
>(newv
[i
]) << (8 * (sizeof(value_type
) - i
));
590 * \brief The underlying condition.
595 template<class T
> void memorysearch::search(const T
& obj
) throw()
597 search_value_helper
<T
> helper(obj
);
598 struct translated_address t
= translate_address_linear_ram(0);
599 uint32_t switch_at
= t
.memory_size
;
601 uint32_t size
= previous_content
.size();
602 for(uint32_t i
= 0; i
< size
; i
++) {
603 if(still_in
[i
/ 64] == 0) {
604 i
= (i
+ 64) >> 6 << 6;
608 //t.memory_size == 0 can happen if cart changes.
609 while(i
>= switch_at
&& t
.memory_size
> 0) {
610 t
= translate_address_linear_ram(switch_at
);
612 switch_at
+= t
.memory_size
;
614 if(t
.memory_size
== 0 || !helper(t
.memory
+ i
- base
, &previous_content
[i
],
615 t
.memory_size
- (i
- base
), t
.native_endian
)) {
616 if((still_in
[i
/ 64] >> (i
% 64)) & 1) {
617 still_in
[i
/ 64] &= ~(1ULL << (i
% 64));
622 t
= translate_address_linear_ram(0);
624 size
= previous_content
.size();
626 size_t m
= t
.memory_size
;
627 if(m
> (size
- base
))
629 memcpy(&previous_content
[base
], t
.memory
, m
);
630 base
+= t
.memory_size
;
631 t
= translate_address_linear_ram(base
);
635 void memorysearch::byte_value(uint8_t value
) throw() { search(search_value
<uint8_t>(value
)); }
636 void memorysearch::byte_slt() throw() { search(search_lt
<int8_t>()); }
637 void memorysearch::byte_sle() throw() { search(search_le
<int8_t>()); }
638 void memorysearch::byte_seq() throw() { search(search_eq
<int8_t>()); }
639 void memorysearch::byte_sne() throw() { search(search_ne
<int8_t>()); }
640 void memorysearch::byte_sge() throw() { search(search_ge
<int8_t>()); }
641 void memorysearch::byte_sgt() throw() { search(search_gt
<int8_t>()); }
642 void memorysearch::byte_ult() throw() { search(search_lt
<uint8_t>()); }
643 void memorysearch::byte_ule() throw() { search(search_le
<uint8_t>()); }
644 void memorysearch::byte_ueq() throw() { search(search_eq
<uint8_t>()); }
645 void memorysearch::byte_une() throw() { search(search_ne
<uint8_t>()); }
646 void memorysearch::byte_uge() throw() { search(search_ge
<uint8_t>()); }
647 void memorysearch::byte_ugt() throw() { search(search_gt
<uint8_t>()); }
649 void memorysearch::word_value(uint16_t value
) throw() { search(search_value
<uint16_t>(value
)); }
650 void memorysearch::word_slt() throw() { search(search_lt
<int16_t>()); }
651 void memorysearch::word_sle() throw() { search(search_le
<int16_t>()); }
652 void memorysearch::word_seq() throw() { search(search_eq
<int16_t>()); }
653 void memorysearch::word_sne() throw() { search(search_ne
<int16_t>()); }
654 void memorysearch::word_sge() throw() { search(search_ge
<int16_t>()); }
655 void memorysearch::word_sgt() throw() { search(search_gt
<int16_t>()); }
656 void memorysearch::word_ult() throw() { search(search_lt
<uint16_t>()); }
657 void memorysearch::word_ule() throw() { search(search_le
<uint16_t>()); }
658 void memorysearch::word_ueq() throw() { search(search_eq
<uint16_t>()); }
659 void memorysearch::word_une() throw() { search(search_ne
<uint16_t>()); }
660 void memorysearch::word_uge() throw() { search(search_ge
<uint16_t>()); }
661 void memorysearch::word_ugt() throw() { search(search_gt
<uint16_t>()); }
663 void memorysearch::dword_value(uint32_t value
) throw() { search(search_value
<uint32_t>(value
)); }
664 void memorysearch::dword_slt() throw() { search(search_lt
<int32_t>()); }
665 void memorysearch::dword_sle() throw() { search(search_le
<int32_t>()); }
666 void memorysearch::dword_seq() throw() { search(search_eq
<int32_t>()); }
667 void memorysearch::dword_sne() throw() { search(search_ne
<int32_t>()); }
668 void memorysearch::dword_sge() throw() { search(search_ge
<int32_t>()); }
669 void memorysearch::dword_sgt() throw() { search(search_gt
<int32_t>()); }
670 void memorysearch::dword_ult() throw() { search(search_lt
<uint32_t>()); }
671 void memorysearch::dword_ule() throw() { search(search_le
<uint32_t>()); }
672 void memorysearch::dword_ueq() throw() { search(search_eq
<uint32_t>()); }
673 void memorysearch::dword_une() throw() { search(search_ne
<uint32_t>()); }
674 void memorysearch::dword_uge() throw() { search(search_ge
<uint32_t>()); }
675 void memorysearch::dword_ugt() throw() { search(search_gt
<uint32_t>()); }
677 void memorysearch::qword_value(uint64_t value
) throw() { search(search_value
<uint64_t>(value
)); }
678 void memorysearch::qword_slt() throw() { search(search_lt
<int64_t>()); }
679 void memorysearch::qword_sle() throw() { search(search_le
<int64_t>()); }
680 void memorysearch::qword_seq() throw() { search(search_eq
<int64_t>()); }
681 void memorysearch::qword_sne() throw() { search(search_ne
<int64_t>()); }
682 void memorysearch::qword_sge() throw() { search(search_ge
<int64_t>()); }
683 void memorysearch::qword_sgt() throw() { search(search_gt
<int64_t>()); }
684 void memorysearch::qword_ult() throw() { search(search_lt
<uint64_t>()); }
685 void memorysearch::qword_ule() throw() { search(search_le
<uint64_t>()); }
686 void memorysearch::qword_ueq() throw() { search(search_eq
<uint64_t>()); }
687 void memorysearch::qword_une() throw() { search(search_ne
<uint64_t>()); }
688 void memorysearch::qword_uge() throw() { search(search_ge
<uint64_t>()); }
689 void memorysearch::qword_ugt() throw() { search(search_gt
<uint64_t>()); }
691 uint32_t memorysearch::get_candidate_count() throw()
696 std::list
<uint32_t> memorysearch::get_candidates() throw(std::bad_alloc
)
698 struct translated_address t
= translate_address_linear_ram(0);
699 uint32_t switch_at
= t
.memory_size
;
701 uint32_t rbase
= t
.raw_addr
;
702 uint32_t size
= previous_content
.size();
703 std::list
<uint32_t> out
;
705 for(uint32_t i
= 0; i
< size
; i
++) {
706 if(still_in
[i
/ 64] == 0) {
707 i
= (i
+ 64) >> 6 << 6;
711 while(i
>= switch_at
&& t
.memory_size
> 0) {
712 t
= translate_address_linear_ram(switch_at
);
714 rbase
= t
.raw_addr
- t
.rel_addr
;
715 switch_at
+= t
.memory_size
;
717 if((still_in
[i
/ 64] >> (i
% 64)) & 1)
718 out
.push_back(i
- base
+ rbase
);
720 std::cout
<< "out=" << out
.size() << " candidates=" << candidates
<< std::endl
;
728 std::string
tokenize1(const std::string
& command
, const std::string
& syntax
);
729 std::pair
<std::string
, std::string
> tokenize2(const std::string
& command
, const std::string
& syntax
);
730 std::pair
<std::string
, std::string
> tokenize12(const std::string
& command
, const std::string
& syntax
);
732 unsigned char hex(char ch
)
745 case 'a': case 'A': return 10;
746 case 'b': case 'B': return 11;
747 case 'c': case 'C': return 12;
748 case 'd': case 'D': return 13;
749 case 'e': case 'E': return 14;
750 case 'f': case 'F': return 15;
752 throw std::runtime_error("Bad hex character");
755 class memorymanip_command
: public command
758 memorymanip_command(const std::string
& cmd
) throw(std::bad_alloc
)
763 ~memorymanip_command() throw() {}
764 void invoke(const std::string
& args
, window
* win
) throw(std::bad_alloc
, std::runtime_error
)
766 tokensplitter
t(args
);
767 firstword
= static_cast<std::string
>(t
);
768 secondword
= static_cast<std::string
>(t
);
772 has_value
= (secondword
!= "");
774 if(firstword
.length() >= 2 && firstword
.substr(0, 2) == "0x") {
775 if(firstword
.length() > 10)
778 for(unsigned i
= 2; i
< firstword
.length(); i
++)
779 address
= 16 * address
+ hex(firstword
[i
]);
781 address
= parse_value
<uint32_t>(firstword
);
787 if(secondword
.length() >= 2 && secondword
.substr(0, 2) == "0x") {
788 if(secondword
.length() > 18)
791 for(unsigned i
= 2; i
< secondword
.length(); i
++)
792 value
= 16 * value
+ hex(secondword
[i
]);
793 } else if(secondword
.length() > 0 && secondword
[0] == '-') {
794 value
= static_cast<uint64_t>(parse_value
<int64_t>(secondword
));
796 value
= parse_value
<uint64_t>(secondword
);
803 virtual void invoke2(window
* win
) throw(std::bad_alloc
, std::runtime_error
) = 0;
804 std::string firstword
;
805 std::string secondword
;
812 std::string _command
;
815 template<typename outer
, typename inner
, typename ret
>
816 class read_command
: public memorymanip_command
819 read_command(const std::string
& cmd
, ret (*_rfn
)(uint32_t addr
)) throw(std::bad_alloc
)
820 : memorymanip_command(cmd
)
824 ~read_command() throw() {}
825 void invoke2(window
* win
) throw(std::bad_alloc
, std::runtime_error
)
827 if(address_bad
|| has_value
|| has_tail
)
828 throw std::runtime_error("Syntax: " + _command
+ " <address>");
830 std::ostringstream x
;
831 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
832 << static_cast<outer
>(static_cast<inner
>(rfn(address
)));
833 out(win
) << x
.str() << std::endl
;
836 std::string
get_short_help() throw(std::bad_alloc
) { return "Read memory"; }
837 std::string
get_long_help() throw(std::bad_alloc
)
839 return "Syntax: " + _command
+ " <address>\n"
840 "Reads data from memory.\n";
843 ret (*rfn
)(uint32_t addr
);
846 template<typename arg
, int64_t low
, uint64_t high
>
847 class write_command
: public memorymanip_command
850 write_command(const std::string
& cmd
, bool (*_wfn
)(uint32_t addr
, arg a
)) throw(std::bad_alloc
)
851 : memorymanip_command(cmd
)
855 ~write_command() throw() {}
856 void invoke2(window
* win
) throw(std::bad_alloc
, std::runtime_error
)
858 if(address_bad
|| value_bad
|| has_tail
)
859 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
860 if(static_cast<int64_t>(value
) < low
|| value
> high
)
861 throw std::runtime_error("Value to write out of range");
862 wfn(address
, value
& high
);
864 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
865 std::string
get_long_help() throw(std::bad_alloc
)
867 return "Syntax: " + _command
+ " <address> <value>\n"
868 "Writes data to memory.\n";
870 bool (*wfn
)(uint32_t addr
, arg a
);
873 class memorysearch_command
: public memorymanip_command
876 memorysearch_command() throw(std::bad_alloc
) : memorymanip_command("search-memory") {}
877 void invoke2(window
* win
) throw(std::bad_alloc
, std::runtime_error
)
880 isrch
= new memorysearch();
881 if(firstword
== "sblt" && !has_value
)
883 else if(firstword
== "sble" && !has_value
)
885 else if(firstword
== "sbeq" && !has_value
)
887 else if(firstword
== "sbne" && !has_value
)
889 else if(firstword
== "sbge" && !has_value
)
891 else if(firstword
== "sbgt" && !has_value
)
893 else if(firstword
== "ublt" && !has_value
)
895 else if(firstword
== "uble" && !has_value
)
897 else if(firstword
== "ubeq" && !has_value
)
899 else if(firstword
== "ubne" && !has_value
)
901 else if(firstword
== "ubge" && !has_value
)
903 else if(firstword
== "ubgt" && !has_value
)
905 else if(firstword
== "b" && has_value
) {
906 if(static_cast<int64_t>(value
) < -128 || value
> 255)
907 throw std::runtime_error("Value to compare out of range");
908 isrch
->byte_value(value
& 0xFF);
909 } else if(firstword
== "swlt" && !has_value
)
911 else if(firstword
== "swle" && !has_value
)
913 else if(firstword
== "sweq" && !has_value
)
915 else if(firstword
== "swne" && !has_value
)
917 else if(firstword
== "swge" && !has_value
)
919 else if(firstword
== "swgt" && !has_value
)
921 else if(firstword
== "uwlt" && !has_value
)
923 else if(firstword
== "uwle" && !has_value
)
925 else if(firstword
== "uweq" && !has_value
)
927 else if(firstword
== "uwne" && !has_value
)
929 else if(firstword
== "uwge" && !has_value
)
931 else if(firstword
== "uwgt" && !has_value
)
933 else if(firstword
== "w" && has_value
) {
934 if(static_cast<int64_t>(value
) < -32768 || value
> 65535)
935 throw std::runtime_error("Value to compare out of range");
936 isrch
->word_value(value
& 0xFF);
937 } else if(firstword
== "sdlt" && !has_value
)
939 else if(firstword
== "sdle" && !has_value
)
941 else if(firstword
== "sdeq" && !has_value
)
943 else if(firstword
== "sdne" && !has_value
)
945 else if(firstword
== "sdge" && !has_value
)
947 else if(firstword
== "sdgt" && !has_value
)
949 else if(firstword
== "udlt" && !has_value
)
951 else if(firstword
== "udle" && !has_value
)
953 else if(firstword
== "udeq" && !has_value
)
955 else if(firstword
== "udne" && !has_value
)
957 else if(firstword
== "udge" && !has_value
)
959 else if(firstword
== "udgt" && !has_value
)
961 else if(firstword
== "d" && has_value
) {
962 if(static_cast<int64_t>(value
) < -2147483648 || value
> 4294967295ULL)
963 throw std::runtime_error("Value to compare out of range");
964 isrch
->dword_value(value
& 0xFF);
965 } else if(firstword
== "sqlt" && !has_value
)
967 else if(firstword
== "sqle" && !has_value
)
969 else if(firstword
== "sqeq" && !has_value
)
971 else if(firstword
== "sqne" && !has_value
)
973 else if(firstword
== "sqge" && !has_value
)
975 else if(firstword
== "sqgt" && !has_value
)
977 else if(firstword
== "uqlt" && !has_value
)
979 else if(firstword
== "uqle" && !has_value
)
981 else if(firstword
== "uqeq" && !has_value
)
983 else if(firstword
== "uqne" && !has_value
)
985 else if(firstword
== "uqge" && !has_value
)
987 else if(firstword
== "uqgt" && !has_value
)
989 else if(firstword
== "q" && has_value
) {
990 isrch
->qword_value(value
& 0xFF);
991 } else if(firstword
== "reset" && !has_value
)
993 else if(firstword
== "count" && !has_value
)
995 else if(firstword
== "print" && !has_value
) {
996 auto c
= isrch
->get_candidates();
997 for(auto ci
= c
.begin(); ci
!= c
.end(); ci
++) {
998 std::ostringstream x
;
999 x
<< "0x" << std::hex
<< std::setw(8) << std::setfill('0') << *ci
;
1000 out(win
) << x
.str() << std::endl
;
1003 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword
+ "'");
1004 out(win
) << isrch
->get_candidate_count() << " candidates remain." << std::endl
;
1006 std::string
get_short_help() throw(std::bad_alloc
) { return "Search memory addresses"; }
1007 std::string
get_long_help() throw(std::bad_alloc
)
1009 return "Syntax: " + _command
+ " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
1010 "Syntax: " + _command
+ " {b,w,d,q} <value>\n"
1011 "Syntax: " + _command
+ " reset\n"
1012 "Syntax: " + _command
+ " count\n"
1013 "Syntax: " + _command
+ " print\n"
1014 "Searches addresses from memory.\n";
1018 read_command
<uint64_t, uint8_t, uint8_t> ru1("read-byte", memory_read_byte
);
1019 read_command
<uint64_t, uint16_t, uint16_t> ru2("read-word", memory_read_word
);
1020 read_command
<uint64_t, uint32_t, uint32_t> ru4("read-dword", memory_read_dword
);
1021 read_command
<uint64_t, uint64_t, uint64_t> ru8("read-qword", memory_read_qword
);
1022 read_command
<uint64_t, int8_t, uint8_t> rs1("read-sbyte", memory_read_byte
);
1023 read_command
<uint64_t, int16_t, uint16_t> rs2("read-sword", memory_read_word
);
1024 read_command
<uint64_t, int32_t, uint32_t> rs4("read-sdword", memory_read_dword
);
1025 read_command
<uint64_t, int64_t, uint64_t> rs8("read-sqword", memory_read_qword
);
1026 write_command
<uint8_t, -128, 0xFF> w1("write-byte", memory_write_byte
);
1027 write_command
<uint16_t, -32768, 0xFFFF> w2("write-word", memory_write_word
);
1028 write_command
<uint32_t, -2147483648, 0xFFFFFFFFU
> w4("write-dword", memory_write_dword
);
1029 write_command
<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL
> w8("write-qword", memory_write_qword
);