JSON-based controller descriptions
[lsnes.git] / src / core / disassemble.cpp
blob2698025a977960eab35acccc633f8ff62e790ad3
1 #include "core/command.hpp"
2 #include "interface/disassembler.hpp"
3 #include "library/bintohex.hpp"
4 #include "library/minmax.hpp"
5 #include "core/memorymanip.hpp"
6 #include "core/window.hpp"
7 #include "library/string.hpp"
8 #include <iomanip>
9 #include <fstream>
10 #include <iostream>
12 namespace
14 struct dres
16 uint64_t addr;
17 uint64_t len;
18 std::string disasm;
21 unsigned char hex(char ch)
23 switch(ch) {
24 case '0': return 0;
25 case '1': return 1;
26 case '2': return 2;
27 case '3': return 3;
28 case '4': return 4;
29 case '5': return 5;
30 case '6': return 6;
31 case '7': return 7;
32 case '8': return 8;
33 case '9': return 9;
34 case 'a': case 'A': return 10;
35 case 'b': case 'B': return 11;
36 case 'c': case 'C': return 12;
37 case 'd': case 'D': return 13;
38 case 'e': case 'E': return 14;
39 case 'f': case 'F': return 15;
41 throw std::runtime_error("Bad hex character");
44 uint64_t parse_hexordec(const std::string& k)
46 regex_results t;
47 uint64_t address = 0;
48 if(t = regex("0x(.+)", k)) {
49 if(t[1].length() > 16)
50 throw 42;
51 address = 0;
52 for(unsigned i = 0; i < t[1].length(); i++)
53 address = 16 * address + hex(t[1][i]);
54 } else {
55 address = parse_value<uint64_t>(k);
57 return address;
60 function_ptr_command<const std::string&> disassemble(lsnes_cmd, "disassemble", "Disassemble code",
61 "Syntax: disassemble <kind> <addr> [<count>] [to <filename>]\nDisassemble code\n",
62 [](const std::string& t) throw(std::bad_alloc, std::runtime_error) {
63 regex_results r = regex("([^ \t]+)[ \t]+([0-9]+|0x[0-9A-Fa-f]+)([ \t]+([0-9]+))?"
64 "([ \t]+to[ \t]+(.+))?", t);
65 if(!r) {
66 messages << "Syntax: disassemble <kind> <addr> [<count>] [to <filename>]" << std::endl;
67 return;
69 std::string kind = r[1];
70 uint64_t addr = parse_hexordec(r[2]);
71 uint64_t count = 1;
72 if(r[4] != "")
73 count = parse_value<uint64_t>(r[4]);
74 std::string file;
75 if(r[6] != "")
76 file = r[6];
77 std::list<dres> result;
78 disassembler* d;
79 try {
80 d = &disassembler::byname(kind);
81 } catch(std::exception& e) {
82 messages << "Can't find such disassembler" << std::endl;
83 return;
85 uint64_t laddr = addr;
86 uint64_t longest = 0;
87 for(uint64_t i = 1; i <= count; i++) {
88 uint64_t bytes = 0;
89 dres x;
90 x.addr = laddr;
91 x.disasm = d->disassemble(laddr, [&bytes, laddr]() -> unsigned char {
92 return lsnes_memory.read<uint8_t>(laddr + bytes++);
93 });
94 x.len = bytes;
95 result.push_back(x);
96 longest = max(longest, bytes);
97 laddr += bytes;
99 std::ostream* strm = &messages.getstream();
100 if(file != "") {
101 strm = new std::ofstream(file);
102 if(!*strm) {
103 messages << "Can't open output file" << std::endl;
104 return;
107 for(auto i : result) {
108 std::vector<unsigned char> tmp;
109 tmp.resize(i.len);
110 lsnes_memory.read_range(i.addr, &tmp[0], i.len);
111 std::string l = (stringfmt() << std::setw(16) << std::setfill('0') << std::hex
112 << i.addr).str() + " " + binary_to_hex(&tmp[0], i.len) + " "
113 + i.disasm;
114 (*strm) << l << std::endl;
116 if(file != "")
117 delete strm;