1 |
dpavlin |
1 |
/* |
2 |
|
|
* HT Editor |
3 |
|
|
* debugger.cc |
4 |
|
|
* |
5 |
|
|
* Copyright (C) 2003 Stefan Weyergraf |
6 |
|
|
* |
7 |
|
|
* This program is free software; you can redistribute it and/or modify |
8 |
|
|
* it under the terms of the GNU General Public License version 2 as |
9 |
|
|
* published by the Free Software Foundation. |
10 |
|
|
* |
11 |
|
|
* This program is distributed in the hope that it will be useful, |
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU General Public License |
17 |
|
|
* along with this program; if not, write to the Free Software |
18 |
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 |
|
|
*/ |
20 |
|
|
#define HAVE_DEBUGGER |
21 |
|
|
|
22 |
|
|
#include <stdio.h> |
23 |
|
|
|
24 |
|
|
#include "system/display.h" |
25 |
|
|
#include "tools/except.h" |
26 |
|
|
#include "tools/snprintf.h" |
27 |
|
|
#include "tools/debug.h" |
28 |
|
|
#include "debugger.h" |
29 |
|
|
#include "parsehelper.h" |
30 |
|
|
#include "stdfuncs.h" |
31 |
|
|
#include "cpu/cpu.h" |
32 |
|
|
|
33 |
|
|
#include "debug/ppcdis.h" |
34 |
|
|
|
35 |
|
|
#ifdef HAVE_DEBUGGER |
36 |
|
|
#include "cpu/cpu_generic/ppc_mmu.h" |
37 |
|
|
#endif |
38 |
|
|
|
39 |
|
|
/* |
40 |
|
|
* A function |
41 |
|
|
*/ |
42 |
|
|
SInt64 *Function::evalInteger() const |
43 |
|
|
{ |
44 |
|
|
EvalType type = getReturnType(); |
45 |
|
|
switch (type) { |
46 |
|
|
case ET_INTEGER: throw NotImplementedException(HERE); |
47 |
|
|
case ET_FLOAT: { |
48 |
|
|
Float *f = evalFloat(); |
49 |
|
|
SInt64 *i = new SInt64((sint64)f->value); |
50 |
|
|
delete f; |
51 |
|
|
return i; |
52 |
|
|
break; |
53 |
|
|
} |
54 |
|
|
case ET_STRING: { |
55 |
|
|
String *s = evalString(); |
56 |
|
|
uint64 u; |
57 |
|
|
SInt64 *i; |
58 |
|
|
if (s->toInt64(u, 10)) { |
59 |
|
|
i = new SInt64(u); |
60 |
|
|
} else { |
61 |
|
|
i = new SInt64(0); |
62 |
|
|
} |
63 |
|
|
delete s; |
64 |
|
|
return i; |
65 |
|
|
break; |
66 |
|
|
} |
67 |
|
|
case ET_VARARGS: /* may-not-happen */ |
68 |
|
|
ASSERT(0); |
69 |
|
|
break; |
70 |
|
|
} |
71 |
|
|
return NULL; |
72 |
|
|
} |
73 |
|
|
|
74 |
|
|
Float *Function::evalFloat() const |
75 |
|
|
{ |
76 |
|
|
EvalType type = getReturnType(); |
77 |
|
|
switch (type) { |
78 |
|
|
case ET_INTEGER: { |
79 |
|
|
SInt64 *u = evalInteger(); |
80 |
|
|
Float *f = new Float(u->value); |
81 |
|
|
delete u; |
82 |
|
|
return f; |
83 |
|
|
} |
84 |
|
|
case ET_FLOAT: throw NotImplementedException(HERE); |
85 |
|
|
case ET_STRING: { |
86 |
|
|
throw NotImplementedException(HERE); |
87 |
|
|
// but it should be |
88 |
|
|
break; |
89 |
|
|
} |
90 |
|
|
case ET_VARARGS: /* may-not-happen */ |
91 |
|
|
ASSERT(0); |
92 |
|
|
break; |
93 |
|
|
} |
94 |
|
|
return NULL; |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
String *Function::evalString() const |
98 |
|
|
{ |
99 |
|
|
EvalType type = getReturnType(); |
100 |
|
|
switch (type) { |
101 |
|
|
case ET_INTEGER: { |
102 |
|
|
SInt64 *u = evalInteger(); |
103 |
|
|
String *s = new String(); |
104 |
|
|
s->assignFormat("%qd", u->value); |
105 |
|
|
delete u; |
106 |
|
|
return s; |
107 |
|
|
} |
108 |
|
|
case ET_FLOAT: { |
109 |
|
|
Float *f = evalFloat(); |
110 |
|
|
String *s = new String(); |
111 |
|
|
s->assignFormat("%f", f->value); |
112 |
|
|
delete f; |
113 |
|
|
return s; |
114 |
|
|
} |
115 |
|
|
case ET_STRING: throw NotImplementedException(HERE); |
116 |
|
|
case ET_VARARGS: /* may-not-happen */ |
117 |
|
|
ASSERT(0); |
118 |
|
|
break; |
119 |
|
|
} |
120 |
|
|
return NULL; |
121 |
|
|
} |
122 |
|
|
|
123 |
|
|
uint Function::getArgCount() const |
124 |
|
|
{ |
125 |
|
|
return 0; |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
Function *Function::getArg(uint i) const |
129 |
|
|
{ |
130 |
|
|
throw IllegalArgumentException(HERE); |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
void Function::setArg(uint i, Function *f) |
134 |
|
|
{ |
135 |
|
|
throw IllegalArgumentException(HERE); |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
/* |
139 |
|
|
* A constant integer function |
140 |
|
|
*/ |
141 |
|
|
SInt64Function::SInt64Function(sint64 v) |
142 |
|
|
{ |
143 |
|
|
value = v; |
144 |
|
|
} |
145 |
|
|
|
146 |
|
|
EvalType SInt64Function::getReturnType() const |
147 |
|
|
{ |
148 |
|
|
return ET_INTEGER; |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
SInt64 *SInt64Function::evalInteger() const |
152 |
|
|
{ |
153 |
|
|
return new SInt64(value); |
154 |
|
|
} |
155 |
|
|
|
156 |
|
|
/* |
157 |
|
|
* A GPR |
158 |
|
|
*/ |
159 |
|
|
GPRFunction::GPRFunction(int number) |
160 |
|
|
{ |
161 |
|
|
mNumber = number; |
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
EvalType GPRFunction::getReturnType() const |
165 |
|
|
{ |
166 |
|
|
return ET_INTEGER; |
167 |
|
|
} |
168 |
|
|
|
169 |
|
|
SInt64 *GPRFunction::evalInteger() const |
170 |
|
|
{ |
171 |
|
|
#ifdef HAVE_DEBUGGER |
172 |
|
|
return new SInt64(gCPU.gpr[mNumber]); |
173 |
|
|
#else |
174 |
|
|
return NULL; |
175 |
|
|
#endif |
176 |
|
|
} |
177 |
|
|
|
178 |
|
|
FPRFunction::FPRFunction(int number) |
179 |
|
|
{ |
180 |
|
|
mNumber = number; |
181 |
|
|
} |
182 |
|
|
|
183 |
|
|
EvalType FPRFunction::getReturnType() const |
184 |
|
|
{ |
185 |
|
|
return ET_FLOAT; |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
Float *FPRFunction::evalFloat() const |
189 |
|
|
{ |
190 |
|
|
#ifdef HAVE_DEBUGGER |
191 |
|
|
double_uint64 du = { gCPU.fpr[mNumber] }; |
192 |
|
|
return new Float(du.d); |
193 |
|
|
#else |
194 |
|
|
return NULL; |
195 |
|
|
#endif |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
UInt32PFunction::UInt32PFunction(uint32 *aValue) |
199 |
|
|
{ |
200 |
|
|
mValue = aValue; |
201 |
|
|
} |
202 |
|
|
|
203 |
|
|
EvalType UInt32PFunction::getReturnType() const |
204 |
|
|
{ |
205 |
|
|
return ET_INTEGER; |
206 |
|
|
} |
207 |
|
|
|
208 |
|
|
SInt64 *UInt32PFunction::evalInteger() const |
209 |
|
|
{ |
210 |
|
|
return new SInt64(*mValue); |
211 |
|
|
} |
212 |
|
|
|
213 |
|
|
/* |
214 |
|
|
* A constant float function |
215 |
|
|
*/ |
216 |
|
|
FloatFunction::FloatFunction(double v) |
217 |
|
|
{ |
218 |
|
|
value = v; |
219 |
|
|
} |
220 |
|
|
|
221 |
|
|
EvalType FloatFunction::getReturnType() const |
222 |
|
|
{ |
223 |
|
|
return ET_FLOAT; |
224 |
|
|
} |
225 |
|
|
|
226 |
|
|
Float *FloatFunction::evalFloat() const |
227 |
|
|
{ |
228 |
|
|
return new Float(value); |
229 |
|
|
} |
230 |
|
|
|
231 |
|
|
/* |
232 |
|
|
* A constant string function |
233 |
|
|
*/ |
234 |
|
|
StringFunction::StringFunction(const byte *str, int len) |
235 |
|
|
: value(str, len) |
236 |
|
|
{ |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
EvalType StringFunction::getReturnType() const |
240 |
|
|
{ |
241 |
|
|
return ET_STRING; |
242 |
|
|
} |
243 |
|
|
|
244 |
|
|
String *StringFunction::evalString() const |
245 |
|
|
{ |
246 |
|
|
return value.clone(); |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
/** |
250 |
|
|
* A parametrized function (implementation helper) |
251 |
|
|
*/ |
252 |
|
|
|
253 |
|
|
PFunction::PFunction() |
254 |
|
|
: mArgs(true) |
255 |
|
|
{ |
256 |
|
|
} |
257 |
|
|
|
258 |
|
|
uint PFunction::getArgCount() const |
259 |
|
|
{ |
260 |
|
|
return mArgs.count(); |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
Function *PFunction::getArg(uint i) const |
264 |
|
|
{ |
265 |
|
|
Function *r = (Function*)mArgs[i]; |
266 |
|
|
if (!r) throw IllegalArgumentException(HERE); |
267 |
|
|
return r; |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
void PFunction::setArg(uint i, Function *f) |
271 |
|
|
{ |
272 |
|
|
mArgs.forceSetByIdx(i, f); |
273 |
|
|
} |
274 |
|
|
|
275 |
|
|
/* |
276 |
|
|
* An expression parser |
277 |
|
|
*/ |
278 |
|
|
|
279 |
|
|
enum protoMatchQuality { |
280 |
|
|
PMQ_EXACT, |
281 |
|
|
PMQ_OK, |
282 |
|
|
PMQ_NOT_OK |
283 |
|
|
}; |
284 |
|
|
|
285 |
|
|
static bool convertsInto(EvalType from, EvalType to) |
286 |
|
|
{ |
287 |
|
|
switch (from) { |
288 |
|
|
case ET_INTEGER: |
289 |
|
|
return true; |
290 |
|
|
case ET_FLOAT: |
291 |
|
|
return (to != ET_INTEGER); |
292 |
|
|
case ET_STRING: |
293 |
|
|
return (to == ET_STRING); |
294 |
|
|
case ET_VARARGS: |
295 |
|
|
/* may-not-happen */ |
296 |
|
|
break; |
297 |
|
|
} |
298 |
|
|
return false; |
299 |
|
|
} |
300 |
|
|
|
301 |
|
|
static protoMatchQuality matchFunctionPrototype(const Enumerator ¶ms, uint count, EvalType *decl) |
302 |
|
|
{ |
303 |
|
|
if (params.count() < count) return PMQ_NOT_OK; |
304 |
|
|
uint pcount = params.count(); |
305 |
|
|
if (count && (decl[count-1] == ET_VARARGS)) { |
306 |
|
|
count--; |
307 |
|
|
pcount = count; |
308 |
|
|
} |
309 |
|
|
if (count == pcount) { |
310 |
|
|
protoMatchQuality r = PMQ_EXACT; |
311 |
|
|
for (uint i=0; i<count; i++) { |
312 |
|
|
Function *f = (Function*)params[i]; |
313 |
|
|
if (!convertsInto(f->getReturnType(), decl[i])) return PMQ_NOT_OK; |
314 |
|
|
if (f->getReturnType() != decl[i]) r = PMQ_OK; |
315 |
|
|
} |
316 |
|
|
return r; |
317 |
|
|
} |
318 |
|
|
return PMQ_NOT_OK; |
319 |
|
|
} |
320 |
|
|
|
321 |
|
|
static Function *matchFunctionByDesc(const String &name, const Enumerator ¶ms, FunctionDesc *descs) |
322 |
|
|
{ |
323 |
|
|
protoMatchQuality bestPMQ = PMQ_NOT_OK; |
324 |
|
|
FunctionDesc *bestMatch = NULL; |
325 |
|
|
while (descs->name) { |
326 |
|
|
if (strcmp(descs->name, name.contentChar()) == 0) { |
327 |
|
|
protoMatchQuality pmq = matchFunctionPrototype(params, descs->declparam_count, descs->declparam); |
328 |
|
|
if (pmq == PMQ_EXACT) { |
329 |
|
|
// if its exact take it immediately |
330 |
|
|
bestPMQ = PMQ_EXACT; |
331 |
|
|
bestMatch = descs; |
332 |
|
|
break; |
333 |
|
|
} else if ((bestPMQ == PMQ_NOT_OK) && (pmq == PMQ_OK)) { |
334 |
|
|
// try to take the first thats ok |
335 |
|
|
bestPMQ = PMQ_OK; |
336 |
|
|
bestMatch = descs; |
337 |
|
|
} |
338 |
|
|
} |
339 |
|
|
descs++; |
340 |
|
|
} |
341 |
|
|
if (bestPMQ != PMQ_NOT_OK) { |
342 |
|
|
Function *r = bestMatch->creator(); |
343 |
|
|
for (uint i=0; i<params.count(); i++) { |
344 |
|
|
r->setArg(i, (Function*)params[i]); |
345 |
|
|
} |
346 |
|
|
return r; |
347 |
|
|
} |
348 |
|
|
return NULL; |
349 |
|
|
} |
350 |
|
|
|
351 |
|
|
Watch::Watch(String *aName, Function *aFunc) |
352 |
|
|
{ |
353 |
|
|
mName = aName->clone(); |
354 |
|
|
f = aFunc; |
355 |
|
|
} |
356 |
|
|
|
357 |
|
|
Watch::~Watch() |
358 |
|
|
{ |
359 |
|
|
delete mName; |
360 |
|
|
delete f; |
361 |
|
|
} |
362 |
|
|
|
363 |
|
|
int Watch::toString(char *buf, int buflen) const |
364 |
|
|
{ |
365 |
|
|
SInt64 *sint = f->evalInteger(); |
366 |
|
|
String *s = f->evalString(); |
367 |
|
|
int ret = ht_snprintf(buf, buflen, "watch: '%y' = %y (0x%08x)", mName, s, (uint32)sint->value); |
368 |
|
|
delete sint; |
369 |
|
|
delete s; |
370 |
|
|
return ret; |
371 |
|
|
} |
372 |
|
|
|
373 |
|
|
Debugger::Debugger() |
374 |
|
|
{ |
375 |
|
|
mWatches = new LinkedList(true); |
376 |
|
|
#ifdef HAVE_DEBUGGER |
377 |
|
|
savedCPUState = gCPU; |
378 |
|
|
#endif |
379 |
|
|
mUseColors = true; |
380 |
|
|
} |
381 |
|
|
|
382 |
|
|
Debugger::~Debugger() |
383 |
|
|
{ |
384 |
|
|
delete mWatches; |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
Function *Debugger::eval_scalarToFunction(eval_scalar &s) |
388 |
|
|
{ |
389 |
|
|
switch (s.type) { |
390 |
|
|
case SCALAR_INT: |
391 |
|
|
return new SInt64Function(s.scalar.integer.value); |
392 |
|
|
case SCALAR_FLOAT: |
393 |
|
|
return new FloatFunction(s.scalar.floatnum.value); |
394 |
|
|
case SCALAR_REG: |
395 |
|
|
switch (s.scalar.reg.type) { |
396 |
|
|
case REG_GPR: |
397 |
|
|
return new GPRFunction(s.scalar.reg.num); |
398 |
|
|
case REG_FPR: |
399 |
|
|
return new FPRFunction(s.scalar.reg.num); |
400 |
|
|
#ifdef HAVE_DEBUGGER |
401 |
|
|
case REG_PC: |
402 |
|
|
return new UInt32PFunction(&gCPU.pc); |
403 |
|
|
case REG_LR: |
404 |
|
|
return new UInt32PFunction(&gCPU.lr); |
405 |
|
|
case REG_CR: |
406 |
|
|
return new UInt32PFunction(&gCPU.cr); |
407 |
|
|
case REG_CTR: |
408 |
|
|
return new UInt32PFunction(&gCPU.ctr); |
409 |
|
|
case REG_XER: |
410 |
|
|
return new UInt32PFunction(&gCPU.xer); |
411 |
|
|
case REG_MSR: |
412 |
|
|
return new UInt32PFunction(&gCPU.msr); |
413 |
|
|
case REG_SRR0: |
414 |
|
|
return new UInt32PFunction(&gCPU.srr[0]); |
415 |
|
|
case REG_SRR1: |
416 |
|
|
return new UInt32PFunction(&gCPU.srr[1]); |
417 |
|
|
#endif |
418 |
|
|
} |
419 |
|
|
break; |
420 |
|
|
case SCALAR_STR: |
421 |
|
|
return new StringFunction((byte*)s.scalar.str.value, s.scalar.str.len); |
422 |
|
|
case SCALAR_FUNCTION: { |
423 |
|
|
Array p(false); |
424 |
|
|
for (int i=0; i<s.scalar.function.param_count; i++) { |
425 |
|
|
p += eval_scalarToFunction(s.scalar.function.params[i]); |
426 |
|
|
} |
427 |
|
|
return matchFunction(s.scalar.function.name, p); |
428 |
|
|
} |
429 |
|
|
case SCALAR_EMPTY: |
430 |
|
|
return NULL; |
431 |
|
|
case SCALAR_ANY: |
432 |
|
|
case SCALAR_VARARGS: |
433 |
|
|
/* may-not-happen */ |
434 |
|
|
break; |
435 |
|
|
} |
436 |
|
|
/* may-not-happen */ |
437 |
|
|
ASSERT(0); |
438 |
|
|
return NULL; |
439 |
|
|
} |
440 |
|
|
|
441 |
|
|
Function *Debugger::matchFunction(const String &name, const Enumerator ¶ms) |
442 |
|
|
{ |
443 |
|
|
Function *r = matchFunctionByDesc(name, params, gStdEvalFunctions); |
444 |
|
|
if (!r) { |
445 |
|
|
String msg; |
446 |
|
|
msg.assignFormat("parse/eval: no function matching signature '%y(", &name); |
447 |
|
|
for (uint i=0; i<params.count(); i++) { |
448 |
|
|
Function *f = (Function*)params[i]; |
449 |
|
|
switch (f->getReturnType()) { |
450 |
|
|
case ET_INTEGER: |
451 |
|
|
msg.append("integer"); |
452 |
|
|
break; |
453 |
|
|
case ET_FLOAT: |
454 |
|
|
msg.append("float"); |
455 |
|
|
break; |
456 |
|
|
case ET_STRING: |
457 |
|
|
msg.append("string"); |
458 |
|
|
break; |
459 |
|
|
case ET_VARARGS: |
460 |
|
|
/* may-not-happen */ |
461 |
|
|
ASSERT(0); |
462 |
|
|
break; |
463 |
|
|
} |
464 |
|
|
if (i+1<params.count()) msg.append(","); |
465 |
|
|
} |
466 |
|
|
msg.append(")'"); |
467 |
|
|
throw MsgException(msg.contentChar()); |
468 |
|
|
} |
469 |
|
|
return r; |
470 |
|
|
} |
471 |
|
|
|
472 |
|
|
inline static void disasm(uint32 code, uint32 ea, char *result) |
473 |
|
|
{ |
474 |
|
|
PPCDisassembler dis; |
475 |
|
|
CPU_ADDR addr; |
476 |
|
|
addr.addr32.offset = ea; |
477 |
|
|
strcpy(result, dis.str(dis.decode((byte*)&code, 4, addr), 0)); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
void Debugger::dump() |
481 |
|
|
{ |
482 |
|
|
#ifdef HAVE_DEBUGGER |
483 |
|
|
int r = 0; |
484 |
|
|
const char *hiColor, *loColor; |
485 |
|
|
if (mUseColors) { |
486 |
|
|
hiColor = "\e[33;1m"; |
487 |
|
|
loColor = "\e[37;1m"; |
488 |
|
|
} else { |
489 |
|
|
hiColor = ""; |
490 |
|
|
loColor = ""; |
491 |
|
|
} |
492 |
|
|
for (int i=0; i<8; i++) { |
493 |
|
|
for (int j=0; j<4; j++) { |
494 |
|
|
ht_printf("r%02d: %s%08x%s ", r, (savedCPUState.gpr[r] != gCPU.gpr[r])?hiColor:loColor , gCPU.gpr[r], loColor); |
495 |
|
|
r++; |
496 |
|
|
} |
497 |
|
|
ht_printf("\n"); |
498 |
|
|
} |
499 |
|
|
/* ht_printf("dbatu0: %08x dbatl0: %08x\n", gCPU.dbatu[0], gCPU.dbatl[0]); |
500 |
|
|
ht_printf("dbatu1: %08x dbatl1: %08x\n", gCPU.dbatu[1], gCPU.dbatl[1]); |
501 |
|
|
ht_printf("dbatu2: %08x dbatl2: %08x\n", gCPU.dbatu[2], gCPU.dbatl[2]); |
502 |
|
|
ht_printf("dbatu3: %08x dbatl3: %08x\n", gCPU.dbatu[3], gCPU.dbatl[3]);*/ |
503 |
|
|
ht_printf("cr: %s%08x%s xer: %s%08x%s lr: %s%08x%s ctr: %s%08x%s\n", |
504 |
|
|
(savedCPUState.cr != gCPU.cr)?hiColor:loColor, gCPU.cr, loColor, |
505 |
|
|
(savedCPUState.xer != gCPU.xer)?hiColor:loColor, gCPU.xer, loColor, |
506 |
|
|
(savedCPUState.lr != gCPU.lr)?hiColor:loColor, gCPU.lr, loColor, |
507 |
|
|
(savedCPUState.ctr != gCPU.ctr)?hiColor:loColor, gCPU.ctr, loColor); |
508 |
|
|
// ht_printf("msr: %08x sv: %d srr1: %08x\n", gCPU.msr, (gCPU.msr & MSR_PR) ? 0 : 1, gCPU.srr[1]); |
509 |
|
|
|
510 |
|
|
foreach(Watch, w, *mWatches, { |
511 |
|
|
ht_printf("%y\n", w); |
512 |
|
|
}); |
513 |
|
|
|
514 |
|
|
char disstr[256]; |
515 |
|
|
disasm(gCPU.current_opc, gCPU.pc, disstr); |
516 |
|
|
ht_printf("@%08x: %08x %s\n", gCPU.pc, gCPU.current_opc, disstr); |
517 |
|
|
|
518 |
|
|
if (disstr[0] == 'b') { |
519 |
|
|
int i = 1; |
520 |
|
|
while (disstr[i] && disstr[i] != ' ') i++; |
521 |
|
|
if (disstr[i-1] != 'l') { |
522 |
|
|
mForceSinglestep = true; |
523 |
|
|
} |
524 |
|
|
} |
525 |
|
|
#endif |
526 |
|
|
} |
527 |
|
|
|
528 |
|
|
static void displayFPRs() |
529 |
|
|
{ |
530 |
|
|
#if 0 |
531 |
|
|
for (int i=0; i<32; i++) { |
532 |
|
|
ppc_double dd; |
533 |
|
|
ppc_fpu_unpack_double(dd, gCPU.fpr[i]); |
534 |
|
|
double d = ppc_fpu_get_double(dd); |
535 |
|
|
ht_printf("fr%02d: ", i); |
536 |
|
|
switch (dd.type) { |
537 |
|
|
case ppc_fpr_norm: |
538 |
|
|
ht_printf("%c%qb * 2^%d = %f", dd.s?'-':'+', &dd.m, dd.e, d); |
539 |
|
|
break; |
540 |
|
|
case ppc_fpr_zero: |
541 |
|
|
ht_printf("%c0.0", dd.s?'-':'+'); |
542 |
|
|
break; |
543 |
|
|
case ppc_fpr_Inf: |
544 |
|
|
ht_printf("%cInf", dd.s?'-':'+'); |
545 |
|
|
break; |
546 |
|
|
case ppc_fpr_NaN: |
547 |
|
|
ht_printf("%cNaN", dd.s?'-':'+'); |
548 |
|
|
break; |
549 |
|
|
} |
550 |
|
|
ht_printf("\n"); |
551 |
|
|
ht_printf(" = %qx\n", &gCPU.fpr[i]); |
552 |
|
|
} |
553 |
|
|
#endif |
554 |
|
|
} |
555 |
|
|
|
556 |
|
|
static bool translateAddress(uint32 ea, uint32 &pa, bool error) |
557 |
|
|
{ |
558 |
|
|
#ifdef HAVE_DEBUGGER |
559 |
|
|
if (ppc_effective_to_physical(ea, PPC_MMU_READ|PPC_MMU_NO_EXC|PPC_MMU_SV, pa)) { |
560 |
|
|
if (error) ht_printf("cant translate effective address %08x\n", ea); |
561 |
|
|
return false; |
562 |
|
|
} else { |
563 |
|
|
return true; |
564 |
|
|
} |
565 |
|
|
#endif |
566 |
|
|
} |
567 |
|
|
|
568 |
|
|
bool Debugger::parse(const String &str) |
569 |
|
|
{ |
570 |
|
|
eval_command s; |
571 |
|
|
bool ret = false; |
572 |
|
|
memset(&s, 0, sizeof s); |
573 |
|
|
if (!eval_parse(&s, str.contentChar())) { |
574 |
|
|
char *str2; |
575 |
|
|
int pos; |
576 |
|
|
if (!get_eval_error(&str2, &pos)) { |
577 |
|
|
str2 = "internal error! please report!"; |
578 |
|
|
pos = 0; |
579 |
|
|
} |
580 |
|
|
throw MsgfException("error: %s at %d", str2, pos); |
581 |
|
|
} else { |
582 |
|
|
Function *params[3]; |
583 |
|
|
for (int i=0; i<s.paramcount; i++) { |
584 |
|
|
params[i] = eval_scalarToFunction(s.param[i]); |
585 |
|
|
} |
586 |
|
|
switch (s.type) { |
587 |
|
|
case COMMAND_NOP: break; |
588 |
|
|
case COMMAND_PRINT: { |
589 |
|
|
String *s = params[0]->evalString(); |
590 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
591 |
|
|
ht_printf("= %y (0x%08x)\n", s, sint->value); |
592 |
|
|
delete s; |
593 |
|
|
delete sint; |
594 |
|
|
break; |
595 |
|
|
} |
596 |
|
|
case COMMAND_REGS: |
597 |
|
|
dump(); |
598 |
|
|
break; |
599 |
|
|
case COMMAND_FLOATS: |
600 |
|
|
displayFPRs(); |
601 |
|
|
break; |
602 |
|
|
case COMMAND_SETREG: { |
603 |
|
|
SInt64 *sint = params[1]->evalInteger(); |
604 |
|
|
switch (s.param[0].scalar.reg.type) { |
605 |
|
|
#ifdef HAVE_DEBUGGER |
606 |
|
|
case REG_GPR: |
607 |
|
|
gCPU.gpr[s.param[0].scalar.reg.num] = sint->value; |
608 |
|
|
break; |
609 |
|
|
case REG_FPR: { |
610 |
|
|
Float *f = params[1]->evalFloat(); |
611 |
|
|
double_uint64 du; |
612 |
|
|
du.d = f->value; |
613 |
|
|
gCPU.fpr[s.param[0].scalar.reg.num] = du.u; |
614 |
|
|
delete f; |
615 |
|
|
break; |
616 |
|
|
} |
617 |
|
|
case REG_PC: |
618 |
|
|
gCPU.pc = gCPU.npc = sint->value; |
619 |
|
|
break; |
620 |
|
|
case REG_CR: |
621 |
|
|
gCPU.cr = sint->value; |
622 |
|
|
break; |
623 |
|
|
case REG_LR: |
624 |
|
|
gCPU.lr = sint->value; |
625 |
|
|
break; |
626 |
|
|
case REG_CTR: |
627 |
|
|
gCPU.ctr = sint->value; |
628 |
|
|
break; |
629 |
|
|
case REG_XER: |
630 |
|
|
gCPU.xer = sint->value; |
631 |
|
|
break; |
632 |
|
|
case REG_MSR: |
633 |
|
|
gCPU.msr = sint->value; |
634 |
|
|
break; |
635 |
|
|
case REG_SRR0: |
636 |
|
|
gCPU.srr[0] = sint->value; |
637 |
|
|
break; |
638 |
|
|
case REG_SRR1: |
639 |
|
|
gCPU.srr[1] = sint->value; |
640 |
|
|
break; |
641 |
|
|
#endif |
642 |
|
|
} |
643 |
|
|
delete sint; |
644 |
|
|
break; |
645 |
|
|
} |
646 |
|
|
#ifdef HAVE_DEBUGGER |
647 |
|
|
case COMMAND_LIST_BREAK: |
648 |
|
|
ht_printf("Breakpoint %d at %08x\n", 1, gBreakpoint); |
649 |
|
|
ht_printf("Breakpoint %d at %08x\n", 2, gBreakpoint2); |
650 |
|
|
break; |
651 |
|
|
case COMMAND_BREAK: { |
652 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
653 |
|
|
gBreakpoint2 = sint->value; |
654 |
|
|
ht_printf("Breakpoint %d at %08x\n", 2, gBreakpoint2); |
655 |
|
|
break; |
656 |
|
|
} |
657 |
|
|
case COMMAND_STEP: |
658 |
|
|
ppc_set_singlestep_nonverbose(true); |
659 |
|
|
ret = true; |
660 |
|
|
break; |
661 |
|
|
case COMMAND_NEXT: |
662 |
|
|
gBreakpoint = gCPU.npc; |
663 |
|
|
if (mForceSinglestep) { |
664 |
|
|
ppc_set_singlestep_nonverbose(true); |
665 |
|
|
} else { |
666 |
|
|
gBreakpoint = gCPU.npc; |
667 |
|
|
ppc_set_singlestep_nonverbose(false); |
668 |
|
|
} |
669 |
|
|
ret = true; |
670 |
|
|
break; |
671 |
|
|
case COMMAND_CONTINUE: |
672 |
|
|
ppc_set_singlestep_nonverbose(false); |
673 |
|
|
ret = true; |
674 |
|
|
break; |
675 |
|
|
case COMMAND_QUIT: |
676 |
|
|
ppc_cpu_stop(); |
677 |
|
|
ppc_set_singlestep_nonverbose(false); |
678 |
|
|
ret = true; |
679 |
|
|
break; |
680 |
|
|
#endif |
681 |
|
|
case COMMAND_E2P: { |
682 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
683 |
|
|
uint32 pa, ea = sint->value; |
684 |
|
|
if (translateAddress(ea, pa, true)) { |
685 |
|
|
ht_printf("effective: %08x, physical: %08x\n", ea, pa); |
686 |
|
|
} |
687 |
|
|
delete sint; |
688 |
|
|
break; |
689 |
|
|
} |
690 |
|
|
case COMMAND_INSPECT_BYTE: { |
691 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
692 |
|
|
uint32 pa, ea = sint->value; |
693 |
|
|
uint8 v; |
694 |
|
|
if (translateAddress(ea, pa, true)) { |
695 |
|
|
#ifdef HAVE_DEBUGGER |
696 |
|
|
if (ppc_read_physical_byte(pa, v)) { |
697 |
|
|
ht_printf("cant read at physical address %08x\n", pa); |
698 |
|
|
} else { |
699 |
|
|
ht_printf("@%08x: %02x (physical: %08x)\n", ea, v, pa); |
700 |
|
|
} |
701 |
|
|
#endif |
702 |
|
|
} |
703 |
|
|
delete sint; |
704 |
|
|
break; |
705 |
|
|
} |
706 |
|
|
case COMMAND_INSPECT_HALF: { |
707 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
708 |
|
|
uint32 pa, ea = sint->value; |
709 |
|
|
uint16 v; |
710 |
|
|
if (translateAddress(ea, pa, true)) { |
711 |
|
|
#ifdef HAVE_DEBUGGER |
712 |
|
|
if (ppc_read_physical_half(pa, v)) { |
713 |
|
|
ht_printf("cant read at physical address %08x\n", pa); |
714 |
|
|
} else { |
715 |
|
|
ht_printf("@%08x: %04x (physical: %08x)\n", ea, v, pa); |
716 |
|
|
} |
717 |
|
|
#endif |
718 |
|
|
} |
719 |
|
|
delete sint; |
720 |
|
|
break; |
721 |
|
|
} |
722 |
|
|
case COMMAND_INSPECT_WORD: { |
723 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
724 |
|
|
uint32 pa, ea = sint->value; |
725 |
|
|
delete sint; |
726 |
|
|
uint32 v; |
727 |
|
|
if (translateAddress(ea, pa, true)) { |
728 |
|
|
#ifdef HAVE_DEBUGGER |
729 |
|
|
if (ppc_read_physical_word(pa, v)) { |
730 |
|
|
ht_printf("cant read at physical address %08x\n", pa); |
731 |
|
|
} else { |
732 |
|
|
ht_printf("@%08x: %08x (physical: %08x)\n", ea, v, pa); |
733 |
|
|
} |
734 |
|
|
#endif |
735 |
|
|
} |
736 |
|
|
break; |
737 |
|
|
} |
738 |
|
|
case COMMAND_INSPECT_DWORD: { |
739 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
740 |
|
|
uint32 pa, ea = sint->value; |
741 |
|
|
delete sint; |
742 |
|
|
uint64 v; |
743 |
|
|
if (translateAddress(ea, pa, true)) { |
744 |
|
|
#ifdef HAVE_DEBUGGER |
745 |
|
|
if (ppc_read_physical_dword(pa, v)) { |
746 |
|
|
ht_printf("cant read at physical address %08x\n", pa); |
747 |
|
|
} else { |
748 |
|
|
ht_printf("@%08x: %016x (physical: %08x)\n", ea, v, pa); |
749 |
|
|
} |
750 |
|
|
#endif |
751 |
|
|
} |
752 |
|
|
break; |
753 |
|
|
} |
754 |
|
|
case COMMAND_INSPECT_STRING: { |
755 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
756 |
|
|
uint32 pa, ea = sint->value; |
757 |
|
|
delete sint; |
758 |
|
|
byte *v; |
759 |
|
|
if (translateAddress(ea, pa, true)) { |
760 |
|
|
#ifdef HAVE_DEBUGGER |
761 |
|
|
if (ppc_direct_physical_memory_handle(pa, v)) { |
762 |
|
|
ht_printf("cant read at physical address %08x\n", pa); |
763 |
|
|
} else { |
764 |
|
|
ht_printf("@%08x: '%s' (physical: %08x)\n", ea, v, pa); |
765 |
|
|
} |
766 |
|
|
#endif |
767 |
|
|
} |
768 |
|
|
break; |
769 |
|
|
} |
770 |
|
|
case COMMAND_INSPECT_MEM: { |
771 |
|
|
SInt64 *sint = params[0]->evalInteger(); |
772 |
|
|
uint32 pa, ea = sint->value; |
773 |
|
|
uint32 count = 0x100; |
774 |
|
|
delete sint; |
775 |
|
|
byte v; |
776 |
|
|
int x = 0; |
777 |
|
|
char buf[80]; |
778 |
|
|
memset(buf, ' ', sizeof buf); |
779 |
|
|
buf[79] = 0; |
780 |
|
|
buf[sprintf(buf, "@%08x", ea)] = ' '; |
781 |
|
|
while (count) { |
782 |
|
|
if (translateAddress(ea, pa, true)) { |
783 |
|
|
#ifdef HAVE_DEBUGGER |
784 |
|
|
if (ppc_read_physical_byte(pa, v)) { |
785 |
|
|
ht_printf("cant read at physical address %08x\n", pa); |
786 |
|
|
break; |
787 |
|
|
} else { |
788 |
|
|
// ht_printf("@%08x: '%s' (physical: %08x)\n", ea, v, pa); |
789 |
|
|
sprintf(buf+10+(x%16)*3, "%02x", v); |
790 |
|
|
buf[10+(x%16)*3+2] = ' '; |
791 |
|
|
sprintf(buf+10+16*3+x%16, "%c", (v>=32 && v<=127)?v:' '); |
792 |
|
|
buf[10+16*3+x%16+1] = ' '; |
793 |
|
|
} |
794 |
|
|
#endif |
795 |
|
|
} else { |
796 |
|
|
break; |
797 |
|
|
} |
798 |
|
|
count--; |
799 |
|
|
ea++; |
800 |
|
|
x++; |
801 |
|
|
if (x % 16 == 0) { |
802 |
|
|
ht_printf("%s\n", buf); |
803 |
|
|
memset(buf, ' ', sizeof buf); |
804 |
|
|
buf[79] = 0; |
805 |
|
|
buf[sprintf(buf, "@%08x", ea)] = ' '; |
806 |
|
|
} |
807 |
|
|
} |
808 |
|
|
if (x % 16) ht_printf("%s\n", buf); |
809 |
|
|
break; |
810 |
|
|
} |
811 |
|
|
case COMMAND_WATCH: { |
812 |
|
|
String *name; |
813 |
|
|
if (params[1]) { |
814 |
|
|
name = params[1]->evalString(); |
815 |
|
|
} else { |
816 |
|
|
name = new String("noname"); |
817 |
|
|
} |
818 |
|
|
mWatches->insert(new Watch(name, eval_scalarToFunction(s.param[0]))); |
819 |
|
|
break; |
820 |
|
|
} |
821 |
|
|
case COMMAND_WATCH_BYTE: |
822 |
|
|
case COMMAND_WATCH_HALF: |
823 |
|
|
case COMMAND_WATCH_WORD: |
824 |
|
|
case COMMAND_WATCH_DWORD: |
825 |
|
|
case COMMAND_DELETE_WATCH: |
826 |
|
|
case COMMAND_DUMP: |
827 |
|
|
case COMMAND_DISASM: { |
828 |
|
|
#ifdef HAVE_DEBUGGER |
829 |
|
|
uint32 ea, pa; |
830 |
|
|
if (params[0]) { |
831 |
|
|
SInt64 *sint; |
832 |
|
|
sint = params[0]->evalInteger(); |
833 |
|
|
ea = sint->value & ~3; |
834 |
|
|
delete sint; |
835 |
|
|
} else { |
836 |
|
|
ea = gCPU.pc; |
837 |
|
|
} |
838 |
|
|
uint32 count; |
839 |
|
|
if (params[1]) { |
840 |
|
|
SInt64 *sint; |
841 |
|
|
sint = params[1]->evalInteger(); |
842 |
|
|
count = sint->value; |
843 |
|
|
delete sint; |
844 |
|
|
} else { |
845 |
|
|
count = 16; |
846 |
|
|
} |
847 |
|
|
while (count) { |
848 |
|
|
uint32 opc; |
849 |
|
|
if (translateAddress(ea, pa, true)) { |
850 |
|
|
if (ppc_read_physical_word(pa, opc)) { |
851 |
|
|
ht_printf("cant read at physical address %08x\n", pa); |
852 |
|
|
break; |
853 |
|
|
} |
854 |
|
|
} else { |
855 |
|
|
break; |
856 |
|
|
} |
857 |
|
|
char disstr[256]; |
858 |
|
|
disasm(opc, gCPU.pc, disstr); |
859 |
|
|
ht_printf("@%08x: %08x %s\n", ea, opc, disstr); |
860 |
|
|
count--; |
861 |
|
|
ea+=4; |
862 |
|
|
} |
863 |
|
|
#endif |
864 |
|
|
break; |
865 |
|
|
} |
866 |
|
|
case COMMAND_HELP: |
867 |
|
|
ht_printf("bist du jeck?\n"); |
868 |
|
|
break; |
869 |
|
|
} |
870 |
|
|
for (int i=0; i<s.paramcount; i++) { |
871 |
|
|
delete params[i]; |
872 |
|
|
} |
873 |
|
|
} |
874 |
|
|
return ret; |
875 |
|
|
} |
876 |
|
|
|
877 |
|
|
void Debugger::enter() |
878 |
|
|
{ |
879 |
|
|
char buf[1024]; |
880 |
|
|
bool quit = false; |
881 |
|
|
if (mAlwaysShowRegs) dump(); |
882 |
|
|
|
883 |
|
|
/* |
884 |
|
|
* If current instruction is a branch instruction |
885 |
|
|
* which doesnt set LR we force single step |
886 |
|
|
*/ |
887 |
|
|
mForceSinglestep = false; |
888 |
|
|
char disstr[256]; |
889 |
|
|
#ifdef HAVE_DEBUGGER |
890 |
|
|
disasm(gCPU.current_opc, gCPU.pc, disstr); |
891 |
|
|
#endif |
892 |
|
|
if (disstr[0] == 'b') { |
893 |
|
|
int i = 1; |
894 |
|
|
while (disstr[i] && disstr[i] != ' ') i++; |
895 |
|
|
if (disstr[i-1] != 'l') { |
896 |
|
|
mForceSinglestep = true; |
897 |
|
|
} |
898 |
|
|
} |
899 |
|
|
#ifdef HAVE_DEBUGGER |
900 |
|
|
gBreakpoint = 0; |
901 |
|
|
#endif |
902 |
|
|
|
903 |
|
|
while (!quit) { |
904 |
|
|
printf("> "); |
905 |
|
|
fgets(buf, sizeof buf, stdin); |
906 |
|
|
try { |
907 |
|
|
quit = parse(buf); |
908 |
|
|
} catch (const Exception &e) { |
909 |
|
|
String s; |
910 |
|
|
ht_printf("%y\n", &e.reason(s)); |
911 |
|
|
continue; |
912 |
|
|
} |
913 |
|
|
} |
914 |
|
|
#ifdef HAVE_DEBUGGER |
915 |
|
|
savedCPUState = gCPU; |
916 |
|
|
#endif |
917 |
|
|
} |
918 |
|
|
|
919 |
|
|
#include "configparser.h" |
920 |
|
|
void debugger_init_config() |
921 |
|
|
{ |
922 |
|
|
gConfig->acceptConfigEntryString("debugger_exec", false); |
923 |
|
|
} |