4 #include <snes/snes.hpp>
6 #include "memorymanip.hpp"
7 #include "fieldsplit.hpp"
11 typedef uint8_t uint8
;
12 typedef uint16_t uint16
;
13 typedef uint32_t uint32
;
15 typedef int16_t int16
;
16 typedef int32_t int32
;
17 #include <nall/platform.hpp>
18 #include <nall/endian.hpp>
19 #include <nall/varint.hpp>
20 #include <nall/bit.hpp>
21 #include <nall/serializer.hpp>
22 #include <nall/property.hpp>
24 #include <ui-libsnes/libsnes.hpp>
30 struct translated_address
50 std::vector
<region
> memory_regions
;
51 uint32_t linear_ram_size
= 0;
52 bool system_little_endian
= true;
54 struct translated_address
translate_address(uint32_t rawaddr
) throw()
56 struct translated_address t
;
61 t
.not_writable
= true;
62 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
63 if(i
->base
> rawaddr
|| i
->base
+ i
->size
<= rawaddr
)
65 t
.rel_addr
= rawaddr
- i
->base
;
68 t
.memory_size
= i
->size
;
69 t
.not_writable
= i
->not_writable
;
70 t
.native_endian
= i
->native_endian
;
76 struct translated_address
translate_address_linear_ram(uint32_t ramlinaddr
) throw()
78 struct translated_address t
;
83 t
.not_writable
= true;
84 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
87 if(ramlinaddr
>= i
->size
) {
88 ramlinaddr
-= i
->size
;
91 t
.rel_addr
= ramlinaddr
;
92 t
.raw_addr
= i
->base
+ ramlinaddr
;
94 t
.memory_size
= i
->size
;
95 t
.not_writable
= i
->not_writable
;
96 t
.native_endian
= i
->native_endian
;
102 uint32_t get_linear_ram_size() throw()
104 return linear_ram_size
;
107 uint32_t create_region(const std::string
& name
, uint32_t base
, uint8_t* memory
, uint32_t size
, bool readonly
,
108 bool native_endian
= false) throw(std::bad_alloc
)
117 r
.not_writable
= readonly
;
118 r
.native_endian
= native_endian
;
120 linear_ram_size
+= size
;
121 memory_regions
.push_back(r
);
125 uint32_t create_region(const std::string
& name
, uint32_t base
, MappedRAM
& memory
, bool readonly
,
126 bool native_endian
= false) throw(std::bad_alloc
)
128 return create_region(name
, base
, memory
.data(), memory
.size(), readonly
, native_endian
);
131 uint16_t native_bigendian_convert(uint16_t x
) throw()
133 if(system_little_endian
)
134 return (((x
>> 8) & 0xFF) | ((x
<< 8) & 0xFF00));
139 uint32_t native_bigendian_convert(uint32_t x
) throw()
141 if(system_little_endian
)
142 return (((x
>> 24) & 0xFF) | ((x
>> 8) & 0xFF00) |
143 ((x
<< 8) & 0xFF0000) | ((x
<< 24) & 0xFF000000));
148 uint64_t native_bigendian_convert(uint64_t x
) throw()
150 if(system_little_endian
)
151 return (((x
>> 56) & 0xFF) | ((x
>> 40) & 0xFF00) |
152 ((x
>> 24) & 0xFF0000) | ((x
>> 8) & 0xFF000000) |
153 ((x
<< 8) & 0xFF00000000ULL
) | ((x
<< 24) & 0xFF0000000000ULL
) |
154 ((x
<< 40) & 0xFF000000000000ULL
) | ((x
<< 56) & 0xFF00000000000000ULL
));
161 void refresh_cart_mappings() throw(std::bad_alloc
)
164 memory_regions
.clear();
165 if(get_current_rom_info().first
== ROMTYPE_NONE
)
167 create_region("WRAM", 0x007E0000, cpu
.wram
, 131072, false);
168 create_region("APURAM", 0x00000000, smp
.apuram
, 65536, false);
169 create_region("VRAM", 0x00010000, ppu
.vram
, 65536, false);
170 create_region("OAM", 0x00020000, ppu
.oam
, 544, false);
171 create_region("CGRAM", 0x00021000, ppu
.cgram
, 512, false);
172 if(cartridge
.has_srtc()) create_region("RTC", 0x00022000, srtc
.rtc
, 20, false);
173 if(cartridge
.has_spc7110rtc()) create_region("RTC", 0x00022000, spc7110
.rtc
, 20, false);
174 if(cartridge
.has_necdsp()) {
175 create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(necdsp
.dataRAM
), 4096, false, true);
176 create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(necdsp
.programROM
), 65536, true,
178 create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(necdsp
.dataROM
), 4096, true, true);
180 create_region("SRAM", 0x10000000, cartridge
.ram
, false);
181 create_region("ROM", 0x80000000, cartridge
.rom
, true);
182 switch(get_current_rom_info().first
) {
184 case ROMTYPE_BSXSLOTTED
:
185 create_region("BSXFLASH", 0x90000000, bsxflash
.memory
, true);
186 create_region("BSX_RAM", 0x20000000, bsxcartridge
.sram
, false);
187 create_region("BSX_PRAM", 0x30000000, bsxcartridge
.psram
, false);
189 case ROMTYPE_SUFAMITURBO
:
190 create_region("SLOTA_ROM", 0x90000000, sufamiturbo
.slotA
.rom
, true);
191 create_region("SLOTB_ROM", 0xA0000000, sufamiturbo
.slotB
.rom
, true);
192 create_region("SLOTA_RAM", 0x20000000, sufamiturbo
.slotA
.ram
, false);
193 create_region("SLOTB_RAM", 0x30000000, sufamiturbo
.slotB
.ram
, false);
196 create_region("GBROM", 0x90000000, GameBoy::cartridge
.romdata
, GameBoy::cartridge
.romsize
, true);
197 create_region("GBRAM", 0x20000000, GameBoy::cartridge
.ramdata
, GameBoy::cartridge
.ramsize
, false);
205 std::vector
<struct memory_region
> get_regions() throw(std::bad_alloc
)
207 std::vector
<struct memory_region
> out
;
208 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
209 struct memory_region r
;
210 r
.region_name
= i
->name
;
211 r
.baseaddr
= i
->base
;
213 r
.lastaddr
= i
->base
+ i
->size
- 1;
214 r
.readonly
= i
->not_writable
;
215 r
.native_endian
= i
->native_endian
;
221 uint8_t memory_read_byte(uint32_t addr
) throw()
223 struct translated_address laddr
= translate_address(addr
);
225 if(laddr
.rel_addr
< laddr
.memory_size
)
226 value
|= laddr
.memory
[laddr
.rel_addr
++];
230 uint16_t memory_read_word(uint32_t addr
) throw()
232 struct translated_address laddr
= translate_address(addr
);
234 if(laddr
.rel_addr
< laddr
.memory_size
)
235 value
|= (static_cast<uint16_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
236 if(laddr
.rel_addr
< laddr
.memory_size
)
237 value
|= (static_cast<uint16_t>(laddr
.memory
[laddr
.rel_addr
++]));
238 if(laddr
.native_endian
)
239 value
= native_bigendian_convert(value
);
243 uint32_t memory_read_dword(uint32_t addr
) throw()
245 struct translated_address laddr
= translate_address(addr
);
247 if(laddr
.rel_addr
< laddr
.memory_size
)
248 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 24);
249 if(laddr
.rel_addr
< laddr
.memory_size
)
250 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 16);
251 if(laddr
.rel_addr
< laddr
.memory_size
)
252 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
253 if(laddr
.rel_addr
< laddr
.memory_size
)
254 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]));
255 if(laddr
.native_endian
)
256 value
= native_bigendian_convert(value
);
260 uint64_t memory_read_qword(uint32_t addr
) throw()
262 struct translated_address laddr
= translate_address(addr
);
264 if(laddr
.rel_addr
< laddr
.memory_size
)
265 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 56);
266 if(laddr
.rel_addr
< laddr
.memory_size
)
267 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 48);
268 if(laddr
.rel_addr
< laddr
.memory_size
)
269 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 40);
270 if(laddr
.rel_addr
< laddr
.memory_size
)
271 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 32);
272 if(laddr
.rel_addr
< laddr
.memory_size
)
273 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 24);
274 if(laddr
.rel_addr
< laddr
.memory_size
)
275 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 16);
276 if(laddr
.rel_addr
< laddr
.memory_size
)
277 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
278 if(laddr
.rel_addr
< laddr
.memory_size
)
279 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]));
280 if(laddr
.native_endian
)
281 value
= native_bigendian_convert(value
);
285 //Byte write to address (false if failed).
286 bool memory_write_byte(uint32_t addr
, uint8_t data
) throw()
288 struct translated_address laddr
= translate_address(addr
);
289 if(laddr
.rel_addr
>= laddr
.memory_size
|| laddr
.not_writable
)
291 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
295 bool memory_write_word(uint32_t addr
, uint16_t data
) throw()
297 struct translated_address laddr
= translate_address(addr
);
298 if(laddr
.native_endian
)
299 data
= native_bigendian_convert(data
);
300 if(laddr
.rel_addr
>= laddr
.memory_size
- 1 || laddr
.not_writable
)
302 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
303 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
307 bool memory_write_dword(uint32_t addr
, uint32_t data
) throw()
309 struct translated_address laddr
= translate_address(addr
);
310 if(laddr
.native_endian
)
311 data
= native_bigendian_convert(data
);
312 if(laddr
.rel_addr
>= laddr
.memory_size
- 3 || laddr
.not_writable
)
314 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 24);
315 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 16);
316 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
317 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
321 bool memory_write_qword(uint32_t addr
, uint64_t data
) throw()
323 struct translated_address laddr
= translate_address(addr
);
324 if(laddr
.native_endian
)
325 data
= native_bigendian_convert(data
);
326 if(laddr
.rel_addr
>= laddr
.memory_size
- 7 || laddr
.not_writable
)
328 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 56);
329 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 48);
330 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 40);
331 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 32);
332 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 24);
333 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 16);
334 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
335 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
339 memorysearch::memorysearch() throw(std::bad_alloc
)
344 void memorysearch::reset() throw(std::bad_alloc
)
346 uint32_t linearram
= get_linear_ram_size();
347 previous_content
.resize(linearram
);
348 still_in
.resize((linearram
+ 63) / 64);
349 for(uint32_t i
= 0; i
< linearram
/ 64; i
++)
350 still_in
[i
] = 0xFFFFFFFFFFFFFFFFULL
;
352 still_in
[linearram
/ 64] = (1ULL << (linearram
% 64)) - 1;
354 while(addr
< linearram
) {
355 struct translated_address t
= translate_address_linear_ram(addr
);
356 memcpy(&previous_content
[addr
], t
.memory
, t
.memory_size
);
357 addr
+= t
.memory_size
;
359 candidates
= linearram
;
363 * \brief Native-value search function for specific value
369 * \brief The underlying numeric type
371 typedef T value_type
;
374 * \brief Create new search object
376 * \param v The value to search for.
378 search_value(T v
) throw()
384 * \brief Condition function.
385 * \param oldv The old value
386 * \param newv The new value
387 * \return True if new value satisfies condition, false otherwise.
389 bool operator()(T oldv
, T newv
) const throw()
391 return (newv
== val
);
395 * \brief The value to look for
401 * \brief Native-value search function for less-than function.
407 * \brief The underlying numeric type
409 typedef T value_type
;
412 * \brief Condition function.
413 * \param oldv The old value
414 * \param newv The new value
415 * \return True if new value satisfies condition, false otherwise.
417 bool operator()(T oldv
, T newv
) const throw()
419 return (newv
< oldv
);
424 * \brief Native-value search function for less-or-equal-to function.
430 * \brief The underlying numeric type
432 typedef T value_type
;
435 * \brief Condition function.
436 * \param oldv The old value
437 * \param newv The new value
438 * \return True if new value satisfies condition, false otherwise.
440 bool operator()(T oldv
, T newv
) const throw()
442 return (newv
<= oldv
);
447 * \brief Native-value search function for equals function.
453 * \brief The underlying numeric type
455 typedef T value_type
;
458 * \brief Condition function.
459 * \param oldv The old value
460 * \param newv The new value
461 * \return True if new value satisfies condition, false otherwise.
463 bool operator()(T oldv
, T newv
) const throw()
465 return (newv
== oldv
);
470 * \brief Native-value search function for not-equal function.
476 * \brief The underlying numeric type
478 typedef T value_type
;
481 * \brief Condition function.
482 * \param oldv The old value
483 * \param newv The new value
484 * \return True if new value satisfies condition, false otherwise.
486 bool operator()(T oldv
, T newv
) const throw()
488 return (newv
!= oldv
);
493 * \brief Native-value search function for greater-or-equal-to function.
499 * \brief The underlying numeric type
501 typedef T value_type
;
504 * \brief Condition function.
505 * \param oldv The old value
506 * \param newv The new value
507 * \return True if new value satisfies condition, false otherwise.
509 bool operator()(T oldv
, T newv
) const throw()
511 return (newv
>= oldv
);
516 * \brief Native-value search function for greater-than function.
522 * \brief The underlying numeric type
524 typedef T value_type
;
527 * \brief Condition function.
528 * \param oldv The old value
529 * \param newv The new value
530 * \return True if new value satisfies condition, false otherwise.
532 bool operator()(T oldv
, T newv
) const throw()
534 return (newv
> oldv
);
539 * \brief Helper class to decode arguments to search functions
541 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
542 * expected for the search function.
545 struct search_value_helper
548 * \brief The underlying numeric type
550 typedef typename
T::value_type value_type
;
553 * \brief Constructor constructing condition object
555 * This constructor takes in condition object with the native-value interface and makes condition object with
556 * interface used by search().
558 * \param v The condition object to wrap.
560 search_value_helper(const T
& v
) throw()
566 * \brief Condition function
568 * This function is search()-compatible condition function calling the underlying condition.
570 bool operator()(const uint8_t* newv
, const uint8_t* oldv
, uint32_t left
, bool nativeendian
) const throw()
572 if(left
< sizeof(value_type
))
577 v1
= *reinterpret_cast<const value_type
*>(oldv
);
578 v2
= *reinterpret_cast<const value_type
*>(newv
);
580 for(size_t i
= 0; i
< sizeof(value_type
); i
++) {
581 v1
|= static_cast<value_type
>(oldv
[i
]) << (8 * (sizeof(value_type
) - i
));
582 v2
|= static_cast<value_type
>(newv
[i
]) << (8 * (sizeof(value_type
) - i
));
588 * \brief The underlying condition.
593 template<class T
> void memorysearch::search(const T
& obj
) throw()
595 search_value_helper
<T
> helper(obj
);
596 struct translated_address t
= translate_address_linear_ram(0);
597 uint32_t switch_at
= t
.memory_size
;
599 uint32_t size
= previous_content
.size();
600 for(uint32_t i
= 0; i
< size
; i
++) {
601 if(still_in
[i
/ 64] == 0) {
602 i
= (i
+ 64) >> 6 << 6;
606 //t.memory_size == 0 can happen if cart changes.
607 while(i
>= switch_at
&& t
.memory_size
> 0) {
608 t
= translate_address_linear_ram(switch_at
);
610 switch_at
+= t
.memory_size
;
612 if(t
.memory_size
== 0 || !helper(t
.memory
+ i
- base
, &previous_content
[i
],
613 t
.memory_size
- (i
- base
), t
.native_endian
)) {
614 if((still_in
[i
/ 64] >> (i
% 64)) & 1) {
615 still_in
[i
/ 64] &= ~(1ULL << (i
% 64));
620 t
= translate_address_linear_ram(0);
622 size
= previous_content
.size();
624 size_t m
= t
.memory_size
;
625 if(m
> (size
- base
))
627 memcpy(&previous_content
[base
], t
.memory
, m
);
628 base
+= t
.memory_size
;
629 t
= translate_address_linear_ram(base
);
633 void memorysearch::byte_value(uint8_t value
) throw() { search(search_value
<uint8_t>(value
)); }
634 void memorysearch::byte_slt() throw() { search(search_lt
<int8_t>()); }
635 void memorysearch::byte_sle() throw() { search(search_le
<int8_t>()); }
636 void memorysearch::byte_seq() throw() { search(search_eq
<int8_t>()); }
637 void memorysearch::byte_sne() throw() { search(search_ne
<int8_t>()); }
638 void memorysearch::byte_sge() throw() { search(search_ge
<int8_t>()); }
639 void memorysearch::byte_sgt() throw() { search(search_gt
<int8_t>()); }
640 void memorysearch::byte_ult() throw() { search(search_lt
<uint8_t>()); }
641 void memorysearch::byte_ule() throw() { search(search_le
<uint8_t>()); }
642 void memorysearch::byte_ueq() throw() { search(search_eq
<uint8_t>()); }
643 void memorysearch::byte_une() throw() { search(search_ne
<uint8_t>()); }
644 void memorysearch::byte_uge() throw() { search(search_ge
<uint8_t>()); }
645 void memorysearch::byte_ugt() throw() { search(search_gt
<uint8_t>()); }
647 void memorysearch::word_value(uint16_t value
) throw() { search(search_value
<uint16_t>(value
)); }
648 void memorysearch::word_slt() throw() { search(search_lt
<int16_t>()); }
649 void memorysearch::word_sle() throw() { search(search_le
<int16_t>()); }
650 void memorysearch::word_seq() throw() { search(search_eq
<int16_t>()); }
651 void memorysearch::word_sne() throw() { search(search_ne
<int16_t>()); }
652 void memorysearch::word_sge() throw() { search(search_ge
<int16_t>()); }
653 void memorysearch::word_sgt() throw() { search(search_gt
<int16_t>()); }
654 void memorysearch::word_ult() throw() { search(search_lt
<uint16_t>()); }
655 void memorysearch::word_ule() throw() { search(search_le
<uint16_t>()); }
656 void memorysearch::word_ueq() throw() { search(search_eq
<uint16_t>()); }
657 void memorysearch::word_une() throw() { search(search_ne
<uint16_t>()); }
658 void memorysearch::word_uge() throw() { search(search_ge
<uint16_t>()); }
659 void memorysearch::word_ugt() throw() { search(search_gt
<uint16_t>()); }
661 void memorysearch::dword_value(uint32_t value
) throw() { search(search_value
<uint32_t>(value
)); }
662 void memorysearch::dword_slt() throw() { search(search_lt
<int32_t>()); }
663 void memorysearch::dword_sle() throw() { search(search_le
<int32_t>()); }
664 void memorysearch::dword_seq() throw() { search(search_eq
<int32_t>()); }
665 void memorysearch::dword_sne() throw() { search(search_ne
<int32_t>()); }
666 void memorysearch::dword_sge() throw() { search(search_ge
<int32_t>()); }
667 void memorysearch::dword_sgt() throw() { search(search_gt
<int32_t>()); }
668 void memorysearch::dword_ult() throw() { search(search_lt
<uint32_t>()); }
669 void memorysearch::dword_ule() throw() { search(search_le
<uint32_t>()); }
670 void memorysearch::dword_ueq() throw() { search(search_eq
<uint32_t>()); }
671 void memorysearch::dword_une() throw() { search(search_ne
<uint32_t>()); }
672 void memorysearch::dword_uge() throw() { search(search_ge
<uint32_t>()); }
673 void memorysearch::dword_ugt() throw() { search(search_gt
<uint32_t>()); }
675 void memorysearch::qword_value(uint64_t value
) throw() { search(search_value
<uint64_t>(value
)); }
676 void memorysearch::qword_slt() throw() { search(search_lt
<int64_t>()); }
677 void memorysearch::qword_sle() throw() { search(search_le
<int64_t>()); }
678 void memorysearch::qword_seq() throw() { search(search_eq
<int64_t>()); }
679 void memorysearch::qword_sne() throw() { search(search_ne
<int64_t>()); }
680 void memorysearch::qword_sge() throw() { search(search_ge
<int64_t>()); }
681 void memorysearch::qword_sgt() throw() { search(search_gt
<int64_t>()); }
682 void memorysearch::qword_ult() throw() { search(search_lt
<uint64_t>()); }
683 void memorysearch::qword_ule() throw() { search(search_le
<uint64_t>()); }
684 void memorysearch::qword_ueq() throw() { search(search_eq
<uint64_t>()); }
685 void memorysearch::qword_une() throw() { search(search_ne
<uint64_t>()); }
686 void memorysearch::qword_uge() throw() { search(search_ge
<uint64_t>()); }
687 void memorysearch::qword_ugt() throw() { search(search_gt
<uint64_t>()); }
689 uint32_t memorysearch::get_candidate_count() throw()
694 std::list
<uint32_t> memorysearch::get_candidates() throw(std::bad_alloc
)
696 struct translated_address t
= translate_address_linear_ram(0);
697 uint32_t switch_at
= t
.memory_size
;
699 uint32_t rbase
= t
.raw_addr
;
700 uint32_t size
= previous_content
.size();
701 std::list
<uint32_t> out
;
703 for(uint32_t i
= 0; i
< size
; i
++) {
704 if(still_in
[i
/ 64] == 0) {
705 i
= (i
+ 64) >> 6 << 6;
709 while(i
>= switch_at
&& t
.memory_size
> 0) {
710 t
= translate_address_linear_ram(switch_at
);
712 rbase
= t
.raw_addr
- t
.rel_addr
;
713 switch_at
+= t
.memory_size
;
715 if((still_in
[i
/ 64] >> (i
% 64)) & 1)
716 out
.push_back(i
- base
+ rbase
);
718 std::cout
<< "out=" << out
.size() << " candidates=" << candidates
<< std::endl
;
726 std::string
tokenize1(const std::string
& command
, const std::string
& syntax
);
727 std::pair
<std::string
, std::string
> tokenize2(const std::string
& command
, const std::string
& syntax
);
728 std::pair
<std::string
, std::string
> tokenize12(const std::string
& command
, const std::string
& syntax
);
730 unsigned char hex(char ch
)
743 case 'a': case 'A': return 10;
744 case 'b': case 'B': return 11;
745 case 'c': case 'C': return 12;
746 case 'd': case 'D': return 13;
747 case 'e': case 'E': return 14;
748 case 'f': case 'F': return 15;
750 throw std::runtime_error("Bad hex character");
755 bool memorymanip_command(const std::string
& cmd
, window
* win
) throw(std::bad_alloc
, std::runtime_error
)
757 tokensplitter
t(cmd
);
758 std::string command
= t
;
759 std::string firstword
= t
;
760 std::string secondword
= t
;
763 bool has_tail
= (t
.tail() != "");
764 bool address_bad
= true;
765 bool value_bad
= true;
766 bool has_value
= (secondword
!= "");
768 if(firstword
.length() >= 2 && firstword
.substr(0, 2) == "0x") {
769 if(firstword
.length() > 10)
772 for(unsigned i
= 2; i
< firstword
.length(); i
++)
773 address
= 16 * address
+ hex(firstword
[i
]);
775 address
= parse_value
<uint32_t>(firstword
);
781 if(secondword
.length() >= 2 && secondword
.substr(0, 2) == "0x") {
782 if(secondword
.length() > 18)
785 for(unsigned i
= 2; i
< secondword
.length(); i
++)
786 value
= 16 * value
+ hex(secondword
[i
]);
787 } else if(secondword
.length() > 0 && secondword
[0] == '-') {
788 value
= static_cast<uint64_t>(parse_value
<int64_t>(secondword
));
790 value
= parse_value
<uint64_t>(secondword
);
795 if(command
== "read-byte") {
796 if(address_bad
|| has_value
|| has_tail
)
797 throw std::runtime_error("Syntax: " + command
+ " <address>");
799 std::ostringstream x
;
800 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
801 << static_cast<uint64_t>(memory_read_byte(address
));
802 out(win
) << x
.str() << std::endl
;
806 if(command
== "read-word") {
807 if(address_bad
|| has_value
|| has_tail
)
808 throw std::runtime_error("Syntax: " + command
+ " <address>");
810 std::ostringstream x
;
811 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
812 << static_cast<uint64_t>(memory_read_word(address
));
813 out(win
) << x
.str() << std::endl
;
817 if(command
== "read-dword") {
818 if(address_bad
|| has_value
|| has_tail
)
819 throw std::runtime_error("Syntax: " + command
+ " <address>");
821 std::ostringstream x
;
822 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
823 << static_cast<uint64_t>(memory_read_dword(address
));
824 out(win
) << x
.str() << std::endl
;
828 if(command
== "read-qword") {
829 if(address_bad
|| has_value
|| has_tail
)
830 throw std::runtime_error("Syntax: " + command
+ " <address>");
832 std::ostringstream x
;
833 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
834 << static_cast<uint64_t>(memory_read_qword(address
));
835 out(win
) << x
.str() << std::endl
;
839 if(command
== "read-sbyte") {
840 if(address_bad
|| has_value
|| has_tail
)
841 throw std::runtime_error("Syntax: " + command
+ " <address>");
843 std::ostringstream x
;
844 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
845 << static_cast<int64_t>(static_cast<int8_t>(memory_read_byte(address
)));
846 out(win
) << x
.str() << std::endl
;
850 if(command
== "read-sword") {
851 if(address_bad
|| has_value
|| has_tail
)
852 throw std::runtime_error("Syntax: " + command
+ " <address>");
854 std::ostringstream x
;
855 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
856 << static_cast<int64_t>(static_cast<int16_t>(memory_read_word(address
)));
857 out(win
) << x
.str() << std::endl
;
861 if(command
== "read-sdword") {
862 if(address_bad
|| has_value
|| has_tail
)
863 throw std::runtime_error("Syntax: " + command
+ " <address>");
865 std::ostringstream x
;
866 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
867 << static_cast<int64_t>(static_cast<int32_t>(memory_read_dword(address
)));
868 out(win
) << x
.str() << std::endl
;
872 if(command
== "read-sqword") {
873 if(address_bad
|| has_value
|| has_tail
)
874 throw std::runtime_error("Syntax: " + command
+ " <address>");
876 std::ostringstream x
;
877 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
878 << static_cast<int64_t>(static_cast<int64_t>(memory_read_qword(address
)));
879 out(win
) << x
.str() << std::endl
;
883 if(command
== "write-byte") {
884 if(address_bad
|| value_bad
|| has_tail
)
885 throw std::runtime_error("Syntax: " + command
+ " <address> <value>");
886 if(static_cast<int64_t>(value
) < -128 || value
> 255)
887 throw std::runtime_error("Value to write out of range");
888 memory_write_byte(address
, value
& 0xFF);
891 if(command
== "write-word") {
892 if(address_bad
|| value_bad
|| has_tail
)
893 throw std::runtime_error("Syntax: " + command
+ " <address> <value>");
894 if(static_cast<int64_t>(value
) < -32768 || value
> 65535)
895 throw std::runtime_error("Value to write out of range");
896 memory_write_word(address
, value
& 0xFFFF);
899 if(command
== "write-dword") {
900 if(address_bad
|| value_bad
|| has_tail
)
901 throw std::runtime_error("Syntax: " + command
+ " <address> <value>");
902 if(static_cast<int64_t>(value
) < -2147483648 || value
> 4294967295ULL)
903 throw std::runtime_error("Value to write out of range");
904 memory_write_dword(address
, value
& 0xFFFF);
907 if(command
== "write-qword") {
908 if(address_bad
|| value_bad
|| has_tail
)
909 throw std::runtime_error("Syntax: " + command
+ " <address> <value>");
910 memory_write_dword(address
, value
& 0xFFFF);
913 if(command
== "search-memory") {
915 isrch
= new memorysearch();
916 if(firstword
== "sblt" && !has_value
)
918 else if(firstword
== "sble" && !has_value
)
920 else if(firstword
== "sbeq" && !has_value
)
922 else if(firstword
== "sbne" && !has_value
)
924 else if(firstword
== "sbge" && !has_value
)
926 else if(firstword
== "sbgt" && !has_value
)
928 else if(firstword
== "ublt" && !has_value
)
930 else if(firstword
== "uble" && !has_value
)
932 else if(firstword
== "ubeq" && !has_value
)
934 else if(firstword
== "ubne" && !has_value
)
936 else if(firstword
== "ubge" && !has_value
)
938 else if(firstword
== "ubgt" && !has_value
)
940 else if(firstword
== "b" && has_value
) {
941 if(static_cast<int64_t>(value
) < -128 || value
> 255)
942 throw std::runtime_error("Value to compare out of range");
943 isrch
->byte_value(value
& 0xFF);
944 } else if(firstword
== "swlt" && !has_value
)
946 else if(firstword
== "swle" && !has_value
)
948 else if(firstword
== "sweq" && !has_value
)
950 else if(firstword
== "swne" && !has_value
)
952 else if(firstword
== "swge" && !has_value
)
954 else if(firstword
== "swgt" && !has_value
)
956 else if(firstword
== "uwlt" && !has_value
)
958 else if(firstword
== "uwle" && !has_value
)
960 else if(firstword
== "uweq" && !has_value
)
962 else if(firstword
== "uwne" && !has_value
)
964 else if(firstword
== "uwge" && !has_value
)
966 else if(firstword
== "uwgt" && !has_value
)
968 else if(firstword
== "w" && has_value
) {
969 if(static_cast<int64_t>(value
) < -32768 || value
> 65535)
970 throw std::runtime_error("Value to compare out of range");
971 isrch
->word_value(value
& 0xFF);
972 } else if(firstword
== "sdlt" && !has_value
)
974 else if(firstword
== "sdle" && !has_value
)
976 else if(firstword
== "sdeq" && !has_value
)
978 else if(firstword
== "sdne" && !has_value
)
980 else if(firstword
== "sdge" && !has_value
)
982 else if(firstword
== "sdgt" && !has_value
)
984 else if(firstword
== "udlt" && !has_value
)
986 else if(firstword
== "udle" && !has_value
)
988 else if(firstword
== "udeq" && !has_value
)
990 else if(firstword
== "udne" && !has_value
)
992 else if(firstword
== "udge" && !has_value
)
994 else if(firstword
== "udgt" && !has_value
)
996 else if(firstword
== "d" && has_value
) {
997 if(static_cast<int64_t>(value
) < -2147483648 || value
> 4294967295ULL)
998 throw std::runtime_error("Value to compare out of range");
999 isrch
->dword_value(value
& 0xFF);
1000 } else if(firstword
== "sqlt" && !has_value
)
1002 else if(firstword
== "sqle" && !has_value
)
1004 else if(firstword
== "sqeq" && !has_value
)
1006 else if(firstword
== "sqne" && !has_value
)
1008 else if(firstword
== "sqge" && !has_value
)
1010 else if(firstword
== "sqgt" && !has_value
)
1012 else if(firstword
== "uqlt" && !has_value
)
1014 else if(firstword
== "uqle" && !has_value
)
1016 else if(firstword
== "uqeq" && !has_value
)
1018 else if(firstword
== "uqne" && !has_value
)
1020 else if(firstword
== "uqge" && !has_value
)
1022 else if(firstword
== "uqgt" && !has_value
)
1024 else if(firstword
== "q" && has_value
) {
1025 isrch
->qword_value(value
& 0xFF);
1026 } else if(firstword
== "reset" && !has_value
)
1028 else if(firstword
== "count" && !has_value
)
1030 else if(firstword
== "print" && !has_value
) {
1031 auto c
= isrch
->get_candidates();
1032 for(auto ci
= c
.begin(); ci
!= c
.end(); ci
++) {
1033 std::ostringstream x
;
1034 x
<< "0x" << std::hex
<< std::setw(8) << std::setfill('0') << *ci
;
1035 out(win
) << x
.str() << std::endl
;
1038 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword
+ "'");
1039 out(win
) << isrch
->get_candidate_count() << " candidates remain." << std::endl
;