Mercurial > projects > ddbg_continued
comparison src/cli/ddbgcli.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 | a5fb1bc967e6 |
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.ddbgcli; | |
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 minidump; | |
14 import container; | |
15 import util; | |
16 import codeview.codeview; | |
17 import breakpoint; | |
18 import debugger; | |
19 import disasm; | |
20 import callstack; | |
21 import dbgprocess; | |
22 import dbgthread; | |
23 import expression.expression_apd; | |
24 import expression.datahandler : SymbolValue, DataHandler; | |
25 import expression.evaluationcontext; | |
26 import cli.userinterface; | |
27 | |
28 import win32.winbase; | |
29 import win32.winuser; | |
30 import win32.winnt; | |
31 import win32.dbghelp; | |
32 | |
33 /************************************************************************************************** | |
34 | |
35 **************************************************************************************************/ | |
36 class DdbgCLI : UserInterfaceBase | |
37 { | |
38 const int PRINT_SOURCE_LINES = 3; | |
39 | |
40 string[] lastcmd, | |
41 onexCommands, | |
42 ontermCommands; | |
43 string debuggee, | |
44 command_line; | |
45 | |
46 uint current_frame_level; | |
47 | |
48 bool quit; | |
49 | |
50 const ubyte CPU_REGISTERS = 1, | |
51 FPU_REGISTERS = 2, | |
52 MMX_REGISTERS = 4, | |
53 SSE_REGISTERS = 8; | |
54 ubyte dump_registers = CPU_REGISTERS; | |
55 | |
56 uint lastEvaluationDepth = 1; | |
57 | |
58 bool auto_find_scope_frame, /// find frame of last active scope if current frame has no source/symbols | |
59 jump_to_last_known_location_on_exception = true; | |
60 | |
61 /********************************************************************************************** | |
62 | |
63 **********************************************************************************************/ | |
64 void init(string[] args) | |
65 { | |
66 DbgIO.println(WELCOME_STRING); | |
67 if ( args.length < 2 ) | |
68 throw new DebuggerException("Usage: ddbg [-cli=<mode>] [-cmd=<commands>] <exe file> [arguments]"); | |
69 | |
70 debuggee = args[1]; | |
71 foreach ( inout arg; args ) | |
72 { | |
73 if ( find(arg, ' ') >= 0 ) | |
74 arg = "\""~arg~"\""; | |
75 } | |
76 command_line = join(args[1..$], " "); | |
77 | |
78 dbg = new Debugger(debuggee, this); | |
79 } | |
80 | |
81 int start() | |
82 { | |
83 while ( !quit ) | |
84 { | |
85 debug | |
86 readCommand(); | |
87 else | |
88 { | |
89 try readCommand(); | |
90 catch ( Exception e ) | |
91 DbgIO.println(e.msg); | |
92 } | |
93 } | |
94 return 0; | |
95 } | |
96 | |
97 /********************************************************************************************** | |
98 | |
99 **********************************************************************************************/ | |
100 void singleStep() | |
101 { | |
102 DbgIO.println(describeLocation(dbg.current_address)); | |
103 } | |
104 | |
105 /********************************************************************************************** | |
106 | |
107 **********************************************************************************************/ | |
108 void exitProcess() | |
109 { | |
110 DbgIO.println("Process terminated"); | |
111 cmdQueue ~= ontermCommands; | |
112 } | |
113 | |
114 /********************************************************************************************** | |
115 | |
116 **********************************************************************************************/ | |
117 void loadedDLL(DLL dll) | |
118 { | |
119 if( dll !is null && dll.image.name.length ) { | |
120 DbgIO.write(dll.image.name); | |
121 DbgIO.println(" loaded at 0x%08x", dll.base); | |
122 } | |
123 else | |
124 DbgIO.writeln("unknown DLL loaded"); | |
125 } | |
126 | |
127 /********************************************************************************************** | |
128 | |
129 **********************************************************************************************/ | |
130 void win32exception(uint threadId, EXCEPTION_RECORD* exrec) | |
131 { | |
132 DbgIO.println( | |
133 "Unhandled Exception: %s(0x%x) at %s thread(%d)", | |
134 getExceptionName(exrec.ExceptionCode), exrec.ExceptionCode, describeLocation(dbg.current_address), threadId | |
135 ); | |
136 } | |
137 | |
138 /********************************************************************************************** | |
139 | |
140 **********************************************************************************************/ | |
141 void exception(uint threadId, string class_name, string msg, size_t obj_ptr) | |
142 { | |
143 if ( jump_to_last_known_location_on_exception ) | |
144 { | |
145 uint index; | |
146 current_frame_level = 0; | |
147 Location loc = dbg.images.findLocation(dbg.current_address); | |
148 | |
149 if ( loc.codeblock is null ) | |
150 { | |
151 dbg.stack.firstFrame(index); | |
152 ubyte[] frame = dbg.stack.prevFrame(index, index); | |
153 while ( loc.codeblock is null && frame !is null ) | |
154 { | |
155 uint ret_adr = (cast(uint[])frame)[1]; | |
156 loc = dbg.images.findLocation(ret_adr); | |
157 frame = dbg.stack.prevFrame(index, index); | |
158 ++current_frame_level; | |
159 } | |
160 } | |
161 } | |
162 | |
163 DbgIO.println("Unhandled D Exception (%s", class_name); | |
164 DbgIO.write(msg.length>0?" \""~msg~"\"":""); | |
165 DbgIO.println(") at %s thread(%d)", describeLocation(dbg.current_address), threadId); | |
166 cmdQueue ~= onexCommands; | |
167 } | |
168 | |
169 /********************************************************************************************** | |
170 | |
171 **********************************************************************************************/ | |
172 void userInterrupt() | |
173 { | |
174 DbgIO.println("User interrupt at %s", describeLocation(dbg.current_address)); | |
175 } | |
176 | |
177 /********************************************************************************************** | |
178 | |
179 **********************************************************************************************/ | |
180 bool breakpoint(int index, Breakpoint bp, DbgThread thread) | |
181 { | |
182 if ( bp.hardware ) | |
183 { | |
184 DbgIO.println("Hardware breakpoint for 0x%x hit at %s thread(%d)", | |
185 bp.address, describeLocation(dbg.current_address), thread.id | |
186 ); | |
187 } | |
188 else if ( bp.file is null || bp.line == 0 ) | |
189 DbgIO.println("Unknown breakpoint hit at %s thread(%d)", describeLocation(bp.address), thread.id); | |
190 else | |
191 { | |
192 string[] source = dbg.getSourceFile(bp.file); | |
193 string source_line; | |
194 if ( source !is null && bp.line <= source.length ) | |
195 source_line = source[bp.line-1]; | |
196 | |
197 if ( !bp.temporary ) | |
198 DbgIO.print("Breakpoint %d hit at ", index); | |
199 DbgIO.println("%s:%d 0x%x thread(%d)", bp.file, bp.line, bp.address, thread.id); | |
200 if ( source_line.length > 0 ) | |
201 DbgIO.writeln(source_line); | |
202 } | |
203 return true; | |
204 } | |
205 | |
206 /********************************************************************************************** | |
207 | |
208 **********************************************************************************************/ | |
209 void debugString(string str) | |
210 { | |
211 printf("OUTPUT DEBUG STRING:\n%s\n", toStringz(str)); | |
212 } | |
213 | |
214 /********************************************************************************************** | |
215 Command line parser. Gets called when debuggee is suspended. | |
216 **********************************************************************************************/ | |
217 bool parseCommand(string input) | |
218 { | |
219 if ( strip(input).length > 0 ) | |
220 { | |
221 auto r = std.regexp.RegExp("(([^\" \\t]+)|(\"[^\"]+\"))+"); | |
222 lastcmd.length = 0; | |
223 foreach ( m; r.search(input) ) | |
224 lastcmd ~= r.match(0); | |
225 } | |
226 if ( lastcmd.length <= 0 ) | |
227 return false; | |
228 | |
229 switch ( lastcmd[0] ) | |
230 { | |
231 case "help": | |
232 case "h": | |
233 case "?": | |
234 DbgIO.write(import("ddbg_help.txt")); | |
235 break; | |
236 case "=": | |
237 if ( !dbg.process_loaded && dbg.miniDump is null ) | |
238 break; | |
239 if ( lastcmd.length > 1 ) | |
240 { | |
241 try DbgIO.writeln(symbolValueToString(dbg.handleData(dbg.evaluateExpression(lastcmd[1], current_frame_level), false))); | |
242 catch ( EvaluationException e ) { | |
243 DbgIO.writeln(e.toString); | |
244 } | |
245 } | |
246 break; | |
247 case "arg": | |
248 if ( dbg.process_loaded ) | |
249 DbgIO.println("Warning: process already started"); | |
250 command_line = debuggee~" "~join(lastcmd[1..$], " "); | |
251 break; | |
252 // add breakpoint | |
253 case "bp": | |
254 int index; | |
255 if ( lastcmd.length < 2 ) { | |
256 DbgIO.println("invalid syntax - see help for details"); | |
257 break; | |
258 } | |
259 | |
260 int pos = find(lastcmd[1], '#'); | |
261 uint threadId; | |
262 if ( pos > 0 ) | |
263 { | |
264 threadId = cast(uint)atoi(lastcmd[1][pos+1..$]); | |
265 lastcmd[1] = lastcmd[1][0..pos]; | |
266 } | |
267 Location loc = new Location(lastcmd[1]); | |
268 loc.bind(dbg.images, dbg.source_search_paths); | |
269 if ( lastcmd.length > 2 ) | |
270 index = cast(int)atoi(lastcmd[2]); | |
271 | |
272 Breakpoint bp; | |
273 if ( index <= 0 && dbg.breakpoints.length > 0 ) | |
274 index = dbg.breakpoints.keys.dup.sort[$-1]+1; | |
275 bp = dbg.setBreakpoint(loc, index, threadId); | |
276 DbgIO.println("Breakpoint set: %s", bp.toString); | |
277 break; | |
278 // delete breakpoint | |
279 case "dbp": | |
280 if ( lastcmd.length > 1 ) | |
281 { | |
282 if ( lastcmd[1] == "*" ) | |
283 { | |
284 foreach ( uint i; dbg.breakpoints.keys ) | |
285 dbg.removeBreakpoint(i); | |
286 } | |
287 else if ( isNumeric(lastcmd[1]) ) | |
288 { | |
289 if ( !dbg.removeBreakpoint(cast(uint)atoi(lastcmd[1])) ) | |
290 DbgIO.println("invalid breakpoint index: %s",lastcmd[1]); | |
291 } | |
292 else | |
293 { | |
294 Location loc = new Location(lastcmd[1]); | |
295 loc.bind(dbg.images, dbg.source_search_paths); | |
296 if ( loc !is null ) | |
297 { | |
298 int bp_index; | |
299 dbg.getBreakpoint(loc, bp_index); | |
300 if ( bp_index >= 0 && !dbg.removeBreakpoint(bp_index) ) | |
301 DbgIO.println("No breakpoint set at "~lastcmd[1]); | |
302 } | |
303 else | |
304 DbgIO.println("dbp [<source file>:<line>|#index|*]"); | |
305 } | |
306 } | |
307 else | |
308 DbgIO.println("dbp [<source file>:<line>|#index|*]"); | |
309 break; | |
310 // set evaluation depth | |
311 case "er": | |
312 lastcmd.length = 1; | |
313 if ( dbg.evaluationDepth > 1 ) { | |
314 lastEvaluationDepth = dbg.evaluationDepth; | |
315 lastcmd ~= "1"; | |
316 } | |
317 else | |
318 lastcmd ~= .toString(lastEvaluationDepth); | |
319 case "ed": | |
320 if ( lastcmd.length < 2 || !isNumeric(lastcmd[1]) ) | |
321 DbgIO.println("Usage: ed <depth>"); | |
322 else { | |
323 dbg.evaluationDepth = cast(int)atoi(lastcmd[1]); | |
324 DbgIO.println("Expression evaluation depth is %d", dbg.evaluationDepth); | |
325 } | |
326 break; | |
327 case "el": | |
328 if ( lastcmd.length < 2 || !isNumeric(lastcmd[1]) ) | |
329 DbgIO.println("Usage: el <length>"); | |
330 else { | |
331 DataHandler.max_elem_count = cast(int)atoi(lastcmd[1]); | |
332 DbgIO.println("Array evaluation length is %d", DataHandler.max_elem_count); | |
333 } | |
334 break; | |
335 // select frame | |
336 case "f": | |
337 if ( lastcmd.length > 1 ) | |
338 current_frame_level = cast(uint)atoi(lastcmd[1]); | |
339 DbgIO.println("Current frame level is %d", current_frame_level); | |
340 break; | |
341 // image base address | |
342 case "ii": | |
343 foreach ( img; dbg.images.images ) | |
344 { | |
345 uint ibase = img.imageBase; | |
346 DbgIO.println("ImageBase\t0x%x", ibase); | |
347 DbgIO.println("CodeBase\t0x%x", img.getCodeBase); | |
348 DbgIO.println("Sections:\nname\t\taddress\t\tsize\t\tcharacteristics"); | |
349 foreach ( s; img.sections ) | |
350 with ( *s.header ) DbgIO.println("%s\t0x%08x\t0x%08x\t0x%08x", cast(char[8])Name, ibase+VirtualAddress, Misc.VirtualSize, Characteristics); | |
351 } | |
352 break; | |
353 // jump to last known source frame | |
354 case "jkf": | |
355 jump_to_last_known_location_on_exception = !jump_to_last_known_location_on_exception; | |
356 DbgIO.println("%s to from of last known source location on exception", | |
357 jump_to_last_known_location_on_exception?"Jumping":"Not jumping" | |
358 ); | |
359 break; | |
360 // walk memory | |
361 case "mi": | |
362 if ( !dbg.process_loaded ) | |
363 break; | |
364 uint filteredStates = MEM_COMMIT; | |
365 foreach ( lc; lastcmd[1..$] ) | |
366 { | |
367 switch ( lc ) | |
368 { | |
369 case "free": filteredStates |= MEM_FREE; break; | |
370 case "rsrv": filteredStates |= MEM_RESERVE; break; | |
371 default: | |
372 } | |
373 } | |
374 | |
375 MEMORY_BASIC_INFORMATION[] mbis = dbg.process.walkMemory; | |
376 | |
377 DbgIO.println("Base AlcBase AlcProt RgnSize Stat Protect Type"); | |
378 foreach ( mbi; mbis ) | |
379 { | |
380 if ( (mbi.State & filteredStates) == 0 ) | |
381 continue; | |
382 | |
383 string state; | |
384 switch ( mbi.State ) | |
385 { | |
386 case MEM_COMMIT: state = "comt"; break; | |
387 case MEM_FREE: state = "free"; break; | |
388 case MEM_RESERVE: state = "rsrv"; break; | |
389 default: state = "unkn"; break; | |
390 } | |
391 | |
392 string type; | |
393 switch ( mbi.Type ) | |
394 { | |
395 case MEM_IMAGE: type = "imag"; break; | |
396 case MEM_MAPPED: type = "mapd"; break; | |
397 case MEM_PRIVATE: type = "priv"; break; | |
398 default: type = "unkn"; break; | |
399 } | |
400 | |
401 string protectName(uint prot) | |
402 { | |
403 string protStr; | |
404 switch ( prot & 0xff ) | |
405 { | |
406 case 0: protStr = "?"; break; | |
407 case PAGE_EXECUTE: protStr = "x"; break; | |
408 case PAGE_EXECUTE_READ: protStr = "xr"; break; | |
409 case PAGE_EXECUTE_READWRITE: protStr = "xrw"; break; | |
410 case PAGE_EXECUTE_WRITECOPY: protStr = "xwc"; break; | |
411 case PAGE_NOACCESS: protStr = "na"; break; | |
412 case PAGE_READONLY: protStr = "ro"; break; | |
413 case PAGE_READWRITE: protStr = "rw"; break; | |
414 case PAGE_WRITECOPY: protStr = "wc"; break; | |
415 default: protStr = format("%02x", prot & 0xff); break; | |
416 } | |
417 protStr ~= " "; | |
418 if ( prot & PAGE_GUARD ) | |
419 protStr ~= "g"; | |
420 if ( prot & PAGE_NOCACHE ) | |
421 protStr ~= "nc"; | |
422 return protStr; | |
423 } | |
424 | |
425 DbgIO.println("%08x %08x %- 7s %08x %s %- 7s %s", | |
426 cast(size_t)mbi.BaseAddress, cast(size_t)mbi.AllocationBase, protectName(mbi.AllocationProtect), | |
427 mbi.RegionSize, state, protectName(mbi.Protect), type | |
428 ); | |
429 } | |
430 break; | |
431 // list breakpoints | |
432 case "lbp": | |
433 if ( dbg.breakpoints.length <= 0 ) | |
434 DbgIO.println("no breakpoints set"); | |
435 foreach ( uint i, bp; dbg.breakpoints ) | |
436 DbgIO.println("%d %s", i, bp.toString); | |
437 break; | |
438 // ldll | |
439 case "ldll": | |
440 if ( !dbg.process_loaded ) | |
441 break; | |
442 DbgIO.println("Base Name"); | |
443 foreach ( dll; dbg.process.loaded_dlls ) | |
444 DbgIO.println("%08x %s", dll.base, dll.image.name); | |
445 break; | |
446 // list temporary breakpoints | |
447 case "ltbp": | |
448 if ( dbg.temp_breakpoints.empty ) | |
449 DbgIO.println("no temporary breakpoints set"); | |
450 foreach ( bp; dbg.temp_breakpoints ) | |
451 DbgIO.writeln(bp.value.toString); | |
452 break; | |
453 // list debug modules | |
454 case "lm": | |
455 Module[] modules_noinfo; | |
456 foreach ( img; dbg.images.images ) | |
457 { | |
458 foreach ( m; img.codeView.modulesByIndex ) | |
459 { | |
460 string name = m.name; | |
461 | |
462 if ( m.header.iLib > 0 ) | |
463 name ~= " from "~img.codeView.libraries[m.header.iLib]; | |
464 | |
465 if ( lastcmd.length > 1 && find(name, lastcmd[1]) < 0 ) | |
466 continue; | |
467 | |
468 bool has_info = false; | |
469 with ( m.symbols ) | |
470 { | |
471 if ( proc_symbols.length+stack_symbols.length+data_symbols.length > 0 ) | |
472 { | |
473 DbgIO.println( | |
474 "%s\n\tSymbols: %d proc %d stack %d data", | |
475 name, proc_symbols.length, stack_symbols.length, data_symbols.length | |
476 ); | |
477 has_info = true; | |
478 } | |
479 } | |
480 if ( m.source_module !is null ) | |
481 { | |
482 DbgIO.println("\tSource files:"); | |
483 has_info = true; | |
484 foreach ( sf; m.source_module.files ) | |
485 DbgIO.println("\t\t%s", sf.name); | |
486 } | |
487 if ( !has_info ) | |
488 modules_noinfo ~= m; | |
489 } | |
490 } | |
491 if ( modules_noinfo.length > 0 ) | |
492 { | |
493 DbgIO.println("Modules without debug information:"); | |
494 foreach ( img; dbg.images.images ) | |
495 { | |
496 foreach ( m; modules_noinfo ) | |
497 { | |
498 string name = m.name; | |
499 | |
500 if ( m.header.iLib > 0 ) | |
501 name ~= " from "~img.codeView.libraries[m.header.iLib]; | |
502 | |
503 DbgIO.println("%s #segs=%d", name, m.seginfos.length); | |
504 if ( m.source_module !is null ) | |
505 { | |
506 DbgIO.println("\tSource files:"); | |
507 foreach ( sf; m.source_module.files ) | |
508 DbgIO.println("\t\t%s", sf.name); | |
509 } | |
510 } | |
511 } | |
512 } | |
513 break; | |
514 // list source modules | |
515 case "lsm": | |
516 uint[string] line_counters; | |
517 uint[string] seg_counters; | |
518 foreach ( img; dbg.images.images ) | |
519 { | |
520 if ( img.codeView is null ) | |
521 continue; | |
522 foreach ( m; img.codeView.modulesByIndex ) | |
523 { | |
524 if ( m.source_module is null ) | |
525 continue; | |
526 foreach ( sf; m.source_module.files ) | |
527 { | |
528 if ( lastcmd.length > 1 && find(sf.name, lastcmd[1]) < 0 ) | |
529 continue; | |
530 uint lines = sf.lines.length; | |
531 if ( (sf.name in line_counters) is null ) { | |
532 seg_counters[sf.name] = sf.segments.length; | |
533 line_counters[sf.name] = lines; | |
534 } | |
535 else { | |
536 seg_counters[sf.name] += sf.segments.length; | |
537 line_counters[sf.name] += lines; | |
538 } | |
539 } | |
540 } | |
541 } | |
542 string[] lc_keys = line_counters.keys.dup; | |
543 lc_keys.sort; | |
544 foreach ( key; lc_keys ) | |
545 DbgIO.println("%s\t\tsegs=%d lines=%d", key, seg_counters[key], line_counters[key]); | |
546 break; | |
547 // list source lines per module | |
548 case "lsl": | |
549 foreach ( img; dbg.images.images ) | |
550 { | |
551 if ( img.codeView is null ) | |
552 continue; | |
553 foreach ( m; img.codeView.modulesByIndex ) | |
554 { | |
555 if ( m.source_module is null ) | |
556 continue; | |
557 DbgIO.println("module %s", m.name); | |
558 foreach ( sf; m.source_module.files ) | |
559 { | |
560 DbgIO.println("file %s", sf.name); | |
561 if ( lastcmd.length > 1 && find(sf.name, lastcmd[1]) < 0 ) | |
562 continue; | |
563 foreach ( l; sf.lines.reverse ) | |
564 { | |
565 DbgIO.println("line %d", l); | |
566 } | |
567 } | |
568 } | |
569 } | |
570 break; | |
571 // list all symbols | |
572 case "ls": | |
573 /* | |
574 void dumpSymbolAVL(AVLNode!(NamedSymbol) node, uint indent=0) | |
575 { | |
576 string indentstr = new char[indent*2]; | |
577 indentstr[0..indent*2] = ' '; | |
578 DbgIO.println("%s%s", indentstr, node.value.name_notype); | |
579 if ( node.left !is null ) | |
580 dumpSymbolAVL(node.left, indent+1); | |
581 if ( node.right !is null ) | |
582 dumpSymbolAVL(node.right, indent+1); | |
583 } | |
584 DbgIO.println("AVL dump:"); | |
585 dumpSymbolAVL(dbg.image.codeView.globalNamedSymbols.root); | |
586 */ | |
587 foreach ( img; dbg.images.images ) | |
588 { | |
589 if ( img.codeView is null ) | |
590 continue; | |
591 printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
592 printSymbols(img.codeView, img.codeView.global_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
593 printSymbols(img.codeView, img.codeView.static_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
594 foreach ( m; img.codeView.modulesByIndex ) | |
595 printSymbols(img.codeView, m.symbols.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
596 } | |
597 break; | |
598 // list source search paths | |
599 case "lsp": | |
600 foreach ( s; dbg.source_search_paths ) | |
601 DbgIO.writeln(s); | |
602 break; | |
603 // list function symbols | |
604 case "lf": | |
605 foreach ( img; dbg.images.images ) | |
606 { | |
607 if ( img.codeView is null ) | |
608 continue; | |
609 printSymbols(img.codeView, img.codeView.global_pub.proc_symbols, lastcmd.length>1?lastcmd[1]:null); | |
610 printSymbols(img.codeView, img.codeView.global_sym.proc_symbols, lastcmd.length>1?lastcmd[1]:null); | |
611 printSymbols(img.codeView, img.codeView.static_sym.proc_symbols, lastcmd.length>1?lastcmd[1]:null); | |
612 foreach ( m; img.codeView.modulesByIndex ) | |
613 printSymbols(img.codeView, m.symbols.proc_symbols, lastcmd.length>1?lastcmd[1]:null); | |
614 } | |
615 break; | |
616 // list data symbols | |
617 case "ld": | |
618 foreach ( img; dbg.images.images ) | |
619 { | |
620 if ( img.codeView is null ) | |
621 continue; | |
622 printSymbols(img.codeView, img.codeView.global_pub.data_symbols, lastcmd.length>1?lastcmd[1]:null); | |
623 printSymbols(img.codeView, img.codeView.global_sym.data_symbols, lastcmd.length>1?lastcmd[1]:null); | |
624 printSymbols(img.codeView, img.codeView.static_sym.data_symbols, lastcmd.length>1?lastcmd[1]:null); | |
625 foreach ( m; img.codeView.modulesByIndex ) | |
626 printSymbols(img.codeView, m.symbols.data_symbols, lastcmd.length>1?lastcmd[1]:null); | |
627 } | |
628 break; | |
629 // list global symbols | |
630 case "lg": | |
631 foreach ( img; dbg.images.images ) | |
632 { | |
633 if ( img.codeView is null ) | |
634 continue; | |
635 printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
636 printSymbols(img.codeView, img.codeView.global_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
637 } | |
638 break; | |
639 // list global publics | |
640 case "lp": | |
641 foreach ( img; dbg.images.images ) | |
642 { | |
643 if ( img.codeView is null ) | |
644 continue; | |
645 printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null); | |
646 } | |
647 break; | |
648 // list scope variables | |
649 case "lsv": | |
650 if ( dbg.process_loaded || dbg.miniDump !is null ) | |
651 evalScopeSymbols(); | |
652 break; | |
653 // list threads | |
654 case "lt": | |
655 if ( dbg.miniDump !is null ) | |
656 { | |
657 DbgIO.println(" id pri sus location"); | |
658 MINIDUMP_THREAD[] threads = dbg.miniDump.threads; | |
659 foreach ( thread; threads ) | |
660 { | |
661 CONTEXT* ctx; | |
662 ctx = cast(CONTEXT*)dbg.miniDump.rvaToVa(thread.ThreadContext.Rva); | |
663 Location loc = dbg.images.findLocation(ctx.Eip); | |
664 | |
665 DbgIO.println("%s%s%- 6d %- 3d %- 2d %s", | |
666 thread.ThreadId==dbg.thread_id?">":" ", thread.ThreadId==dbg.miniDump.threadInfo.mainThreadId?"*":" ", | |
667 thread.ThreadId, thread.Priority, thread.SuspendCount, describeLocation(loc) | |
668 ); | |
669 } | |
670 } | |
671 else | |
672 { | |
673 DbgIO.println(" id pri sus creation exit kernel user location"); | |
674 foreach ( t; dbg.process.threads.values ) | |
675 { | |
676 // id name location pri pri-boost start-info times | |
677 ulong creation, | |
678 exit, | |
679 kernel, | |
680 user; | |
681 | |
682 t.times(creation, exit, kernel, user); | |
683 | |
684 CONTEXT ctx; | |
685 t.getContext(ctx); | |
686 Location loc = dbg.images.findLocation(ctx.Eip); | |
687 | |
688 DbgIO.println("%s%s%- 6d %- 3d%s %- 2d %s %s %s %s %s", | |
689 t.id==dbg.thread_id?">":" ", t.id==dbg.process.mainThreadId?"*":" ", t.id, | |
690 t.priority, t.priorityBoost?"b":" ", t.suspendCount, | |
691 formatTicks(creation), formatTicks(exit), formatTicks(kernel), formatTicks(user), | |
692 describeLocation(loc) | |
693 ); | |
694 } | |
695 } | |
696 break; | |
697 // no console | |
698 case "nc": | |
699 dbg.create_new_console = !dbg.create_new_console; | |
700 DbgIO.println("Starting debuggee in %s console", dbg.create_new_console?"new":"this"); | |
701 break; | |
702 // on exception | |
703 case "onex": | |
704 if ( lastcmd.length < 2 ) | |
705 { | |
706 foreach ( cmd; onexCommands ) | |
707 DbgIO.writeln(cmd[0..$-1]); | |
708 } | |
709 else | |
710 { | |
711 onexCommands = null; | |
712 string cmdList; | |
713 foreach ( cmd; lastcmd[1..$] ) | |
714 { | |
715 if ( cmd[0] == '"' && cmd[$-1] == '"' ) | |
716 cmdList ~= " "~cmd[1..$-1]; | |
717 else | |
718 cmdList ~= " "~cmd; | |
719 } | |
720 foreach ( cmd; split(cmdList, ";") ) | |
721 onexCommands ~= strip(cmd)~";"; | |
722 } | |
723 break; | |
724 // on termination | |
725 case "onterm": | |
726 if ( lastcmd.length < 2 ) | |
727 { | |
728 foreach ( cmd; ontermCommands ) | |
729 DbgIO.writeln(cmd[0..$-1]); | |
730 } | |
731 else | |
732 { | |
733 ontermCommands = null; | |
734 string cmdList; | |
735 foreach ( cmd; lastcmd[1..$] ) | |
736 { | |
737 if ( cmd[0] == '"' && cmd[$-1] == '"' ) | |
738 cmdList ~= " "~cmd[1..$-1]; | |
739 else | |
740 cmdList ~= " "~cmd; | |
741 } | |
742 foreach ( cmd; split(cmdList, ";") ) | |
743 ontermCommands ~= strip(cmd)~";"; | |
744 } | |
745 break; | |
746 // print source | |
747 case "ps": | |
748 Location loc; | |
749 string[] source; | |
750 | |
751 do | |
752 { | |
753 if ( current_frame_level > 0 ) | |
754 { | |
755 auto frame = dbg.stack.getFrame(current_frame_level); | |
756 if ( frame is null ) | |
757 goto Lnotfound; | |
758 uint ret_adr = (cast(uint[])frame)[1]; | |
759 loc = dbg.images.findLocation(ret_adr); | |
760 } | |
761 else | |
762 loc = dbg.images.findLocation(dbg.current_address); | |
763 debug DbgIO.println("found location %s", loc.file); | |
764 | |
765 source = dbg.getSourceFile(loc.file); | |
766 if ( source !is null ) | |
767 break; | |
768 if ( auto_find_scope_frame ) { | |
769 ++current_frame_level; | |
770 continue; | |
771 } | |
772 Lnotfound: | |
773 DbgIO.writeln("Source file for current location unknown"); | |
774 break; | |
775 } | |
776 while( source is null ); | |
777 | |
778 int start_line, end_line; | |
779 if ( lastcmd.length > 1 ) { | |
780 start_line = cast(uint)atoi(lastcmd[1]); | |
781 end_line = loc.line + start_line; | |
782 start_line = loc.line - start_line; | |
783 } | |
784 else if ( loc.scope_sym !is null ) | |
785 { | |
786 ProcedureSymbol psym = cast(ProcedureSymbol)loc.scope_sym; | |
787 auto start_address = loc.getCodeBase + psym.cvdata.offset; | |
788 auto start_loc = dbg.images.findLocation(start_address); | |
789 auto end_loc = dbg.images.findLocation(start_address+psym.cvdata.proc_length-1); | |
790 debug DbgIO.println("address range: 0x%x 0x%x", start_address, start_address+psym.cvdata.proc_length-1); | |
791 debug DbgIO.println("lines before prev: %d - %d", start_loc.line, end_loc.line); | |
792 end_loc = dbg.images.findPrevSrcLine(end_loc); | |
793 start_line = start_loc.line; | |
794 if ( end_loc !is null ) | |
795 end_line = end_loc.line; | |
796 } | |
797 if ( end_line == 0 ) { | |
798 start_line = loc.line - PRINT_SOURCE_LINES; | |
799 end_line = loc.line + PRINT_SOURCE_LINES; | |
800 } | |
801 | |
802 debug DbgIO.println("lines: %d - %d", start_line, end_line); | |
803 for ( int l = dmax(0, start_line-1); l < dmin(cast(int)source.length, end_line); ++l ) | |
804 { | |
805 if ( l+1 == loc.line ) | |
806 DbgIO.write(">"); | |
807 DbgIO.writeln(source[l]); | |
808 } | |
809 break; | |
810 // quit | |
811 case "q": | |
812 dbg.abort = true; | |
813 quit = true; | |
814 return true; | |
815 // run/continue | |
816 case "r": | |
817 if ( dbg.miniDump !is null ) { | |
818 DbgIO.println("Command not valid in post-mortem mode"); | |
819 break; | |
820 } | |
821 if ( dbg.process_loaded ) { | |
822 dbg.resume; | |
823 return true; | |
824 } | |
825 else { | |
826 dbg.start(command_line); | |
827 return true; | |
828 } | |
829 // single-step | |
830 case "s": | |
831 if ( dbg.miniDump !is null ) { | |
832 DbgIO.println("Command not valid in post-mortem mode"); | |
833 break; | |
834 } | |
835 if ( dbg.process_loaded ) { | |
836 dbg.single_step = true; | |
837 dbg.activateSingleStep(true); | |
838 } | |
839 return true; | |
840 // add source search path | |
841 case "sp": | |
842 if ( lastcmd.length > 1 ) | |
843 { | |
844 string sp = lastcmd[1].dup; | |
845 if ( sp[$-1] != '\\' ) | |
846 sp ~= '\\'; | |
847 dbg.source_search_paths ~= sp; | |
848 } | |
849 else | |
850 DbgIO.println("usage: sp <search_path>"); | |
851 break; | |
852 // switch thread | |
853 case "st": | |
854 if ( lastcmd.length < 2 ) { | |
855 DbgIO.writeln("Usage: st <threadID>"); | |
856 break; | |
857 } | |
858 size_t threadId = cast(size_t)atoi(lastcmd[1]); | |
859 if ( dbg.miniDump !is null ) | |
860 { | |
861 foreach ( thread; dbg.miniDump.threads ) | |
862 { | |
863 if ( threadId == thread.ThreadId ) { | |
864 dbg.selectThread(threadId); | |
865 break; | |
866 } | |
867 } | |
868 } | |
869 else | |
870 { | |
871 foreach ( t; dbg.process.threads.values ) | |
872 { | |
873 if ( threadId == t.id ) { | |
874 dbg.selectThread(threadId); | |
875 break; | |
876 } | |
877 } | |
878 } | |
879 break; | |
880 // step over | |
881 case "ov": | |
882 if ( dbg.miniDump !is null ) { | |
883 DbgIO.println("Command not valid in post-mortem mode"); | |
884 break; | |
885 } | |
886 if ( dbg.process_loaded && dbg.step(StepMode.e_over) ) | |
887 { | |
888 debug foreach ( bp; dbg.temp_breakpoints ) | |
889 DbgIO.writeln(bp.value.toString); | |
890 return true; | |
891 } | |
892 break; | |
893 // step into | |
894 case "in": | |
895 if ( dbg.miniDump !is null ) { | |
896 DbgIO.println("Command not valid in post-mortem mode"); | |
897 break; | |
898 } | |
899 if ( dbg.process_loaded && dbg.step(StepMode.e_in) ) | |
900 { | |
901 debug foreach ( bp; dbg.temp_breakpoints ) | |
902 DbgIO.writeln(bp.value.toString); | |
903 return true; | |
904 } | |
905 break; | |
906 // step out | |
907 case "out": | |
908 if ( dbg.miniDump !is null ) { | |
909 DbgIO.println("Command not valid in post-mortem mode"); | |
910 break; | |
911 } | |
912 if ( dbg.process_loaded && dbg.step(StepMode.e_out) ) | |
913 { | |
914 debug foreach ( bp; dbg.temp_breakpoints ) | |
915 DbgIO.writeln(bp.value.toString); | |
916 return true; | |
917 } | |
918 break; | |
919 // disassemble | |
920 case "da": | |
921 if ( !dbg.process_loaded ) | |
922 break; | |
923 | |
924 uint start_address; | |
925 if ( current_frame_level > 0 ) { | |
926 auto frame = dbg.stack.getFrame(current_frame_level); | |
927 start_address = (cast(uint[])frame)[1]; | |
928 } | |
929 else | |
930 start_address = dbg.current_address; | |
931 | |
932 if ( lastcmd.length > 1 ) | |
933 sscanf(toStringz(lastcmd[1]), "%x", &start_address); | |
934 else | |
935 { | |
936 Location loc = dbg.images.findLocation(dbg.current_address); | |
937 if ( loc.scope_sym !is null ) { | |
938 ProcedureSymbol psym = cast(ProcedureSymbol)loc.scope_sym; | |
939 start_address = loc.getCodeBase + psym.cvdata.offset; | |
940 DisAsm.disasm(dbg.process, start_address, start_address+psym.cvdata.proc_length, &printDisassembly); | |
941 break; | |
942 } | |
943 } | |
944 DisAsm.disasm(dbg.process, start_address, 0, &printDisassembly); | |
945 break; | |
946 // disassemble line | |
947 case "dal": | |
948 if ( !dbg.process_loaded ) | |
949 break; | |
950 | |
951 int num_lines = 1; | |
952 if ( lastcmd.length > 1 ) | |
953 { | |
954 sscanf(toStringz(lastcmd[1]), "%d", &num_lines); | |
955 if ( num_lines < 0 ) | |
956 --num_lines; | |
957 } | |
958 | |
959 uint start_address; | |
960 if ( current_frame_level > 0 ) { | |
961 auto frame = dbg.stack.getFrame(current_frame_level); | |
962 start_address = (cast(uint[])frame)[1]; | |
963 } | |
964 else | |
965 start_address = dbg.current_address; | |
966 | |
967 for ( ; num_lines != 0; num_lines<0?++num_lines:--num_lines ) | |
968 { | |
969 Location loc = dbg.images.findLocation(start_address); | |
970 if ( loc is null ) { | |
971 DbgIO.println("No source line information available"); | |
972 break; | |
973 } | |
974 DisAsm.disasm( | |
975 dbg.process, | |
976 loc.getCodeBase+loc.codeblock.start, | |
977 loc.getCodeBase+loc.codeblock.end, | |
978 &printDisassembly | |
979 ); | |
980 } | |
981 break; | |
982 // dump registers | |
983 case "dr": | |
984 if ( lastcmd.length > 1 ) | |
985 { | |
986 foreach ( lc; lastcmd[1..$] ) | |
987 { | |
988 switch ( lc ) | |
989 { | |
990 case "cpu": dump_registers |= CPU_REGISTERS; break; | |
991 case "fpu": dump_registers |= FPU_REGISTERS; break; | |
992 case "mmx": dump_registers |= MMX_REGISTERS; break; | |
993 case "sse": dump_registers |= SSE_REGISTERS; break; | |
994 default: | |
995 DbgIO.println("Unknown register set \"%s\"", lc); | |
996 } | |
997 } | |
998 } | |
999 if ( dump_registers == 0 ) { | |
1000 DbgIO.println("No register set selected. See help for usage of \"dr\""); | |
1001 break; | |
1002 } | |
1003 if ( dbg.miniDump !is null ) | |
1004 printRegisterDump(dbg.miniDump.getContext); | |
1005 else if ( dbg.process_loaded ) | |
1006 printRegisterDump(dbg.process.threads[dbg.thread_id]); | |
1007 break; | |
1008 // dump stack | |
1009 case "ds": | |
1010 if ( !dbg.process_loaded ) | |
1011 break; | |
1012 | |
1013 int dump_length; | |
1014 if ( lastcmd.length > 1 ) | |
1015 dump_length = cast(int)atoi(lastcmd[1])*4; | |
1016 else | |
1017 { | |
1018 CONTEXT ctx; | |
1019 if ( dbg.process.threads[dbg.thread_id].getContext(ctx, CONTEXT_CONTROL) ) | |
1020 dump_length = ctx.Ebp-ctx.Esp+8; | |
1021 if ( dump_length <= 0 ) | |
1022 dump_length = 16*4; | |
1023 } | |
1024 int top = dbg.stack.data.length>dump_length?dump_length:dbg.stack.data.length; | |
1025 dumpMemory(dbg.stack.top_ptr, top, dbg.stack.data); | |
1026 break; | |
1027 case "dm": | |
1028 if ( !dbg.process_loaded ) | |
1029 break; | |
1030 | |
1031 if ( lastcmd.length < 3 ) { | |
1032 DbgIO.println("usage: dm <start> <length>"); | |
1033 break; | |
1034 } | |
1035 uint start; | |
1036 sscanf(toStringz(lastcmd[1]), "%x", &start); | |
1037 dumpMemory(start, cast(uint)atoi(lastcmd[2])); | |
1038 break; | |
1039 case "hwbp": | |
1040 int index; | |
1041 if ( lastcmd.length < 2 ) { | |
1042 DbgIO.println("invalid syntax - see help for details"); | |
1043 break; | |
1044 } | |
1045 | |
1046 int pos = find(lastcmd[1], '#'); | |
1047 uint threadId; | |
1048 if ( pos > 0 ) | |
1049 { | |
1050 threadId = cast(uint)atoi(lastcmd[1][pos+1..$]); | |
1051 lastcmd[1] = lastcmd[1][0..pos]; | |
1052 } | |
1053 | |
1054 Location loc; | |
1055 | |
1056 size_t address; | |
1057 sscanf(toStringz(lastcmd[1]), "%x", &address); | |
1058 if ( address > 0 ) | |
1059 loc = new Location(address); | |
1060 else | |
1061 loc = new Location(lastcmd[1]); | |
1062 loc.bind(dbg.images, dbg.source_search_paths); | |
1063 if ( lastcmd.length > 2 ) | |
1064 index = cast(int)atoi(lastcmd[2]); | |
1065 | |
1066 Breakpoint bp; | |
1067 if ( index <= 0 && dbg.breakpoints.length > 0 ) | |
1068 index = dbg.breakpoints.keys.dup.sort[$-1]+1; | |
1069 bp = dbg.setBreakpoint(loc, index, threadId, true); | |
1070 DbgIO.println("Hardware Breakpoint set: %s", bp.toString); | |
1071 break; | |
1072 // type of expression | |
1073 case "t": | |
1074 if ( dbg.process_loaded && lastcmd.length > 1 ) | |
1075 { | |
1076 SymbolData sd; | |
1077 try { | |
1078 sd = dbg.evaluateExpression(lastcmd[1], current_frame_level); | |
1079 string type = demangle("_D0"~sd.type); | |
1080 DbgIO.println("%s\n%s", sd.type, type); | |
1081 } | |
1082 catch ( EvaluationException e ) { | |
1083 DbgIO.writeln(e.toString); | |
1084 } | |
1085 } | |
1086 break; | |
1087 // unwind stack | |
1088 case "us": | |
1089 if ( dbg.process_loaded || dbg.miniDump !is null ) | |
1090 unwindStack(); | |
1091 break; | |
1092 // write minidump | |
1093 case "wmd": | |
1094 if ( dbg.miniDump !is null ) { | |
1095 DbgIO.println("Command not valid in post-mortem mode"); | |
1096 break; | |
1097 } | |
1098 if ( !dbg.process_loaded ) | |
1099 break; | |
1100 if ( !MiniDump.haveMiniDump ) { | |
1101 DbgIO.println("DbgHelp.dll required for MiniDump support.\nInstall the Microsoft Platform SDK or Windows XP."); | |
1102 break; | |
1103 } | |
1104 if ( lastcmd.length < 2 ) { | |
1105 DbgIO.println("Usage: wmd <filename>"); | |
1106 break; | |
1107 } | |
1108 dbg.writeMiniDump(lastcmd[1]); | |
1109 break; | |
1110 // read minidump | |
1111 case "rmd": | |
1112 if ( dbg.process_loaded ) { | |
1113 DbgIO.println("For post-mortem debugging, the process must not be started"); | |
1114 break; | |
1115 } | |
1116 if ( !MiniDump.haveMiniDump ) { | |
1117 DbgIO.println("DbgHelp.dll required for MiniDump support.\nInstall the Microsoft Platform SDK or Windows XP."); | |
1118 break; | |
1119 } | |
1120 if ( lastcmd.length < 2 ) { | |
1121 DbgIO.println("Usage: rmd <filename>"); | |
1122 break; | |
1123 } | |
1124 dbg.readMiniDump(lastcmd[1]); | |
1125 break; | |
1126 // unknown command | |
1127 default: | |
1128 DbgIO.println("Unknown command '%s' ignored!", lastcmd[0]); | |
1129 break; | |
1130 } | |
1131 | |
1132 return false; | |
1133 } | |
1134 | |
1135 /********************************************************************************************** | |
1136 | |
1137 **********************************************************************************************/ | |
1138 void dumpMemory(uint start, uint length, ubyte[] _data=null) | |
1139 { | |
1140 ubyte[] data; | |
1141 if ( _data is null ) | |
1142 { | |
1143 data.length = length; | |
1144 if ( !dbg.process.readProcessMemory(start, data.ptr, data.length) ) | |
1145 return; | |
1146 } | |
1147 else | |
1148 data = _data; | |
1149 for ( uint i = 0; i < length; ++i ) | |
1150 { | |
1151 if ( i % (4*4) == 0 ) | |
1152 { | |
1153 if ( i > 0 ) | |
1154 DbgIO.println(""); | |
1155 DbgIO.print("%08x:", start+i); | |
1156 } | |
1157 if ( i % 4 == 0 ) | |
1158 DbgIO.print(" "); | |
1159 DbgIO.print("%02x", data[i]); | |
1160 } | |
1161 DbgIO.println(""); | |
1162 } | |
1163 | |
1164 /********************************************************************************************** | |
1165 | |
1166 **********************************************************************************************/ | |
1167 void evalScopeSymbols() | |
1168 { | |
1169 uint scope_address = dbg.getScopeAddress(current_frame_level); | |
1170 | |
1171 ScopeSymbol scope_sym = dbg.images.findProcedureSymbol(scope_address); | |
1172 if ( scope_sym is null ) { | |
1173 DbgIO.println("No valid scope active"); | |
1174 return; | |
1175 } | |
1176 | |
1177 for ( ; scope_sym !is null; scope_sym = scope_sym.parent_scope ) | |
1178 { | |
1179 DbgIO.println("Scope: %s, parent: %x", scope_sym.name_type, cast(void*)scope_sym.parent_scope); | |
1180 | |
1181 StackSymbol[] locals_args = scope_sym.symbols.stack_symbols; | |
1182 auto psym = cast(ProcedureSymbol)scope_sym; | |
1183 if ( psym !is null ) | |
1184 locals_args ~= psym.arguments.stack_symbols; | |
1185 foreach ( sym; locals_args.sort ) | |
1186 { | |
1187 string name = sym.mangled_name; | |
1188 DbgIO.print("%s = ", name); | |
1189 // DbgIO.print("%s = [ebp%s%d] ", name, sym.cvdata.offset>0?"+":"", sym.cvdata.offset); | |
1190 try DbgIO.writeln(symbolValueToString(dbg.handleData(dbg.evaluateExpression(name, current_frame_level, sym), true))); | |
1191 catch ( EvaluationException e ) { | |
1192 DbgIO.println(e.msg); | |
1193 } | |
1194 } | |
1195 } | |
1196 } | |
1197 | |
1198 /********************************************************************************************** | |
1199 | |
1200 **********************************************************************************************/ | |
1201 void printAsmLine(uint address, string bytes, string asmsource, string symbol, string location, string source) | |
1202 { | |
1203 bool nl = false; | |
1204 if ( location !is null ) { | |
1205 DbgIO.print("%s ", location); | |
1206 nl = true; | |
1207 } | |
1208 if ( source !is null ) { | |
1209 DbgIO.write(source); | |
1210 nl = true; | |
1211 } | |
1212 if ( nl ) | |
1213 DbgIO.println; | |
1214 | |
1215 // align next column | |
1216 char[] indent; | |
1217 int indcount = 2*12-bytes.length; | |
1218 if ( indcount > 0 ) { | |
1219 indent.length = indcount; | |
1220 indent[0..indcount] = ' '; | |
1221 } | |
1222 // print aligned asm source | |
1223 assert(asmsource !is null); | |
1224 assert(bytes !is null); | |
1225 DbgIO.print("%08x: ", address, bytes, indent, asmsource); | |
1226 | |
1227 if ( symbol !is null ) | |
1228 DbgIO.write(symbol); | |
1229 DbgIO.println; | |
1230 } | |
1231 | |
1232 /********************************************************************************************** | |
1233 Prints the register contents of the given thread's context. | |
1234 **********************************************************************************************/ | |
1235 void printRegisterDump(DbgThread thread) | |
1236 { | |
1237 CONTEXT ctxMem; | |
1238 uint context_flags; | |
1239 if ( dump_registers & CPU_REGISTERS ) | |
1240 context_flags |= CONTEXT_FULL; | |
1241 if ( dump_registers & FPU_REGISTERS ) | |
1242 context_flags |= CONTEXT_FLOATING_POINT; | |
1243 if ( dump_registers & (MMX_REGISTERS|SSE_REGISTERS) ) | |
1244 context_flags |= CONTEXT_EXTENDED_REGISTERS; | |
1245 if ( thread.getContext(ctxMem, context_flags) ) | |
1246 printRegisterDump(&ctxMem); | |
1247 else | |
1248 DbgIO.println("ERROR: Couldn't get main thread's context"); | |
1249 } | |
1250 | |
1251 void printRegisterDump(CONTEXT* ctx) | |
1252 { | |
1253 assert ( ctx !is null ); | |
1254 | |
1255 bool first = true; | |
1256 | |
1257 if ( dump_registers & CPU_REGISTERS ) | |
1258 { | |
1259 DbgIO.println("EAX = %08x\tEBX = %08x\tECX = %08x\tEDX = %08x", ctx.Eax, ctx.Ebx, ctx.Ecx, ctx.Edx); | |
1260 DbgIO.println("EDI = %08x\tESI = %08x\tEBP = %08x\tESP = %08x", ctx.Edi, ctx.Esi, ctx.Ebp, ctx.Esp); | |
1261 DbgIO.println("EIP = %08x\tEFL = %08x", ctx.Eip, ctx.EFlags); | |
1262 DbgIO.println(" CS = %08x\t DS = %08x\t ES = %08x\t FS = %08x", ctx.SegCs, ctx.SegDs, ctx.SegEs, ctx.SegFs); | |
1263 DbgIO.println(" GS = %08x\t SS = %08x", ctx.SegGs, ctx.SegSs); | |
1264 first = false; | |
1265 } | |
1266 | |
1267 if ( dump_registers & FPU_REGISTERS ) | |
1268 { | |
1269 if ( !first ) | |
1270 DbgIO.println(); | |
1271 DbgIO.println("FCW = %04x\tFSW = %04x\tFTW = %04x\tFOP = %04x", | |
1272 cast(ushort)ctx.FloatSave.ControlWord, cast(ushort)ctx.FloatSave.StatusWord, | |
1273 cast(ushort)ctx.FloatSave.TagWord, (cast(ushort[])ctx.ExtendedRegisters)[3] | |
1274 ); | |
1275 DbgIO.println("IP = %08x\tCS = %04x\tDP = %08x\tDS = %04x", | |
1276 (cast(uint[])ctx.ExtendedRegisters)[2], (cast(ushort[])ctx.ExtendedRegisters)[6], | |
1277 (cast(uint[])ctx.ExtendedRegisters)[4], (cast(ushort[])ctx.ExtendedRegisters)[10] | |
1278 ); | |
1279 for ( int i = 0; i < 8; ++i ) | |
1280 DbgIO.println("ST%d = % .16e", i, (cast(real[])ctx.FloatSave.RegisterArea)[i]); | |
1281 first = false; | |
1282 } | |
1283 | |
1284 if ( dump_registers & MMX_REGISTERS ) | |
1285 { | |
1286 if ( !first ) | |
1287 DbgIO.println(); | |
1288 for ( int i = 0; i < 8; ++i ) | |
1289 { | |
1290 DbgIO.println("MM%d = %016x", i, (cast(long[])ctx.ExtendedRegisters)[4+i*2]); | |
1291 DbgIO.println(" = [%.6g, %.6g]", | |
1292 (cast(float[])ctx.ExtendedRegisters)[8+i*4], | |
1293 (cast(float[])ctx.ExtendedRegisters)[8+i*4+1] | |
1294 ); | |
1295 } | |
1296 first = false; | |
1297 } | |
1298 | |
1299 if ( dump_registers & SSE_REGISTERS ) | |
1300 { | |
1301 if ( !first ) | |
1302 DbgIO.println(); | |
1303 DbgIO.println("MXCSR = %08x", (cast(uint[])ctx.ExtendedRegisters)[6]); | |
1304 for ( int i = 0; i < 8; ++i ) | |
1305 { | |
1306 DbgIO.println("XMM%d = %016x%016x", i, (cast(long[])ctx.ExtendedRegisters)[20+i*2+1], (cast(long[])ctx.ExtendedRegisters)[20+i*2]); | |
1307 DbgIO.println(" = [%.6g, %.6g, %.6g, %.6g]", | |
1308 (cast(float[])ctx.ExtendedRegisters)[40+i*4], | |
1309 (cast(float[])ctx.ExtendedRegisters)[40+i*4+1], | |
1310 (cast(float[])ctx.ExtendedRegisters)[40+i*4+2], | |
1311 (cast(float[])ctx.ExtendedRegisters)[40+i*4+3] | |
1312 ); | |
1313 DbgIO.println(" = [%.12g, %.12g]", | |
1314 (cast(double[])ctx.ExtendedRegisters)[20+i*2], | |
1315 (cast(double[])ctx.ExtendedRegisters)[20+i*2+1] | |
1316 ); | |
1317 } | |
1318 } | |
1319 } | |
1320 | |
1321 /********************************************************************************************** | |
1322 | |
1323 **********************************************************************************************/ | |
1324 string symbolValueToString(SymbolValue val) | |
1325 { | |
1326 return symbolValueToString(val,""); | |
1327 } | |
1328 | |
1329 string symbolValueToString(SymbolValue val, string indent) | |
1330 { | |
1331 string str; | |
1332 if ( val.name !is null ) | |
1333 str = val.name~" = "; | |
1334 if ( val.value !is null ) | |
1335 str ~= val.value; | |
1336 else | |
1337 { | |
1338 if ( val.children.length > 0 ) | |
1339 { | |
1340 str ~= "{"; | |
1341 bool first = true; | |
1342 foreach ( c; val.children ) | |
1343 { | |
1344 if ( first ) | |
1345 first = false; | |
1346 else | |
1347 str ~= ","; | |
1348 str ~= "\n "~indent~symbolValueToString(c, indent~" "); | |
1349 } | |
1350 str ~= "\n"~indent~"}"; | |
1351 } | |
1352 else | |
1353 str ~= "{}"; | |
1354 } | |
1355 return str; | |
1356 } | |
1357 | |
1358 /********************************************************************************************** | |
1359 Read command and call CLI supplied parser function. | |
1360 Gets called when debuggee is suspended. | |
1361 **********************************************************************************************/ | |
1362 bool readCommand() | |
1363 { | |
1364 if ( cmdQueue.length <= 0 ) { | |
1365 DbgIO.write("->"); | |
1366 string input = DbgIO.readln(); | |
1367 cmdQueue ~= input; | |
1368 } | |
1369 if ( cmdQueue.length <= 0 ) | |
1370 return false; | |
1371 | |
1372 string cmd = strip(cmdQueue[0]); | |
1373 cmdQueue = cmdQueue[1..$]; | |
1374 if ( cmd.length > 0 && cmd[$-1] == ';' ) { | |
1375 cmd = cmd[0..$-1]; | |
1376 DbgIO.writeln("->"~cmd); | |
1377 } | |
1378 return parseCommand(cmd); | |
1379 } | |
1380 } |