5 #include <snes/snes.hpp>
7 #include "memorymanip.hpp"
12 typedef uint8_t uint8
;
13 typedef uint16_t uint16
;
14 typedef uint32_t uint32
;
16 typedef int16_t int16
;
17 typedef int32_t int32
;
18 #include <nall/platform.hpp>
19 #include <nall/endian.hpp>
20 #include <nall/varint.hpp>
21 #include <nall/bit.hpp>
22 #include <nall/serializer.hpp>
23 #include <nall/property.hpp>
25 #include <ui-libsnes/libsnes.hpp>
31 struct translated_address
51 std::vector
<region
> memory_regions
;
52 uint32_t linear_ram_size
= 0;
53 bool system_little_endian
= true;
55 struct translated_address
translate_address(uint32_t rawaddr
) throw()
57 struct translated_address t
;
62 t
.not_writable
= true;
63 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
64 if(i
->base
> rawaddr
|| i
->base
+ i
->size
<= rawaddr
)
66 t
.rel_addr
= rawaddr
- i
->base
;
69 t
.memory_size
= i
->size
;
70 t
.not_writable
= i
->not_writable
;
71 t
.native_endian
= i
->native_endian
;
77 struct translated_address
translate_address_linear_ram(uint32_t ramlinaddr
) throw()
79 struct translated_address t
;
84 t
.not_writable
= true;
85 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
88 if(ramlinaddr
>= i
->size
) {
89 ramlinaddr
-= i
->size
;
92 t
.rel_addr
= ramlinaddr
;
93 t
.raw_addr
= i
->base
+ ramlinaddr
;
95 t
.memory_size
= i
->size
;
96 t
.not_writable
= i
->not_writable
;
97 t
.native_endian
= i
->native_endian
;
103 uint32_t get_linear_ram_size() throw()
105 return linear_ram_size
;
108 uint32_t create_region(const std::string
& name
, uint32_t base
, uint8_t* memory
, uint32_t size
, bool readonly
,
109 bool native_endian
= false) throw(std::bad_alloc
)
118 r
.not_writable
= readonly
;
119 r
.native_endian
= native_endian
;
121 linear_ram_size
+= size
;
122 memory_regions
.push_back(r
);
126 uint32_t create_region(const std::string
& name
, uint32_t base
, MappedRAM
& memory
, bool readonly
,
127 bool native_endian
= false) throw(std::bad_alloc
)
129 return create_region(name
, base
, memory
.data(), memory
.size(), readonly
, native_endian
);
132 uint16_t native_bigendian_convert(uint16_t x
) throw()
134 if(system_little_endian
)
135 return (((x
>> 8) & 0xFF) | ((x
<< 8) & 0xFF00));
140 uint32_t native_bigendian_convert(uint32_t x
) throw()
142 if(system_little_endian
)
143 return (((x
>> 24) & 0xFF) | ((x
>> 8) & 0xFF00) |
144 ((x
<< 8) & 0xFF0000) | ((x
<< 24) & 0xFF000000));
149 uint64_t native_bigendian_convert(uint64_t x
) throw()
151 if(system_little_endian
)
152 return (((x
>> 56) & 0xFF) | ((x
>> 40) & 0xFF00) |
153 ((x
>> 24) & 0xFF0000) | ((x
>> 8) & 0xFF000000) |
154 ((x
<< 8) & 0xFF00000000ULL
) | ((x
<< 24) & 0xFF0000000000ULL
) |
155 ((x
<< 40) & 0xFF000000000000ULL
) | ((x
<< 56) & 0xFF00000000000000ULL
));
162 void refresh_cart_mappings() throw(std::bad_alloc
)
165 memory_regions
.clear();
166 if(get_current_rom_info().first
== ROMTYPE_NONE
)
168 create_region("WRAM", 0x007E0000, cpu
.wram
, 131072, false);
169 create_region("APURAM", 0x00000000, smp
.apuram
, 65536, false);
170 create_region("VRAM", 0x00010000, ppu
.vram
, 65536, false);
171 create_region("OAM", 0x00020000, ppu
.oam
, 544, false);
172 create_region("CGRAM", 0x00021000, ppu
.cgram
, 512, false);
173 if(cartridge
.has_srtc()) create_region("RTC", 0x00022000, srtc
.rtc
, 20, false);
174 if(cartridge
.has_spc7110rtc()) create_region("RTC", 0x00022000, spc7110
.rtc
, 20, false);
175 if(cartridge
.has_necdsp()) {
176 create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(necdsp
.dataRAM
), 4096, false, true);
177 create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(necdsp
.programROM
), 65536, true,
179 create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(necdsp
.dataROM
), 4096, true, true);
181 create_region("SRAM", 0x10000000, cartridge
.ram
, false);
182 create_region("ROM", 0x80000000, cartridge
.rom
, true);
183 switch(get_current_rom_info().first
) {
185 case ROMTYPE_BSXSLOTTED
:
186 create_region("BSXFLASH", 0x90000000, bsxflash
.memory
, true);
187 create_region("BSX_RAM", 0x20000000, bsxcartridge
.sram
, false);
188 create_region("BSX_PRAM", 0x30000000, bsxcartridge
.psram
, false);
190 case ROMTYPE_SUFAMITURBO
:
191 create_region("SLOTA_ROM", 0x90000000, sufamiturbo
.slotA
.rom
, true);
192 create_region("SLOTB_ROM", 0xA0000000, sufamiturbo
.slotB
.rom
, true);
193 create_region("SLOTA_RAM", 0x20000000, sufamiturbo
.slotA
.ram
, false);
194 create_region("SLOTB_RAM", 0x30000000, sufamiturbo
.slotB
.ram
, false);
197 create_region("GBROM", 0x90000000, GameBoy::cartridge
.romdata
, GameBoy::cartridge
.romsize
, true);
198 create_region("GBRAM", 0x20000000, GameBoy::cartridge
.ramdata
, GameBoy::cartridge
.ramsize
, false);
206 std::vector
<struct memory_region
> get_regions() throw(std::bad_alloc
)
208 std::vector
<struct memory_region
> out
;
209 for(auto i
= memory_regions
.begin(); i
!= memory_regions
.end(); ++i
) {
210 struct memory_region r
;
211 r
.region_name
= i
->name
;
212 r
.baseaddr
= i
->base
;
214 r
.lastaddr
= i
->base
+ i
->size
- 1;
215 r
.readonly
= i
->not_writable
;
216 r
.native_endian
= i
->native_endian
;
222 uint8_t memory_read_byte(uint32_t addr
) throw()
224 struct translated_address laddr
= translate_address(addr
);
226 if(laddr
.rel_addr
< laddr
.memory_size
)
227 value
|= laddr
.memory
[laddr
.rel_addr
++];
231 uint16_t memory_read_word(uint32_t addr
) throw()
233 struct translated_address laddr
= translate_address(addr
);
235 if(laddr
.rel_addr
< laddr
.memory_size
)
236 value
|= (static_cast<uint16_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
237 if(laddr
.rel_addr
< laddr
.memory_size
)
238 value
|= (static_cast<uint16_t>(laddr
.memory
[laddr
.rel_addr
++]));
239 if(laddr
.native_endian
)
240 value
= native_bigendian_convert(value
);
244 uint32_t memory_read_dword(uint32_t addr
) throw()
246 struct translated_address laddr
= translate_address(addr
);
248 if(laddr
.rel_addr
< laddr
.memory_size
)
249 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 24);
250 if(laddr
.rel_addr
< laddr
.memory_size
)
251 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 16);
252 if(laddr
.rel_addr
< laddr
.memory_size
)
253 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
254 if(laddr
.rel_addr
< laddr
.memory_size
)
255 value
|= (static_cast<uint32_t>(laddr
.memory
[laddr
.rel_addr
++]));
256 if(laddr
.native_endian
)
257 value
= native_bigendian_convert(value
);
261 uint64_t memory_read_qword(uint32_t addr
) throw()
263 struct translated_address laddr
= translate_address(addr
);
265 if(laddr
.rel_addr
< laddr
.memory_size
)
266 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 56);
267 if(laddr
.rel_addr
< laddr
.memory_size
)
268 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 48);
269 if(laddr
.rel_addr
< laddr
.memory_size
)
270 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 40);
271 if(laddr
.rel_addr
< laddr
.memory_size
)
272 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 32);
273 if(laddr
.rel_addr
< laddr
.memory_size
)
274 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 24);
275 if(laddr
.rel_addr
< laddr
.memory_size
)
276 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 16);
277 if(laddr
.rel_addr
< laddr
.memory_size
)
278 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]) << 8);
279 if(laddr
.rel_addr
< laddr
.memory_size
)
280 value
|= (static_cast<uint64_t>(laddr
.memory
[laddr
.rel_addr
++]));
281 if(laddr
.native_endian
)
282 value
= native_bigendian_convert(value
);
286 //Byte write to address (false if failed).
287 bool memory_write_byte(uint32_t addr
, uint8_t data
) throw()
289 struct translated_address laddr
= translate_address(addr
);
290 if(laddr
.rel_addr
>= laddr
.memory_size
|| laddr
.not_writable
)
292 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
296 bool memory_write_word(uint32_t addr
, uint16_t data
) throw()
298 struct translated_address laddr
= translate_address(addr
);
299 if(laddr
.native_endian
)
300 data
= native_bigendian_convert(data
);
301 if(laddr
.rel_addr
>= laddr
.memory_size
- 1 || laddr
.not_writable
)
303 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
304 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
308 bool memory_write_dword(uint32_t addr
, uint32_t data
) throw()
310 struct translated_address laddr
= translate_address(addr
);
311 if(laddr
.native_endian
)
312 data
= native_bigendian_convert(data
);
313 if(laddr
.rel_addr
>= laddr
.memory_size
- 3 || laddr
.not_writable
)
315 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 24);
316 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 16);
317 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
318 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
322 bool memory_write_qword(uint32_t addr
, uint64_t data
) throw()
324 struct translated_address laddr
= translate_address(addr
);
325 if(laddr
.native_endian
)
326 data
= native_bigendian_convert(data
);
327 if(laddr
.rel_addr
>= laddr
.memory_size
- 7 || laddr
.not_writable
)
329 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 56);
330 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 48);
331 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 40);
332 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 32);
333 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 24);
334 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 16);
335 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
>> 8);
336 laddr
.memory
[laddr
.rel_addr
++] = static_cast<uint8_t>(data
);
340 memorysearch::memorysearch() throw(std::bad_alloc
)
345 void memorysearch::reset() throw(std::bad_alloc
)
347 uint32_t linearram
= get_linear_ram_size();
348 previous_content
.resize(linearram
);
349 still_in
.resize((linearram
+ 63) / 64);
350 for(uint32_t i
= 0; i
< linearram
/ 64; i
++)
351 still_in
[i
] = 0xFFFFFFFFFFFFFFFFULL
;
353 still_in
[linearram
/ 64] = (1ULL << (linearram
% 64)) - 1;
355 while(addr
< linearram
) {
356 struct translated_address t
= translate_address_linear_ram(addr
);
357 memcpy(&previous_content
[addr
], t
.memory
, t
.memory_size
);
358 addr
+= t
.memory_size
;
360 candidates
= linearram
;
364 * \brief Native-value search function for specific value
370 * \brief The underlying numeric type
372 typedef T value_type
;
375 * \brief Create new search object
377 * \param v The value to search for.
379 search_value(T v
) throw()
385 * \brief Condition function.
386 * \param oldv The old value
387 * \param newv The new value
388 * \return True if new value satisfies condition, false otherwise.
390 bool operator()(T oldv
, T newv
) const throw()
392 return (newv
== val
);
396 * \brief The value to look for
402 * \brief Native-value search function for less-than function.
408 * \brief The underlying numeric type
410 typedef T value_type
;
413 * \brief Condition function.
414 * \param oldv The old value
415 * \param newv The new value
416 * \return True if new value satisfies condition, false otherwise.
418 bool operator()(T oldv
, T newv
) const throw()
420 return (newv
< oldv
);
425 * \brief Native-value search function for less-or-equal-to function.
431 * \brief The underlying numeric type
433 typedef T value_type
;
436 * \brief Condition function.
437 * \param oldv The old value
438 * \param newv The new value
439 * \return True if new value satisfies condition, false otherwise.
441 bool operator()(T oldv
, T newv
) const throw()
443 return (newv
<= oldv
);
448 * \brief Native-value search function for equals function.
454 * \brief The underlying numeric type
456 typedef T value_type
;
459 * \brief Condition function.
460 * \param oldv The old value
461 * \param newv The new value
462 * \return True if new value satisfies condition, false otherwise.
464 bool operator()(T oldv
, T newv
) const throw()
466 return (newv
== oldv
);
471 * \brief Native-value search function for not-equal function.
477 * \brief The underlying numeric type
479 typedef T value_type
;
482 * \brief Condition function.
483 * \param oldv The old value
484 * \param newv The new value
485 * \return True if new value satisfies condition, false otherwise.
487 bool operator()(T oldv
, T newv
) const throw()
489 return (newv
!= oldv
);
494 * \brief Native-value search function for greater-or-equal-to function.
500 * \brief The underlying numeric type
502 typedef T value_type
;
505 * \brief Condition function.
506 * \param oldv The old value
507 * \param newv The new value
508 * \return True if new value satisfies condition, false otherwise.
510 bool operator()(T oldv
, T newv
) const throw()
512 return (newv
>= oldv
);
517 * \brief Native-value search function for greater-than function.
523 * \brief The underlying numeric type
525 typedef T value_type
;
528 * \brief Condition function.
529 * \param oldv The old value
530 * \param newv The new value
531 * \return True if new value satisfies condition, false otherwise.
533 bool operator()(T oldv
, T newv
) const throw()
535 return (newv
> oldv
);
540 * \brief Helper class to decode arguments to search functions
542 * This class acts as adapter between search conditions taking native numbers as parameters and the interface
543 * expected for the search function.
546 struct search_value_helper
549 * \brief The underlying numeric type
551 typedef typename
T::value_type value_type
;
554 * \brief Constructor constructing condition object
556 * This constructor takes in condition object with the native-value interface and makes condition object with
557 * interface used by search().
559 * \param v The condition object to wrap.
561 search_value_helper(const T
& v
) throw()
567 * \brief Condition function
569 * This function is search()-compatible condition function calling the underlying condition.
571 bool operator()(const uint8_t* newv
, const uint8_t* oldv
, uint32_t left
, bool nativeendian
) const throw()
573 if(left
< sizeof(value_type
))
578 v1
= *reinterpret_cast<const value_type
*>(oldv
);
579 v2
= *reinterpret_cast<const value_type
*>(newv
);
581 for(size_t i
= 0; i
< sizeof(value_type
); i
++) {
582 v1
|= static_cast<value_type
>(oldv
[i
]) << (8 * (sizeof(value_type
) - i
));
583 v2
|= static_cast<value_type
>(newv
[i
]) << (8 * (sizeof(value_type
) - i
));
589 * \brief The underlying condition.
594 template<class T
> void memorysearch::search(const T
& obj
) throw()
596 search_value_helper
<T
> helper(obj
);
597 struct translated_address t
= translate_address_linear_ram(0);
598 uint32_t switch_at
= t
.memory_size
;
600 uint32_t size
= previous_content
.size();
601 for(uint32_t i
= 0; i
< size
; i
++) {
602 if(still_in
[i
/ 64] == 0) {
603 i
= (i
+ 64) >> 6 << 6;
607 //t.memory_size == 0 can happen if cart changes.
608 while(i
>= switch_at
&& t
.memory_size
> 0) {
609 t
= translate_address_linear_ram(switch_at
);
611 switch_at
+= t
.memory_size
;
613 if(t
.memory_size
== 0 || !helper(t
.memory
+ i
- base
, &previous_content
[i
],
614 t
.memory_size
- (i
- base
), t
.native_endian
)) {
615 if((still_in
[i
/ 64] >> (i
% 64)) & 1) {
616 still_in
[i
/ 64] &= ~(1ULL << (i
% 64));
621 t
= translate_address_linear_ram(0);
623 size
= previous_content
.size();
625 size_t m
= t
.memory_size
;
626 if(m
> (size
- base
))
628 memcpy(&previous_content
[base
], t
.memory
, m
);
629 base
+= t
.memory_size
;
630 t
= translate_address_linear_ram(base
);
634 void memorysearch::byte_value(uint8_t value
) throw() { search(search_value
<uint8_t>(value
)); }
635 void memorysearch::byte_slt() throw() { search(search_lt
<int8_t>()); }
636 void memorysearch::byte_sle() throw() { search(search_le
<int8_t>()); }
637 void memorysearch::byte_seq() throw() { search(search_eq
<int8_t>()); }
638 void memorysearch::byte_sne() throw() { search(search_ne
<int8_t>()); }
639 void memorysearch::byte_sge() throw() { search(search_ge
<int8_t>()); }
640 void memorysearch::byte_sgt() throw() { search(search_gt
<int8_t>()); }
641 void memorysearch::byte_ult() throw() { search(search_lt
<uint8_t>()); }
642 void memorysearch::byte_ule() throw() { search(search_le
<uint8_t>()); }
643 void memorysearch::byte_ueq() throw() { search(search_eq
<uint8_t>()); }
644 void memorysearch::byte_une() throw() { search(search_ne
<uint8_t>()); }
645 void memorysearch::byte_uge() throw() { search(search_ge
<uint8_t>()); }
646 void memorysearch::byte_ugt() throw() { search(search_gt
<uint8_t>()); }
648 void memorysearch::word_value(uint16_t value
) throw() { search(search_value
<uint16_t>(value
)); }
649 void memorysearch::word_slt() throw() { search(search_lt
<int16_t>()); }
650 void memorysearch::word_sle() throw() { search(search_le
<int16_t>()); }
651 void memorysearch::word_seq() throw() { search(search_eq
<int16_t>()); }
652 void memorysearch::word_sne() throw() { search(search_ne
<int16_t>()); }
653 void memorysearch::word_sge() throw() { search(search_ge
<int16_t>()); }
654 void memorysearch::word_sgt() throw() { search(search_gt
<int16_t>()); }
655 void memorysearch::word_ult() throw() { search(search_lt
<uint16_t>()); }
656 void memorysearch::word_ule() throw() { search(search_le
<uint16_t>()); }
657 void memorysearch::word_ueq() throw() { search(search_eq
<uint16_t>()); }
658 void memorysearch::word_une() throw() { search(search_ne
<uint16_t>()); }
659 void memorysearch::word_uge() throw() { search(search_ge
<uint16_t>()); }
660 void memorysearch::word_ugt() throw() { search(search_gt
<uint16_t>()); }
662 void memorysearch::dword_value(uint32_t value
) throw() { search(search_value
<uint32_t>(value
)); }
663 void memorysearch::dword_slt() throw() { search(search_lt
<int32_t>()); }
664 void memorysearch::dword_sle() throw() { search(search_le
<int32_t>()); }
665 void memorysearch::dword_seq() throw() { search(search_eq
<int32_t>()); }
666 void memorysearch::dword_sne() throw() { search(search_ne
<int32_t>()); }
667 void memorysearch::dword_sge() throw() { search(search_ge
<int32_t>()); }
668 void memorysearch::dword_sgt() throw() { search(search_gt
<int32_t>()); }
669 void memorysearch::dword_ult() throw() { search(search_lt
<uint32_t>()); }
670 void memorysearch::dword_ule() throw() { search(search_le
<uint32_t>()); }
671 void memorysearch::dword_ueq() throw() { search(search_eq
<uint32_t>()); }
672 void memorysearch::dword_une() throw() { search(search_ne
<uint32_t>()); }
673 void memorysearch::dword_uge() throw() { search(search_ge
<uint32_t>()); }
674 void memorysearch::dword_ugt() throw() { search(search_gt
<uint32_t>()); }
676 void memorysearch::qword_value(uint64_t value
) throw() { search(search_value
<uint64_t>(value
)); }
677 void memorysearch::qword_slt() throw() { search(search_lt
<int64_t>()); }
678 void memorysearch::qword_sle() throw() { search(search_le
<int64_t>()); }
679 void memorysearch::qword_seq() throw() { search(search_eq
<int64_t>()); }
680 void memorysearch::qword_sne() throw() { search(search_ne
<int64_t>()); }
681 void memorysearch::qword_sge() throw() { search(search_ge
<int64_t>()); }
682 void memorysearch::qword_sgt() throw() { search(search_gt
<int64_t>()); }
683 void memorysearch::qword_ult() throw() { search(search_lt
<uint64_t>()); }
684 void memorysearch::qword_ule() throw() { search(search_le
<uint64_t>()); }
685 void memorysearch::qword_ueq() throw() { search(search_eq
<uint64_t>()); }
686 void memorysearch::qword_une() throw() { search(search_ne
<uint64_t>()); }
687 void memorysearch::qword_uge() throw() { search(search_ge
<uint64_t>()); }
688 void memorysearch::qword_ugt() throw() { search(search_gt
<uint64_t>()); }
690 uint32_t memorysearch::get_candidate_count() throw()
695 std::list
<uint32_t> memorysearch::get_candidates() throw(std::bad_alloc
)
697 struct translated_address t
= translate_address_linear_ram(0);
698 uint32_t switch_at
= t
.memory_size
;
700 uint32_t rbase
= t
.raw_addr
;
701 uint32_t size
= previous_content
.size();
702 std::list
<uint32_t> out
;
704 for(uint32_t i
= 0; i
< size
; i
++) {
705 if(still_in
[i
/ 64] == 0) {
706 i
= (i
+ 64) >> 6 << 6;
710 while(i
>= switch_at
&& t
.memory_size
> 0) {
711 t
= translate_address_linear_ram(switch_at
);
713 rbase
= t
.raw_addr
- t
.rel_addr
;
714 switch_at
+= t
.memory_size
;
716 if((still_in
[i
/ 64] >> (i
% 64)) & 1)
717 out
.push_back(i
- base
+ rbase
);
719 std::cout
<< "out=" << out
.size() << " candidates=" << candidates
<< std::endl
;
727 std::string
tokenize1(const std::string
& command
, const std::string
& syntax
);
728 std::pair
<std::string
, std::string
> tokenize2(const std::string
& command
, const std::string
& syntax
);
729 std::pair
<std::string
, std::string
> tokenize12(const std::string
& command
, const std::string
& syntax
);
731 unsigned char hex(char ch
)
744 case 'a': case 'A': return 10;
745 case 'b': case 'B': return 11;
746 case 'c': case 'C': return 12;
747 case 'd': case 'D': return 13;
748 case 'e': case 'E': return 14;
749 case 'f': case 'F': return 15;
751 throw std::runtime_error("Bad hex character");
754 class memorymanip_command
: public command
757 memorymanip_command(const std::string
& cmd
) throw(std::bad_alloc
)
762 ~memorymanip_command() throw() {}
763 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
765 tokensplitter
t(args
);
766 firstword
= static_cast<std::string
>(t
);
767 secondword
= static_cast<std::string
>(t
);
771 has_value
= (secondword
!= "");
773 if(firstword
.length() >= 2 && firstword
.substr(0, 2) == "0x") {
774 if(firstword
.length() > 10)
777 for(unsigned i
= 2; i
< firstword
.length(); i
++)
778 address
= 16 * address
+ hex(firstword
[i
]);
780 address
= parse_value
<uint32_t>(firstword
);
786 if(secondword
.length() >= 2 && secondword
.substr(0, 2) == "0x") {
787 if(secondword
.length() > 18)
790 for(unsigned i
= 2; i
< secondword
.length(); i
++)
791 value
= 16 * value
+ hex(secondword
[i
]);
792 } else if(secondword
.length() > 0 && secondword
[0] == '-') {
793 value
= static_cast<uint64_t>(parse_value
<int64_t>(secondword
));
795 value
= parse_value
<uint64_t>(secondword
);
802 virtual void invoke2() throw(std::bad_alloc
, std::runtime_error
) = 0;
803 std::string firstword
;
804 std::string secondword
;
811 std::string _command
;
814 template<typename outer
, typename inner
, typename ret
>
815 class read_command
: public memorymanip_command
818 read_command(const std::string
& cmd
, ret (*_rfn
)(uint32_t addr
)) throw(std::bad_alloc
)
819 : memorymanip_command(cmd
)
823 ~read_command() throw() {}
824 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
826 if(address_bad
|| has_value
|| has_tail
)
827 throw std::runtime_error("Syntax: " + _command
+ " <address>");
829 std::ostringstream x
;
830 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
831 << static_cast<outer
>(static_cast<inner
>(rfn(address
)));
832 messages
<< x
.str() << std::endl
;
835 std::string
get_short_help() throw(std::bad_alloc
) { return "Read memory"; }
836 std::string
get_long_help() throw(std::bad_alloc
)
838 return "Syntax: " + _command
+ " <address>\n"
839 "Reads data from memory.\n";
842 ret (*rfn
)(uint32_t addr
);
845 template<typename arg
, int64_t low
, uint64_t high
>
846 class write_command
: public memorymanip_command
849 write_command(const std::string
& cmd
, bool (*_wfn
)(uint32_t addr
, arg a
)) throw(std::bad_alloc
)
850 : memorymanip_command(cmd
)
854 ~write_command() throw() {}
855 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
857 if(address_bad
|| value_bad
|| has_tail
)
858 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
859 if(static_cast<int64_t>(value
) < low
|| value
> high
)
860 throw std::runtime_error("Value to write out of range");
861 wfn(address
, value
& high
);
863 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
864 std::string
get_long_help() throw(std::bad_alloc
)
866 return "Syntax: " + _command
+ " <address> <value>\n"
867 "Writes data to memory.\n";
869 bool (*wfn
)(uint32_t addr
, arg a
);
872 class memorysearch_command
: public memorymanip_command
875 memorysearch_command() throw(std::bad_alloc
) : memorymanip_command("search-memory") {}
876 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
879 isrch
= new memorysearch();
880 if(firstword
== "sblt" && !has_value
)
882 else if(firstword
== "sble" && !has_value
)
884 else if(firstword
== "sbeq" && !has_value
)
886 else if(firstword
== "sbne" && !has_value
)
888 else if(firstword
== "sbge" && !has_value
)
890 else if(firstword
== "sbgt" && !has_value
)
892 else if(firstword
== "ublt" && !has_value
)
894 else if(firstword
== "uble" && !has_value
)
896 else if(firstword
== "ubeq" && !has_value
)
898 else if(firstword
== "ubne" && !has_value
)
900 else if(firstword
== "ubge" && !has_value
)
902 else if(firstword
== "ubgt" && !has_value
)
904 else if(firstword
== "b" && has_value
) {
905 if(static_cast<int64_t>(value
) < -128 || value
> 255)
906 throw std::runtime_error("Value to compare out of range");
907 isrch
->byte_value(value
& 0xFF);
908 } else if(firstword
== "swlt" && !has_value
)
910 else if(firstword
== "swle" && !has_value
)
912 else if(firstword
== "sweq" && !has_value
)
914 else if(firstword
== "swne" && !has_value
)
916 else if(firstword
== "swge" && !has_value
)
918 else if(firstword
== "swgt" && !has_value
)
920 else if(firstword
== "uwlt" && !has_value
)
922 else if(firstword
== "uwle" && !has_value
)
924 else if(firstword
== "uweq" && !has_value
)
926 else if(firstword
== "uwne" && !has_value
)
928 else if(firstword
== "uwge" && !has_value
)
930 else if(firstword
== "uwgt" && !has_value
)
932 else if(firstword
== "w" && has_value
) {
933 if(static_cast<int64_t>(value
) < -32768 || value
> 65535)
934 throw std::runtime_error("Value to compare out of range");
935 isrch
->word_value(value
& 0xFF);
936 } else if(firstword
== "sdlt" && !has_value
)
938 else if(firstword
== "sdle" && !has_value
)
940 else if(firstword
== "sdeq" && !has_value
)
942 else if(firstword
== "sdne" && !has_value
)
944 else if(firstword
== "sdge" && !has_value
)
946 else if(firstword
== "sdgt" && !has_value
)
948 else if(firstword
== "udlt" && !has_value
)
950 else if(firstword
== "udle" && !has_value
)
952 else if(firstword
== "udeq" && !has_value
)
954 else if(firstword
== "udne" && !has_value
)
956 else if(firstword
== "udge" && !has_value
)
958 else if(firstword
== "udgt" && !has_value
)
960 else if(firstword
== "d" && has_value
) {
961 if(static_cast<int64_t>(value
) < -2147483648 || value
> 4294967295ULL)
962 throw std::runtime_error("Value to compare out of range");
963 isrch
->dword_value(value
& 0xFF);
964 } else if(firstword
== "sqlt" && !has_value
)
966 else if(firstword
== "sqle" && !has_value
)
968 else if(firstword
== "sqeq" && !has_value
)
970 else if(firstword
== "sqne" && !has_value
)
972 else if(firstword
== "sqge" && !has_value
)
974 else if(firstword
== "sqgt" && !has_value
)
976 else if(firstword
== "uqlt" && !has_value
)
978 else if(firstword
== "uqle" && !has_value
)
980 else if(firstword
== "uqeq" && !has_value
)
982 else if(firstword
== "uqne" && !has_value
)
984 else if(firstword
== "uqge" && !has_value
)
986 else if(firstword
== "uqgt" && !has_value
)
988 else if(firstword
== "q" && has_value
) {
989 isrch
->qword_value(value
& 0xFF);
990 } else if(firstword
== "reset" && !has_value
)
992 else if(firstword
== "count" && !has_value
)
994 else if(firstword
== "print" && !has_value
) {
995 auto c
= isrch
->get_candidates();
996 for(auto ci
= c
.begin(); ci
!= c
.end(); ci
++) {
997 std::ostringstream x
;
998 x
<< "0x" << std::hex
<< std::setw(8) << std::setfill('0') << *ci
;
999 messages
<< x
.str() << std::endl
;
1002 throw std::runtime_error("Unknown memorysearch subcommand '" + firstword
+ "'");
1003 messages
<< isrch
->get_candidate_count() << " candidates remain." << std::endl
;
1005 std::string
get_short_help() throw(std::bad_alloc
) { return "Search memory addresses"; }
1006 std::string
get_long_help() throw(std::bad_alloc
)
1008 return "Syntax: " + _command
+ " {s,u}{b,w,d,q}{lt,le,eq,ne,ge,gt}\n"
1009 "Syntax: " + _command
+ " {b,w,d,q} <value>\n"
1010 "Syntax: " + _command
+ " reset\n"
1011 "Syntax: " + _command
+ " count\n"
1012 "Syntax: " + _command
+ " print\n"
1013 "Searches addresses from memory.\n";
1017 read_command
<uint64_t, uint8_t, uint8_t> ru1("read-byte", memory_read_byte
);
1018 read_command
<uint64_t, uint16_t, uint16_t> ru2("read-word", memory_read_word
);
1019 read_command
<uint64_t, uint32_t, uint32_t> ru4("read-dword", memory_read_dword
);
1020 read_command
<uint64_t, uint64_t, uint64_t> ru8("read-qword", memory_read_qword
);
1021 read_command
<uint64_t, int8_t, uint8_t> rs1("read-sbyte", memory_read_byte
);
1022 read_command
<uint64_t, int16_t, uint16_t> rs2("read-sword", memory_read_word
);
1023 read_command
<uint64_t, int32_t, uint32_t> rs4("read-sdword", memory_read_dword
);
1024 read_command
<uint64_t, int64_t, uint64_t> rs8("read-sqword", memory_read_qword
);
1025 write_command
<uint8_t, -128, 0xFF> w1("write-byte", memory_write_byte
);
1026 write_command
<uint16_t, -32768, 0xFFFF> w2("write-word", memory_write_word
);
1027 write_command
<uint32_t, -2147483648, 0xFFFFFFFFU
> w4("write-dword", memory_write_dword
);
1028 write_command
<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL
> w8("write-qword", memory_write_qword
);