Mercurial > projects > ddbg_continued
comparison src/cli/gdbcli.d @ 1:4a9dcbd9e54f
-files of 0.13 beta
-fixes so that it now compiles with the current dmd version
author | marton@basel.hu |
---|---|
date | Tue, 05 Apr 2011 20:44:01 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:586e4a649642 | 1:4a9dcbd9e54f |
---|---|
1 /* Ddbg - Win32 Debugger for the D programming language | |
2 * Copyright (c) 2007 Jascha Wetzel | |
3 * All rights reserved. See LICENSE.TXT for details. | |
4 */ | |
5 module cli.gdbcli; | |
6 | |
7 import std.string; | |
8 static import std.regexp; | |
9 import std.c.stdio : sscanf; | |
10 import std.c.string; | |
11 import std.demangle; | |
12 | |
13 import util; | |
14 import codeview.codeview; | |
15 import breakpoint; | |
16 import debugger; | |
17 import disasm; | |
18 import callstack; | |
19 import dbgprocess; | |
20 import dbgthread; | |
21 import expression.expression_apd; | |
22 import expression.datahandler : SymbolValue; | |
23 import expression.evaluationcontext; | |
24 import cli.userinterface; | |
25 | |
26 import win32.winbase; | |
27 import win32.winuser; | |
28 import win32.winnt; | |
29 | |
30 /************************************************************************************************** | |
31 | |
32 **************************************************************************************************/ | |
33 class GDBCLI : UserInterfaceBase | |
34 { | |
35 string[] lastcmd; | |
36 | |
37 uint current_frame_level; | |
38 | |
39 string prompt, | |
40 command_line, | |
41 debuggee; | |
42 bool fullname = false, | |
43 quit; | |
44 | |
45 /********************************************************************************************** | |
46 | |
47 **********************************************************************************************/ | |
48 this() | |
49 { | |
50 prompt = "(gdb) "; | |
51 } | |
52 | |
53 /********************************************************************************************** | |
54 | |
55 **********************************************************************************************/ | |
56 void init(string[] args) | |
57 { | |
58 DbgIO.println(WELCOME_STRING); | |
59 if ( args.length < 2 ) | |
60 throw new DebuggerException("Usage: ddbg -cli=gdb [-cmd=<commands>] [-fullname] -args <exe file> [arguments]"); | |
61 | |
62 bool read_args = false; | |
63 Lfe: foreach ( int i, a; args ) | |
64 { | |
65 switch ( a ) | |
66 { | |
67 case "-fullname": | |
68 case "--fullname": | |
69 fullname = true; | |
70 break; | |
71 case "-args": | |
72 case "--args": | |
73 read_args=true; | |
74 break; | |
75 default: | |
76 debuggee = a; | |
77 if ( read_args ) | |
78 { | |
79 if ( find(a, ' ') >= 0 ) | |
80 command_line = "\""~a~"\""; | |
81 else | |
82 command_line = a; | |
83 if ( args.length > i+1 ) | |
84 command_line ~= " "~join(args[i+1..$], " "); | |
85 break Lfe; | |
86 } | |
87 } | |
88 } | |
89 | |
90 dbg = new Debugger(debuggee, this); | |
91 dbg.create_new_console = true; | |
92 } | |
93 | |
94 int start() | |
95 { | |
96 while ( !quit ) | |
97 { | |
98 try readCommand(); | |
99 catch ( Exception e ) | |
100 DbgIO.println(e.msg); | |
101 } | |
102 return 0; | |
103 } | |
104 | |
105 /********************************************************************************************** | |
106 | |
107 **********************************************************************************************/ | |
108 void singleStep() | |
109 { | |
110 DbgIO.println(describeLocation(dbg.current_address)); | |
111 } | |
112 | |
113 /********************************************************************************************** | |
114 | |
115 **********************************************************************************************/ | |
116 void exitProcess() | |
117 { | |
118 DbgIO.println("Program exited"); | |
119 } | |
120 | |
121 /********************************************************************************************** | |
122 | |
123 **********************************************************************************************/ | |
124 void loadedDLL(DLL dll) | |
125 { | |
126 if( dll !is null && dll.image.name.length ) | |
127 DbgIO.writeln(dll.image.name~" loaded"); | |
128 else | |
129 DbgIO.writeln("unknown DLL loaded"); | |
130 } | |
131 | |
132 /********************************************************************************************** | |
133 | |
134 **********************************************************************************************/ | |
135 void win32exception(uint threadId, EXCEPTION_RECORD* exrec) | |
136 { | |
137 DbgIO.println( | |
138 "Program received signal SIG Unhandled Exception: %s(0x%x) at 0x%x", | |
139 getExceptionName(exrec.ExceptionCode), exrec.ExceptionCode, exrec.ExceptionAddress //describeLocation(dbg.current_address) | |
140 ); | |
141 } | |
142 | |
143 /********************************************************************************************** | |
144 | |
145 **********************************************************************************************/ | |
146 void exception(uint threadId, string class_name, string msg, size_t obj_ptr) | |
147 { | |
148 DbgIO.println( | |
149 "Program received signal SIG Unhandled D Exception (%s%s) at %s", | |
150 class_name, msg.length>0?" \""~msg~"\"":"", describeLocation(dbg.current_address) | |
151 ); | |
152 } | |
153 | |
154 /********************************************************************************************** | |
155 | |
156 **********************************************************************************************/ | |
157 void userInterrupt() | |
158 { | |
159 DbgIO.println("User interrupt at %s", describeLocation(dbg.current_address)); | |
160 } | |
161 | |
162 /********************************************************************************************** | |
163 | |
164 **********************************************************************************************/ | |
165 bool breakpoint(int index, Breakpoint bp, DbgThread thread) | |
166 { | |
167 if ( bp.file is null || bp.line == 0 ) | |
168 DbgIO.println("Unknown breakpoint hit at %s", describeLocation(bp.address)); | |
169 else | |
170 DbgIO.println("\032\032%s:%d:0:begmidl:0x%08x", fullname?dbg.getFullSourcePath(bp.file):bp.file, bp.line, bp.address); | |
171 return true; | |
172 } | |
173 | |
174 /********************************************************************************************** | |
175 | |
176 **********************************************************************************************/ | |
177 void debugString(string str) | |
178 { | |
179 printf("Error OUTPUT DEBUG STRING:\n%s\n", toStringz(str)); | |
180 } | |
181 | |
182 /********************************************************************************************** | |
183 Command line parser. Gets called when debuggee is suspended. | |
184 **********************************************************************************************/ | |
185 bool parseCommand(string input) | |
186 { | |
187 if ( strip(input).length > 0 ) | |
188 { | |
189 auto r = std.regexp.RegExp("(([^\" \\t]+)|(\"[^\"]+\"))+"); | |
190 lastcmd.length = 0; | |
191 foreach ( m; r.search(strip(input)) ) | |
192 lastcmd ~= r.match(0); | |
193 } | |
194 if ( lastcmd.length <= 0 ) | |
195 return false; | |
196 | |
197 int slash_pos = find(lastcmd[0], '/'); | |
198 if ( slash_pos >= 0 ) { | |
199 lastcmd ~= lastcmd[0]; | |
200 lastcmd[0] = lastcmd[0][0..slash_pos]; | |
201 } | |
202 | |
203 switch ( lastcmd[0] ) | |
204 { | |
205 case "help": | |
206 DbgIO.println("GDB emulation mode - no help available, yet"); | |
207 break; | |
208 case "delete": | |
209 if ( lastcmd.length < 2 ) | |
210 DbgIO.println("Warning: too few arguments for set"); | |
211 else switch ( lastcmd[1] ) | |
212 { | |
213 case "breakpoints": | |
214 if ( lastcmd.length < 3 ) | |
215 { | |
216 foreach ( uint i; dbg.breakpoints.keys ) | |
217 dbg.removeBreakpoint(i); | |
218 } | |
219 else if ( !isNumeric(lastcmd[2]) ) | |
220 DbgIO.println("Warning: invalid breakpoint index '%s'", lastcmd[2]); | |
221 else | |
222 dbg.removeBreakpoint(cast(uint)atoi(lastcmd[2])); | |
223 break; | |
224 default: | |
225 DbgIO.println("Warning: unknown argument %s", lastcmd[1]); | |
226 } | |
227 break; | |
228 case "set": | |
229 if ( lastcmd.length < 2 ) | |
230 DbgIO.println("Warning: too few arguments for set"); | |
231 else switch ( lastcmd[1] ) | |
232 { | |
233 case "prompt": | |
234 if ( lastcmd.length < 3 ) | |
235 DbgIO.println("Warning: too few arguments for set prompt"); | |
236 else | |
237 prompt = lastcmd[2]; | |
238 break; | |
239 case "args": | |
240 if ( dbg.process_loaded ) | |
241 DbgIO.println("Warning: process already started"); | |
242 command_line = debuggee~" "~join(lastcmd[2..$], " "); | |
243 break; | |
244 default: | |
245 DbgIO.println("Warning: unknown variable %s", lastcmd[1]); | |
246 } | |
247 break; | |
248 case "info": | |
249 if ( lastcmd.length < 2 ) | |
250 DbgIO.println("Warning: too few arguments for info"); | |
251 else | |
252 { | |
253 switch ( lastcmd[1] ) | |
254 { | |
255 case "locals": | |
256 if ( dbg.process_loaded ) | |
257 { | |
258 uint scope_address = dbg.getScopeAddress(current_frame_level); | |
259 ScopeSymbol scope_sym = dbg.images.findProcedureSymbol(scope_address); | |
260 for ( ; scope_sym !is null; scope_sym = scope_sym.parent_scope ) | |
261 { | |
262 if ( scope_sym is null ) | |
263 DbgIO.println("No valid scope active"); | |
264 else | |
265 evalStackSymbols(scope_sym.symbols.stack_symbols); | |
266 } | |
267 } | |
268 break; | |
269 case "args": | |
270 if ( dbg.process_loaded ) | |
271 { | |
272 uint scope_address = dbg.getScopeAddress(current_frame_level); | |
273 ScopeSymbol scope_sym = dbg.images.findProcedureSymbol(scope_address); | |
274 for ( ; scope_sym !is null; scope_sym = scope_sym.parent_scope ) | |
275 { | |
276 if ( scope_sym is null ) | |
277 DbgIO.println("No valid scope active"); | |
278 else | |
279 { | |
280 auto psym = cast(ProcedureSymbol)scope_sym; | |
281 if ( psym !is null ) | |
282 evalStackSymbols(psym.arguments.stack_symbols); | |
283 } | |
284 } | |
285 } | |
286 break; | |
287 case "registers": | |
288 printRegisterDump(dbg.process.threads[dbg.thread_id]); | |
289 break; | |
290 case "frame": | |
291 uint scope_address = dbg.getScopeAddress(current_frame_level); | |
292 ubyte[] frame = dbg.stack.getFrame(current_frame_level); | |
293 Location loc = dbg.images.findLocation(scope_address); | |
294 DbgIO.print("Stack level %d, frame at ", current_frame_level); | |
295 if ( loc.scope_sym !is null ) { | |
296 ProcedureSymbol psym = cast(ProcedureSymbol)loc.scope_sym; | |
297 DbgIO.println("0x%x:", loc.getCodeBase + psym.cvdata.offset + psym.cvdata.debug_start); | |
298 } | |
299 else | |
300 DbgIO.println("0x%x:", dbg.current_address); | |
301 | |
302 DbgIO.print(" eip = 0x%x in %s (", | |
303 loc.address, loc.scope_sym is null?"??":loc.scope_sym.name_notype | |
304 ); | |
305 | |
306 if ( loc.codeblock !is null ) | |
307 DbgIO.print("%s:%d", loc.file, loc.line); | |
308 else if ( loc.mod !is null ) | |
309 DbgIO.write(loc.mod.name); | |
310 else | |
311 { | |
312 DLL dll = dbg.process.findDLL(loc.address); | |
313 if ( dll !is null ) | |
314 DbgIO.write(dll.image.name); | |
315 } | |
316 | |
317 DbgIO.println("); saved eip 0x%x", (cast(uint[])frame)[1]); | |
318 break; | |
319 default: | |
320 DbgIO.println("Warning: unknown argument %s", lastcmd[1]); | |
321 } | |
322 } | |
323 break; | |
324 // select frame | |
325 case "select-frame": | |
326 if ( lastcmd.length > 1 ) | |
327 current_frame_level = cast(uint)atoi(lastcmd[1]); | |
328 DbgIO.println("Current frame level is %d", current_frame_level); | |
329 break; | |
330 // add breakpoint | |
331 case "tbreak": | |
332 case "clear": | |
333 case "break": | |
334 int index; | |
335 if ( lastcmd.length < 2 ) { | |
336 DbgIO.println("invalid syntax - see help for details"); | |
337 break; | |
338 } | |
339 Location loc = new Location(lastcmd[1]); | |
340 loc.bind(dbg.images, dbg.source_search_paths); | |
341 if ( loc is null ) | |
342 break; | |
343 if ( lastcmd.length > 2 ) | |
344 index = cast(int)atoi(lastcmd[2]); | |
345 | |
346 if ( lastcmd[0] == "clear" ) | |
347 { | |
348 Breakpoint bp = dbg.getBreakpoint(loc, index); | |
349 dbg.removeBreakpoint(index); | |
350 } | |
351 else | |
352 { | |
353 Breakpoint bp; | |
354 if ( lastcmd[0] == "tbreak" ) | |
355 index = -1; | |
356 else if ( index <= 0 && dbg.breakpoints.length > 0 ) | |
357 index = dbg.breakpoints.keys.dup.sort[$-1]+1; | |
358 bp = dbg.setBreakpoint(loc, index, 0); | |
359 DbgIO.println("Breakpoint %d at 0x%08x", index, bp.address); | |
360 } | |
361 break; | |
362 // add source search path | |
363 case "directory": | |
364 if ( lastcmd.length > 1 ) | |
365 { | |
366 string sp = lastcmd[1].dup; | |
367 if ( find(sp, '/') >= 0 ) | |
368 sp = replace(sp, "/", "\\"); | |
369 if ( sp[$-1] != '\\' ) | |
370 sp ~= '\\'; | |
371 dbg.source_search_paths ~= sp; | |
372 } | |
373 else | |
374 DbgIO.println("usage: ssp <search_path>"); | |
375 break; | |
376 // quit | |
377 case "quit": | |
378 case "q": | |
379 dbg.abort = true; | |
380 quit = true; | |
381 return true; | |
382 // run/continue | |
383 case "cont": | |
384 case "run": | |
385 case "start": | |
386 if ( dbg.process_loaded ) { | |
387 dbg.single_step = false; | |
388 dbg.paused = false; | |
389 return true; | |
390 } | |
391 else { | |
392 dbg.start(command_line); | |
393 return true; | |
394 } | |
395 // single-step | |
396 case "nexti": | |
397 dbg.single_step = true; | |
398 dbg.activateSingleStep(true); | |
399 return true; | |
400 // step over | |
401 case "next": | |
402 if ( dbg.step(StepMode.e_over) ) | |
403 return true; | |
404 break; | |
405 // step into | |
406 case "step": | |
407 if ( dbg.step(StepMode.e_in) ) | |
408 return true; | |
409 break; | |
410 // step out | |
411 case "finish": | |
412 if ( dbg.step(StepMode.e_out) ) | |
413 return true; | |
414 break; | |
415 // unwind stack | |
416 case "bt": | |
417 unwindStack(); | |
418 break; | |
419 case "print": | |
420 case "output": | |
421 if ( dbg.process_loaded && lastcmd.length > 1 ) | |
422 { | |
423 string expr; | |
424 if ( lastcmd[1][0] == '/' ) | |
425 expr = lastcmd[2]; | |
426 else | |
427 expr = lastcmd[1]; | |
428 try DbgIO.println(symbolValueToString(dbg.handleData(dbg.evaluateExpression(expr), false))); | |
429 catch ( EvaluationException e ) { | |
430 DbgIO.writeln(e.toString); | |
431 } | |
432 } | |
433 break; | |
434 case "disassemble": | |
435 if ( !dbg.process_loaded ) | |
436 break; | |
437 | |
438 uint start_address = dbg.current_address; | |
439 if ( lastcmd.length > 1 ) | |
440 sscanf(toStringz(lastcmd[1]), "%x", &start_address); | |
441 else | |
442 { | |
443 Location loc = dbg.images.findLocation(dbg.current_address); | |
444 if ( loc.scope_sym !is null ) { | |
445 ProcedureSymbol psym = cast(ProcedureSymbol)loc.scope_sym; | |
446 start_address = loc.getCodeBase + psym.cvdata.offset; | |
447 DisAsm.disasm(dbg.process, start_address, start_address+psym.cvdata.proc_length, &printDisassembly); | |
448 break; | |
449 } | |
450 } | |
451 DisAsm.disasm(dbg.process, start_address, 0, &printDisassembly); | |
452 break; | |
453 case "x": | |
454 uint start_address; | |
455 if ( lastcmd.length > 2 ) | |
456 { | |
457 if ( lastcmd[1].length > 2 && lastcmd[1][0..2] == "0x" ) | |
458 lastcmd[1] = lastcmd[1][2..$]; | |
459 sscanf(toStringz(lastcmd[1]), "%x", &start_address); | |
460 string count_str = lastcmd[$-1][2..$-2]; | |
461 uint count = cast(uint)atoi(count_str); | |
462 | |
463 dumpMemory(start_address, count); | |
464 } | |
465 else | |
466 DbgIO.println("Warning: too few arguments for x"); | |
467 break; | |
468 case "whatis": | |
469 if ( dbg.process_loaded && lastcmd.length > 1 ) | |
470 { | |
471 SymbolData sd = dbg.evaluateExpression(lastcmd[1], current_frame_level); | |
472 string type = demangle("_D0"~sd.type); | |
473 try DbgIO.println("type = %s", type); | |
474 catch ( EvaluationException e ) { | |
475 DbgIO.writeln(e.toString); | |
476 } | |
477 } | |
478 break; | |
479 | |
480 | |
481 // list source search paths | |
482 case "lsp": | |
483 foreach ( s; dbg.source_search_paths ) | |
484 DbgIO.writeln(s); | |
485 break; | |
486 // list breakpoints | |
487 case "lbp": | |
488 if ( dbg.breakpoints.length <= 0 ) | |
489 DbgIO.println("no breakpoints set"); | |
490 foreach ( uint i, bp; dbg.breakpoints ) | |
491 DbgIO.println("%d %s", i, bp.toString); | |
492 break; | |
493 // list temporary breakpoints | |
494 case "ltbp": | |
495 if ( dbg.temp_breakpoints.empty ) | |
496 DbgIO.println("no temporary breakpoints set"); | |
497 foreach ( bp; dbg.temp_breakpoints ) | |
498 DbgIO.writeln(bp.value.toString); | |
499 break; | |
500 // list debug modules | |
501 case "lm": | |
502 string[] modules_noinfo; | |
503 foreach ( img; dbg.images.images ) | |
504 { | |
505 if ( img.codeView is null ) | |
506 continue; | |
507 foreach ( m; img.codeView.modulesByIndex ) | |
508 { | |
509 string name = m.name; | |
510 | |
511 if ( m.header.iLib > 0 ) | |
512 name ~= " from "~img.codeView.libraries[m.header.iLib]; | |
513 | |
514 if ( lastcmd.length > 1 && find(name, lastcmd[1]) < 0 ) | |
515 continue; | |
516 | |
517 bool has_info = false; | |
518 with ( m.symbols ) if ( proc_symbols.length+stack_symbols.length+data_symbols.length > 0 ) | |
519 { | |
520 DbgIO.println( | |
521 "%s\n\tSymbols: %d proc %d stack %d data", | |
522 name, proc_symbols.length, stack_symbols.length, data_symbols.length | |
523 ); | |
524 has_info = true; | |
525 } | |
526 if ( m.source_module !is null ) | |
527 { | |
528 DbgIO.println("\tSource files:"); | |
529 has_info = true; | |
530 foreach ( sf; m.source_module.files ) | |
531 DbgIO.println("\t\t%s", sf.name); | |
532 } | |
533 if ( !has_info ) | |
534 modules_noinfo ~= name; | |
535 } | |
536 } | |
537 if ( modules_noinfo.length > 0 ) | |
538 { | |
539 DbgIO.println("Modules without debug information:"); | |
540 foreach ( m; modules_noinfo ) | |
541 DbgIO.println("%s ", m); | |
542 } | |
543 break; | |
544 // list source modules | |
545 case "lsm": | |
546 foreach ( img; dbg.images.images ) | |
547 { | |
548 if ( img.codeView is null ) | |
549 continue; | |
550 foreach ( m; img.codeView.modulesByIndex ) | |
551 { | |
552 if ( m.source_module !is null ) | |
553 { | |
554 foreach ( sf; m.source_module.files ) | |
555 { | |
556 if ( lastcmd.length > 1 && find(sf.name, lastcmd[1]) < 0 ) | |
557 continue; | |
558 DbgIO.writeln(sf.name); | |
559 } | |
560 } | |
561 } | |
562 } | |
563 break; | |
564 // list all symbols | |
565 case "ls": | |
566 foreach ( img; dbg.images.images ) | |
567 { | |
568 if ( img.codeView is null ) | |
569 continue; | |
570 printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
571 printSymbols(img.codeView, img.codeView.global_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
572 printSymbols(img.codeView, img.codeView.static_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
573 foreach ( m; img.codeView.modulesByIndex ) | |
574 printSymbols(img.codeView, m.symbols.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
575 } | |
576 break; | |
577 // list function symbols | |
578 case "lf": | |
579 foreach ( img; dbg.images.images ) | |
580 { | |
581 if ( img.codeView is null ) | |
582 continue; | |
583 printSymbols(img.codeView, img.codeView.global_pub.proc_symbols, lastcmd.length>1?lastcmd[1]:null); | |
584 printSymbols(img.codeView, img.codeView.global_sym.proc_symbols, lastcmd.length>1?lastcmd[1]:null); | |
585 printSymbols(img.codeView, img.codeView.static_sym.proc_symbols, lastcmd.length>1?lastcmd[1]:null); | |
586 foreach ( m; img.codeView.modulesByIndex ) | |
587 printSymbols(img.codeView, m.symbols.proc_symbols, lastcmd.length>1?lastcmd[1]:null); | |
588 } | |
589 break; | |
590 // list data symbols | |
591 case "ld": | |
592 foreach ( img; dbg.images.images ) | |
593 { | |
594 if ( img.codeView is null ) | |
595 continue; | |
596 printSymbols(img.codeView, img.codeView.global_pub.data_symbols, lastcmd.length>1?lastcmd[1]:null); | |
597 printSymbols(img.codeView, img.codeView.global_sym.data_symbols, lastcmd.length>1?lastcmd[1]:null); | |
598 printSymbols(img.codeView, img.codeView.static_sym.data_symbols, lastcmd.length>1?lastcmd[1]:null); | |
599 foreach ( m; img.codeView.modulesByIndex ) | |
600 printSymbols(img.codeView, m.symbols.data_symbols, lastcmd.length>1?lastcmd[1]:null); | |
601 } | |
602 break; | |
603 // list global symbols | |
604 case "lg": | |
605 foreach ( img; dbg.images.images ) | |
606 { | |
607 if ( img.codeView is null ) | |
608 continue; | |
609 printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
610 printSymbols(img.codeView, img.codeView.global_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
611 } | |
612 break; | |
613 // list global publics | |
614 case "lp": | |
615 foreach ( img; dbg.images.images ) | |
616 { | |
617 if ( img.codeView is null ) | |
618 continue; | |
619 printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
620 } | |
621 break; | |
622 // delete breakpoint | |
623 case "dbp": | |
624 if ( lastcmd.length > 1 ) | |
625 { | |
626 if ( lastcmd[1] == "*" ) | |
627 { | |
628 foreach ( uint i, bp; dbg.breakpoints ) | |
629 { | |
630 bp.deactivate(dbg.process); | |
631 dbg.breakpoints.remove(i); | |
632 } | |
633 } | |
634 else if ( isNumeric(lastcmd[1]) ) | |
635 { | |
636 if ( !dbg.removeBreakpoint(cast(uint)atoi(lastcmd[1])) ) | |
637 DbgIO.println("invalid breakpoint index: %s",lastcmd[1]); | |
638 } | |
639 else | |
640 { | |
641 Location loc = new Location(lastcmd[1]); | |
642 loc.bind(dbg.images, dbg.source_search_paths); | |
643 if ( loc !is null ) | |
644 { | |
645 int bp_index; | |
646 dbg.getBreakpoint(loc, bp_index); | |
647 if ( bp_index >= 0 && !dbg.removeBreakpoint(bp_index) ) | |
648 DbgIO.println("No breakpoint set at "~lastcmd[1]); | |
649 } | |
650 else | |
651 DbgIO.println("Usage: dbp [<bp index>|<file:line>]"); | |
652 } | |
653 } | |
654 else | |
655 DbgIO.println("Usage: bp <sourc file>:<line>"); | |
656 break; | |
657 // dump stack | |
658 case "ds": | |
659 int dump_length; | |
660 if ( lastcmd.length > 1 ) | |
661 dump_length = cast(int)atoi(lastcmd[1])*4; | |
662 else | |
663 { | |
664 CONTEXT ctx; | |
665 if ( dbg.process.threads[dbg.thread_id].getContext(ctx, CONTEXT_CONTROL) ) | |
666 dump_length = ctx.Ebp-ctx.Esp+8; | |
667 if ( dump_length <= 0 ) | |
668 dump_length = 16*4; | |
669 } | |
670 int top = dbg.stack.data.length>dump_length?dump_length:dbg.stack.data.length; | |
671 dumpMemory(dbg.stack.top_ptr, top, dbg.stack.data); | |
672 break; | |
673 case "dm": | |
674 if ( lastcmd.length < 3 ) { | |
675 DbgIO.println("usage: dm <start> <length>"); | |
676 break; | |
677 } | |
678 uint start; | |
679 sscanf(toStringz(lastcmd[1]), "%x", &start); | |
680 dumpMemory(start, cast(uint)atoi(lastcmd[2])); | |
681 break; | |
682 | |
683 // unknown command | |
684 default: | |
685 DbgIO.println("Warning: Unknown command '%s' ignored!", lastcmd[0]); | |
686 break; | |
687 } | |
688 | |
689 return false; | |
690 } | |
691 | |
692 /********************************************************************************************** | |
693 | |
694 **********************************************************************************************/ | |
695 void dumpMemory(uint start, uint length, ubyte[] _data=null) | |
696 { | |
697 ubyte[] data; | |
698 if ( _data is null ) | |
699 { | |
700 data.length = length; | |
701 if ( !dbg.process.readProcessMemory(start, data.ptr, data.length) ) | |
702 return; | |
703 } | |
704 else | |
705 data = _data; | |
706 for ( uint i = 0; i < length; ++i ) | |
707 { | |
708 if ( i % (8*4) == 0 ) | |
709 { | |
710 if ( i > 0 ) | |
711 DbgIO.println(""); | |
712 DbgIO.print("0x%08x:", start+i); | |
713 } | |
714 DbgIO.print(" 0x%02x", data[i]); | |
715 } | |
716 DbgIO.println(""); | |
717 } | |
718 | |
719 /********************************************************************************************** | |
720 | |
721 **********************************************************************************************/ | |
722 void evalStackSymbols(StackSymbol[] symbols) | |
723 { | |
724 foreach ( sym; symbols ) | |
725 { | |
726 string name = sym.mangled_name; | |
727 DbgIO.print("%s = ", name); | |
728 try DbgIO.writeln(symbolValueToString(dbg.handleData(dbg.evaluateExpression(name, current_frame_level, sym), true))); | |
729 catch ( EvaluationException e ) { | |
730 DbgIO.println(e.msg); | |
731 } | |
732 } | |
733 } | |
734 | |
735 /********************************************************************************************** | |
736 | |
737 **********************************************************************************************/ | |
738 void printAsmLine(uint address, string bytes, string asmsource, string symbol, string location, string source) | |
739 { | |
740 bool nl = false; | |
741 if ( location !is null ) { | |
742 DbgIO.print("0x%08x <??>: // ", address); | |
743 DbgIO.write(location); | |
744 nl = true; | |
745 } | |
746 if ( source !is null ) | |
747 { | |
748 if ( !nl ) | |
749 DbgIO.print("0x%08x <??>: // ", address); | |
750 DbgIO.write(source); | |
751 nl = true; | |
752 } | |
753 if ( nl ) | |
754 DbgIO.println; | |
755 | |
756 assert(asmsource !is null); | |
757 DbgIO.print("0x%08x <??>: ", address, asmsource); | |
758 | |
759 if ( symbol !is null ) | |
760 DbgIO.write(symbol); | |
761 DbgIO.println; | |
762 } | |
763 | |
764 /********************************************************************************************** | |
765 Prints the register contents of the given thread's context. | |
766 **********************************************************************************************/ | |
767 void printRegisterDump(DbgThread thread) | |
768 { | |
769 CONTEXT ctx; | |
770 if ( thread.getContext(ctx) ) | |
771 { | |
772 DbgIO.println("eax\t0x%x -\nebx\t0x%x -\necx\t0x%x -\nedx\t0x%x -", ctx.Eax, ctx.Ebx, ctx.Ecx, ctx.Edx); | |
773 DbgIO.println("cs\t0x%x -\nds\t0x%x -\nes\t0x%x -\nfs\t0x%x -", ctx.SegCs, ctx.SegDs, ctx.SegEs, ctx.SegFs); | |
774 DbgIO.println("gs\t0x%x -\nss\t0x%x -\nedi\t0x%x -\nesi\t0x%x -", ctx.SegGs, ctx.SegSs, ctx.Edi, ctx.Esi); | |
775 DbgIO.println("ebp\t0x%x -\nesp\t0x%x -\neip\t0x%x -\neflags\t0x%x -", ctx.Ebp, ctx.Esp, ctx.Eip, ctx.EFlags); | |
776 } | |
777 else | |
778 DbgIO.println("Warning: Couldn't get main thread's context"); | |
779 } | |
780 | |
781 /********************************************************************************************** | |
782 | |
783 **********************************************************************************************/ | |
784 string symbolValueToString(SymbolValue val) | |
785 { | |
786 string str; | |
787 if ( val.name !is null ) | |
788 str = val.name~" = "; | |
789 if ( val.value !is null ) | |
790 str ~= val.value; | |
791 else | |
792 { | |
793 if ( val.children.length > 0 ) | |
794 { | |
795 str ~= "{"; | |
796 bool first = true; | |
797 foreach ( c; val.children ) | |
798 { | |
799 if ( first ) | |
800 first = false; | |
801 else | |
802 str ~= ","; | |
803 str ~= symbolValueToString(c); | |
804 } | |
805 str ~= "}"; | |
806 } | |
807 else | |
808 str ~= "{}"; | |
809 } | |
810 return str; | |
811 } | |
812 | |
813 /********************************************************************************************** | |
814 Read command and call CLI supplied parser function. | |
815 Gets called when debuggee is suspended. | |
816 **********************************************************************************************/ | |
817 bool readCommand() | |
818 { | |
819 if ( cmdQueue.length > 0 ) | |
820 { | |
821 string cmd = strip(cmdQueue[0]); | |
822 cmdQueue = cmdQueue[1..$]; | |
823 DbgIO.writeln(prompt~cmd); | |
824 return parseCommand(cmd); | |
825 } | |
826 else { | |
827 DbgIO.write(prompt); | |
828 string input = DbgIO.readln(); | |
829 return parseCommand(input); | |
830 } | |
831 } | |
832 } |