1 #include "core/command.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/memorywatch.hpp"
5 #include "core/window.hpp"
6 #include <library/string.hpp>
19 std::map
<std::string
, std::string
> watches
;
23 numeric_type() { t
= VT_NAN
; hex
= 0; }
24 numeric_type(int8_t x
) { t
= VT_SIGNED
; s
= x
; hex
= 0; }
25 numeric_type(uint8_t x
) { t
= VT_UNSIGNED
; u
= x
; hex
= 0; }
26 numeric_type(int16_t x
) { t
= VT_SIGNED
; s
= x
; hex
= 0; }
27 numeric_type(uint16_t x
) { t
= VT_UNSIGNED
; u
= x
; hex
= 0; }
28 numeric_type(int32_t x
) { t
= VT_SIGNED
; s
= x
; hex
= 0; }
29 numeric_type(uint32_t x
) { t
= VT_UNSIGNED
; u
= x
; hex
= 0; }
30 numeric_type(int64_t x
) { t
= VT_SIGNED
; s
= x
; hex
= 0; }
31 numeric_type(uint64_t x
) { t
= VT_UNSIGNED
; u
= x
; hex
= 0; }
32 numeric_type(double x
) { t
= VT_FLOAT
; f
= x
; }
33 numeric_type(const std::string
& _s
)
36 if(_s
.length() > 2 && _s
[0] == '0' && _s
[1] == 'x') {
38 u
= strtoull(_s
.c_str() + 2, &end
, 16);
40 throw std::runtime_error("#syntax (badval)");
41 } else if(_s
.length() > 3 && _s
[0] == '+' && _s
[1] == '0' && _s
[2] == 'x') {
43 s
= (int64_t)strtoull(_s
.c_str() + 3, &end
, 16);
45 throw std::runtime_error("#syntax (badval)");
46 } else if(_s
.length() > 3 && _s
[0] == '-' && _s
[1] == '0' && _s
[2] == 'x') {
48 s
= -(int64_t)strtoull(_s
.c_str() + 3, &end
, 16);
50 throw std::runtime_error("#syntax (badval)");
51 } else if(_s
.find_first_of(".") < _s
.length()) {
53 f
= strtod(_s
.c_str(), &end
);
55 throw std::runtime_error("#syntax (badval)");
56 } else if(_s
.length() > 1 && _s
[0] == '+') {
58 s
= (int64_t)strtoull(_s
.c_str() + 1, &end
, 10);
60 throw std::runtime_error("#syntax (badval)");
61 } else if(_s
.length() > 1 && _s
[0] == '-') {
63 s
= -(int64_t)strtoull(_s
.c_str() + 1, &end
, 10);
65 throw std::runtime_error("#syntax (badval)");
68 u
= strtoull(_s
.c_str(), &end
, 10);
70 throw std::runtime_error("#syntax (badval)");
74 uint64_t as_address() const
77 case VT_SIGNED
: return s
;
78 case VT_UNSIGNED
: return u
;
79 case VT_FLOAT
: return f
;
80 case VT_NAN
: throw std::runtime_error("#NAN");
83 int64_t as_integer() const
86 case VT_SIGNED
: return s
;
87 case VT_UNSIGNED
: return u
;
88 case VT_FLOAT
: return f
;
89 case VT_NAN
: throw std::runtime_error("#NAN");
92 double as_double() const
95 case VT_SIGNED
: return s
;
96 case VT_UNSIGNED
: return u
;
97 case VT_FLOAT
: return f
;
98 case VT_NAN
: throw std::runtime_error("#NAN");
101 std::string
str() const
103 uint64_t wmasks
[] = {
104 0x0000000000000000ULL
, 0x000000000000000FULL
, 0x00000000000000FFULL
,
105 0x0000000000000FFFULL
, 0x000000000000FFFFULL
, 0x00000000000FFFFFULL
,
106 0x0000000000FFFFFFULL
, 0x000000000FFFFFFFULL
, 0x00000000FFFFFFFFULL
,
107 0x0000000FFFFFFFFFULL
, 0x000000FFFFFFFFFFULL
, 0x00000FFFFFFFFFFFULL
,
108 0x0000FFFFFFFFFFFFULL
, 0x000FFFFFFFFFFFFFULL
, 0x00FFFFFFFFFFFFFFULL
,
109 0x0FFFFFFFFFFFFFFFULL
, 0xFFFFFFFFFFFFFFFFULL
111 std::ostringstream x
;
112 if(hex
&& (t
== VT_SIGNED
|| t
== VT_UNSIGNED
)) {
113 uint64_t wmask
= wmasks
[hex
];
114 uint64_t w
= (t
== VT_SIGNED
) ? s
: u
;
115 x
<< std::hex
<< std::setw(hex
) << std::setfill('0') << (w
& wmask
);
119 case VT_SIGNED
: x
<< s
; break;
120 case VT_UNSIGNED
: x
<< u
; break;
121 case VT_FLOAT
: x
<< f
; break;
122 case VT_NAN
: x
<< "#NAN"; break;
126 numeric_type
round(int prec
) const
132 c
= floor(b
* f
+ 0.5) / b
;
133 return numeric_type(c
);
138 numeric_type
operator+(const numeric_type
& b
) const
140 if(t
== VT_NAN
|| b
.t
== VT_NAN
)
141 return numeric_type();
142 else if(t
== VT_FLOAT
|| b
.t
== VT_FLOAT
)
143 return numeric_type(as_double() + b
.as_double());
144 else if(t
== VT_SIGNED
|| b
.t
== VT_SIGNED
)
145 return numeric_type(as_integer() + b
.as_integer());
147 return numeric_type(as_address() + b
.as_address());
149 numeric_type
operator-(const numeric_type
& b
) const
151 if(t
== VT_NAN
|| b
.t
== VT_NAN
)
152 return numeric_type();
153 else if(t
== VT_FLOAT
|| b
.t
== VT_FLOAT
)
154 return numeric_type(as_double() - b
.as_double());
155 else if(t
== VT_SIGNED
|| b
.t
== VT_SIGNED
)
156 return numeric_type(as_integer() - b
.as_integer());
158 return numeric_type(as_address() - b
.as_address());
160 numeric_type
operator*(const numeric_type
& b
) const
162 if(t
== VT_NAN
|| b
.t
== VT_NAN
)
163 return numeric_type();
164 else if(t
== VT_FLOAT
|| b
.t
== VT_FLOAT
)
165 return numeric_type(as_double() * b
.as_double());
166 else if(t
== VT_SIGNED
|| b
.t
== VT_SIGNED
)
167 return numeric_type(as_integer() * b
.as_integer());
169 return numeric_type(as_address() * b
.as_address());
171 numeric_type
operator/(const numeric_type
& b
) const
173 if(b
.t
!= VT_NAN
&& fabs(b
.as_double()) < 1e-30)
174 throw std::runtime_error("#DIV-BY-0");
175 if(t
== VT_NAN
|| b
.t
== VT_NAN
)
176 return numeric_type();
178 return numeric_type(as_double() / b
.as_double());
180 numeric_type
operator%(const numeric_type
& b
) const
182 return numeric_type(*this - b
* idiv(b
));
184 numeric_type
idiv(const numeric_type
& b
) const
186 if(b
.t
!= VT_NAN
&& fabs(b
.as_double()) < 1e-30)
187 throw std::runtime_error("#DIV-BY-0");
188 if(t
== VT_NAN
|| b
.t
== VT_NAN
)
189 return numeric_type();
190 else if(t
== VT_FLOAT
|| b
.t
== VT_FLOAT
)
191 return numeric_type(floor(as_double() / b
.as_double()));
192 else if(t
== VT_SIGNED
|| b
.t
== VT_SIGNED
)
193 return numeric_type(as_integer() / b
.as_integer());
195 return numeric_type(as_address() / b
.as_address());
199 if(ch
>= '0' && ch
<= '9')
201 if(ch
>= 'A' && ch
<= 'G')
202 hex
= (ch
- 'A') + 10;
203 if(ch
>= 'a' && ch
<= 'g')
204 hex
= (ch
- 'a') + 10;
220 numeric_type
stack_pop(std::stack
<numeric_type
>& s
, bool norm
= false)
223 throw std::runtime_error("#syntax (underflow)");
224 numeric_type r
= s
.top();
230 template<typename T
> void stack_push(std::stack
<numeric_type
>& s
, T val
)
232 s
.push(numeric_type(val
));
236 std::string
evaluate_watch(const std::string
& expr
) throw(std::bad_alloc
)
238 std::stack
<numeric_type
> s
;
240 std::string _expr
= expr
;
246 for(size_t i
= 0; i
< expr
.length(); i
++) {
250 y
= expr
.find_first_of("z", i
);
251 if(y
> expr
.length())
252 return "#syntax (noterm)";
253 t
= _expr
.substr(i
+ 1, y
- i
- 1);
254 stack_push(s
, numeric_type(t
));
258 if(i
+ 1 == expr
.length())
259 throw std::runtime_error("#syntax (noparam)");
262 stack_push(s
, a
.round(d
));
265 if(i
+ 1 == expr
.length())
266 throw std::runtime_error("#syntax (noparam)");
267 s
.top().sethex(expr
[++i
]);
270 stack_push
<double>(s
, atan(stack_pop(s
).as_double()));
275 stack_push
<double>(s
, atan2(a
.as_double(), b
.as_double()));
278 stack_push
<double>(s
, cos(stack_pop(s
).as_double()));
282 if(a
.as_double() < 0)
283 throw std::runtime_error("#NAN");
284 stack_push
<double>(s
, sqrt(a
.as_double()));
287 stack_push
<double>(s
, sin(stack_pop(s
).as_double()));
290 stack_push
<double>(s
, tan(stack_pop(s
).as_double()));
293 stack_push(s
, stack_pop(s
, true));
296 stack_push(s
, 4 * atan(1));
301 stack_push(s
, a
+ b
);
306 stack_push(s
, a
- b
);
311 stack_push(s
, a
* b
);
316 stack_push(s
, a
.idiv(b
));
321 stack_push(s
, a
/ b
);
326 stack_push(s
, a
% b
);
329 stack_push
<int8_t>(s
, memory_read_byte(stack_pop(s
).as_address()));
332 stack_push
<uint8_t>(s
, memory_read_byte(stack_pop(s
).as_address()));
335 stack_push
<int16_t>(s
, memory_read_word(stack_pop(s
).as_address()));
338 stack_push
<uint16_t>(s
, memory_read_word(stack_pop(s
).as_address()));
341 stack_push
<int32_t>(s
, memory_read_dword(stack_pop(s
).as_address()));
344 stack_push
<uint32_t>(s
, memory_read_dword(stack_pop(s
).as_address()));
347 stack_push
<int64_t>(s
, memory_read_qword(stack_pop(s
).as_address()));
350 stack_push
<uint64_t>(s
, memory_read_qword(stack_pop(s
).as_address()));
353 throw std::runtime_error("#syntax (illchar)");
359 return s
.top().str();
360 } catch(std::exception
& e
) {
365 std::set
<std::string
> get_watches() throw(std::bad_alloc
)
367 std::set
<std::string
> r
;
368 for(auto i
: watches
)
373 std::string
get_watchexpr_for(const std::string
& w
) throw(std::bad_alloc
)
381 void set_watchexpr_for(const std::string
& w
, const std::string
& expr
) throw(std::bad_alloc
)
383 auto& status
= platform::get_emustatus();
386 status
.set("M[" + w
+ "]", evaluate_watch(expr
));
389 status
.erase("M[" + w
+ "]");
391 information_dispatch::do_status_update();
394 void do_watch_memory()
396 auto& status
= platform::get_emustatus();
397 for(auto i
: watches
)
398 status
.set("M[" + i
.first
+ "]", evaluate_watch(i
.second
));
403 function_ptr_command
<const std::string
&> add_watch("add-watch", "Add a memory watch",
404 "Syntax: add-watch <name> <expression>\nAdds a new memory watch\n",
405 [](const std::string
& t
) throw(std::bad_alloc
, std::runtime_error
) {
406 auto r
= regex("([^ \t]+)[ \t]+(|[^ \t].*)", t
, "Name and expression required.");
407 set_watchexpr_for(r
[1], r
[2]);
410 function_ptr_command
<const std::string
&> remove_watch("remove-watch", "Remove a memory watch",
411 "Syntax: remove-watch <name>\nRemoves a memory watch\n",
412 [](const std::string
& t
) throw(std::bad_alloc
, std::runtime_error
) {
413 auto r
= regex("([^ \t]+)[ \t]*", t
, "Name required.");
414 set_watchexpr_for(r
[1], "");