1
|
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.userinterface;
|
|
6
|
|
7 import breakpoint;
|
|
8 import dbgprocess;
|
|
9 import dbgthread;
|
|
10 import debugger;
|
|
11 import expression.datahandler;
|
|
12 import codeview.codeview;
|
|
13 import util;
|
|
14 import disasm;
|
|
15 import codeview.coff;
|
|
16
|
|
17 import win32.winnt;
|
|
18
|
|
19 import std.string;
|
|
20 import std.c.string;
|
|
21 import std.utf;
|
|
22
|
|
23 interface UserInterface
|
|
24 {
|
|
25 void init(string[] args);
|
|
26 int start();
|
|
27
|
|
28 bool readCommand();
|
|
29 bool parseCommand(string cmd);
|
|
30 void runCommands(string cmdstr);
|
|
31
|
|
32 void debugString(string str);
|
|
33 bool breakpoint(int index, Breakpoint bp, DbgThread thread);
|
|
34 void userInterrupt();
|
|
35 void exception(uint threadId, string class_name, string msg, size_t obj_ptr);
|
|
36 void win32exception(uint threadId, EXCEPTION_RECORD* exrec);
|
|
37 void loadedDLL(DLL dll);
|
|
38 void exitProcess();
|
|
39 void singleStep();
|
|
40 }
|
|
41
|
|
42 struct StackTraceEntry
|
|
43 {
|
|
44 uint index;
|
|
45 Location loc;
|
|
46 uint frame_level;
|
|
47 CodeBlock last_known_cb;
|
|
48
|
|
49 void describe(UserInterfaceBase ui)
|
|
50 {
|
|
51 DbgIO.print("#%d ", index);
|
|
52 if ( loc is null ) {
|
|
53 DbgIO.println("<no debug symbols available>");
|
|
54 return;
|
|
55 }
|
|
56 if ( index > 0 )
|
|
57 DbgIO.print("0x%08x in ", loc.address);
|
|
58 if ( loc.scope_sym !is null )
|
|
59 {
|
|
60 ProcedureSymbol psym = cast(ProcedureSymbol)loc.scope_sym;
|
|
61
|
|
62 string argstr;
|
|
63 bool first = true;
|
|
64 foreach_reverse ( argsym; psym.arguments.stack_symbols )
|
|
65 {
|
|
66 string name = argsym.name_notype;
|
|
67 if ( !first )
|
|
68 argstr ~= ", ";
|
|
69 else
|
|
70 first = false;
|
|
71 argstr ~= argsym.name_notype;
|
|
72 try {
|
|
73 SymbolValue symval = ui.dbg.handleData(ui.dbg.evaluateExpression(name, frame_level), false);
|
|
74 argstr ~= " = "~ui.symbolValueToString(symval);
|
|
75 }
|
|
76 catch ( Exception e ) {
|
|
77 }
|
|
78 }
|
|
79 int end = find(psym.name_type, '('),
|
|
80 start = find(psym.name_type, ' ');
|
|
81 if ( end < 0 )
|
|
82 end = psym.name_type.length;
|
|
83 if ( start < 0 )
|
|
84 start = 0;
|
|
85 if ( end-start < 2 )
|
|
86 start = 0;
|
|
87 DbgIO.print("%s (", psym.name_type[start..end]);
|
|
88 DbgIO.write(argstr~") ");
|
|
89 }
|
|
90 else if ( loc.data_sym !is null )
|
|
91 DbgIO.print(loc.data_sym.name_type, " () ");
|
|
92 else
|
|
93 DbgIO.print("?? () ");
|
|
94 if ( loc.codeblock !is null )
|
|
95 DbgIO.print("at %s:%d", loc.file, loc.line);
|
|
96 else
|
|
97 {
|
|
98 if ( last_known_cb !is null && last_known_cb.segment !is null )
|
|
99 DbgIO.print("at %s:%d ", last_known_cb.segment.file.name, last_known_cb.line);
|
|
100 if ( loc.mod !is null )
|
|
101 DbgIO.print("from %s", loc.mod.name);
|
|
102 else if ( ui.dbg.process !is null )
|
|
103 {
|
|
104 DLL dll = ui.dbg.process.findDLL(loc.address);
|
|
105 if ( dll !is null )
|
|
106 DbgIO.print("from %s", dll.image.name);
|
|
107 }
|
|
108 }
|
|
109 DbgIO.println("");
|
|
110 }
|
|
111 }
|
|
112
|
|
113 abstract class UserInterfaceBase : UserInterface
|
|
114 {
|
|
115 CodeBlock last_codeblock;
|
|
116 Module last_module;
|
|
117 DLL last_dll;
|
|
118
|
|
119 Debugger dbg;
|
|
120
|
|
121 string[] cmdQueue;
|
|
122
|
|
123 void printAsmLine(uint address, string bytes, string asmsource, string symbol, string location, string source);
|
|
124 string symbolValueToString(SymbolValue val);
|
|
125
|
|
126 /**********************************************************************************************
|
|
127
|
|
128 **********************************************************************************************/
|
|
129 void unwindStack()
|
|
130 {
|
|
131 StackTraceEntry[] entries;
|
|
132
|
|
133 uint index,
|
|
134 counter,
|
|
135 frame_level;
|
|
136 debug DbgIO.println("Stack: base 0x%x top 0x%x frame 0x%x", dbg.stack.base_ptr, dbg.stack.top_ptr, dbg.stack.frame_ptr);
|
|
137 Location loc = dbg.images.findLocation(dbg.current_address);
|
|
138 if ( loc is null )
|
|
139 loc = new Location(dbg.current_address, null);
|
|
140 entries ~= StackTraceEntry(counter++, loc, frame_level);
|
|
141
|
|
142 dbg.stack.firstFrame(index);
|
|
143 ubyte[] frame = dbg.stack.prevFrame(index, index);
|
|
144 size_t next_frame=1;
|
|
145 while ( frame !is null )
|
|
146 {
|
|
147 uint ret_adr = (cast(uint[])frame)[1];
|
|
148 loc = dbg.images.findLocation(ret_adr);
|
|
149 if ( loc is null )
|
|
150 loc = new Location(ret_adr, null);
|
|
151 frame = dbg.stack.prevFrame(index, index);
|
|
152 ++frame_level;
|
|
153 if ( next_frame >= entries.length )
|
|
154 entries.length = entries.length*2+1;
|
|
155 entries[next_frame++] = StackTraceEntry(counter++, loc, frame_level);
|
|
156 }
|
|
157 entries.length = next_frame;
|
|
158
|
|
159 CodeBlock last_known_cb;
|
|
160 foreach_reverse ( ref ste; entries )
|
|
161 {
|
|
162 if ( ste.loc !is null && ste.loc.codeblock !is null )
|
|
163 last_known_cb = ste.loc.codeblock;
|
|
164 else
|
|
165 ste.last_known_cb = last_known_cb;
|
|
166 }
|
|
167
|
|
168 foreach ( ste; entries )
|
|
169 ste.describe(this);
|
|
170 }
|
|
171
|
|
172 /**********************************************************************************************
|
|
173 Prints an instruction with looked up symbols if existant.
|
|
174 **********************************************************************************************/
|
|
175 bool printDisassembly(ud_t* ud_obj)
|
|
176 {
|
|
177 // first call
|
|
178 if ( ud_obj is null ) {
|
|
179 last_codeblock = null;
|
|
180 return true;
|
|
181 }
|
|
182
|
|
183 uint address = cast(uint)ud_insn_off(ud_obj);
|
|
184 string source, location;
|
|
185
|
|
186 // check whether we have symbols here
|
|
187 Location loc = dbg.images.findLocation(address);
|
|
188 if ( loc.codeblock !is null )
|
|
189 {
|
|
190 if ( last_codeblock !is loc.codeblock )
|
|
191 {
|
|
192 last_codeblock = loc.codeblock;
|
|
193 string[] source_file = dbg.getSourceFile(loc.file);
|
|
194 location = format("%s:%d", loc.file, loc.line);
|
|
195 if ( source_file !is null && loc.line <= source_file.length )
|
|
196 source = source_file[loc.line-1];
|
|
197 }
|
|
198 }
|
|
199 else
|
|
200 {
|
|
201 CodeView cv;
|
|
202 CodeBlock cb = dbg.images.findCodeBlockRel(address, cv);
|
|
203 if ( cb !is null )
|
|
204 {
|
|
205 if ( last_codeblock !is cb )
|
|
206 last_codeblock = cb;
|
|
207 }
|
|
208 else
|
|
209 {
|
|
210 uint seg;
|
|
211 Module mod = dbg.images.findModule(address, seg);
|
|
212 if ( mod !is null && last_module !is mod ) {
|
|
213 last_module = mod;
|
|
214 location = mod.name;
|
|
215 }
|
|
216 else
|
|
217 {
|
|
218 DLL dll = dbg.process.findDLL(address);
|
|
219 if ( dll !is null && last_dll !is dll ) {
|
|
220 last_dll = dll;
|
|
221 location = dll.image.name;
|
|
222 }
|
|
223 }
|
|
224 }
|
|
225 }
|
|
226
|
|
227 string symbol;
|
|
228 bool is_imm=true;
|
|
229 uint jmp_dest = DisAsm.calcJumpDestination(dbg.process, dbg.process.threads[dbg.thread_id], ud_obj, is_imm);
|
|
230 if ( is_imm && jmp_dest>0 )
|
|
231 symbol = "\t"~describeLocation(jmp_dest, false);
|
|
232
|
|
233 char* hex = ud_insn_hex(ud_obj);
|
|
234 uint hexlen = strlen(hex);
|
|
235 char* ins = ud_insn_asm(ud_obj);
|
|
236
|
|
237 printAsmLine(address, hex[0..hexlen], ins[0..strlen(ins)], symbol, location, source);
|
|
238 return true;
|
|
239 }
|
|
240
|
|
241 /**********************************************************************************************
|
|
242
|
|
243 **********************************************************************************************/
|
|
244 void printSymbols(CodeView cv, NamedSymbol[] syms, string substring=null, uint indent=0)
|
|
245 {
|
|
246 foreach ( ns; syms )
|
|
247 {
|
|
248 if ( substring.length > 0 && find(ns.name_notype, substring)<0 )
|
|
249 continue;
|
|
250
|
|
251 char[] indent_str;
|
|
252 indent_str.length = indent*2;
|
|
253 indent_str[0..indent*2] = ' ';
|
|
254 ClassInfo cs = ns.classinfo;
|
|
255 if ( cs == ProcedureSymbol.classinfo )
|
|
256 {
|
|
257 ProcedureSymbol ps = cast(ProcedureSymbol)ns;
|
|
258 size_t start = ps.cvdata.offset+cv.getCodeBase;
|
|
259 DbgIO.println("%s%s %d arguments, entry 0x%x, debug start 0x%x, debug end 0x%x",
|
|
260 indent_str, ps.name_type, ps.arguments.symbols.length, start,
|
|
261 start+ps.cvdata.debug_start, start+ps.cvdata.debug_end
|
|
262 );
|
|
263 }
|
|
264 else if ( cs == StackSymbol.classinfo ) {
|
|
265 StackSymbol ss = cast(StackSymbol)ns;
|
|
266 DbgIO.println("%s%s stack (%s) %x ebp%s%d", indent_str, ns.name_type, ns.mangled_name, ss.cvtype, ss.offset>=0?"+":"", ss.offset);
|
|
267 }
|
|
268 else if ( cs == DataSymbol.classinfo )
|
|
269 {
|
|
270 DataSymbol ds = cast(DataSymbol)ns;
|
|
271 DbgIO.println("%s%s (%s) data offset: 0x%x size: 0x%x segment: 0x%x type: 0x%x (%s)", indent_str, ds.name_type, ds.name_notype,
|
|
272 ds.offset, ds.size, ds.cvdata.segment, ds.cvdata.type, dbg.images.mangleCVtype(ds.cvdata.type)
|
|
273 );
|
|
274 }
|
|
275 else
|
|
276 DbgIO.println("%s%s %s", indent_str, ns.name_type, cs.name);
|
|
277 ScopeSymbol scs = cast(ScopeSymbol)ns;
|
|
278 if ( scs !is null )
|
|
279 printSymbols(cv, scs.symbols.named_symbols, substring, indent+1);
|
|
280 }
|
|
281 }
|
|
282
|
|
283 /**********************************************************************************************
|
|
284
|
|
285 **********************************************************************************************/
|
|
286 string describeLocation(uint vaddress, bool with_address=true)
|
|
287 {
|
|
288 Location loc = dbg.images.findLocation(vaddress);
|
|
289 return describeLocation(loc, with_address);
|
|
290 }
|
|
291
|
|
292 /**********************************************************************************************
|
|
293
|
|
294 **********************************************************************************************/
|
|
295 string describeLocation(Location loc, bool with_address=true)
|
|
296 {
|
|
297 string desc;
|
|
298
|
|
299 if ( loc is null )
|
|
300 return "unknown";
|
|
301
|
|
302 if ( loc.codeblock !is null )
|
|
303 desc = format("%s:%d", loc.file, loc.line);
|
|
304 if ( with_address )
|
|
305 desc ~= (desc.length>0?" ":"")~format("(0x%08x)", loc.address);
|
|
306
|
|
307 if ( loc.scope_sym !is null )
|
|
308 return loc.scope_sym.name_notype~" "~desc;
|
|
309 if ( loc.data_sym !is null )
|
|
310 return loc.data_sym.name_notype~" "~desc;
|
|
311 if ( loc.mod !is null )
|
|
312 return loc.mod.name~" "~desc;
|
|
313 if ( dbg.process !is null )
|
|
314 {
|
|
315 DLL dll = dbg.process.findDLL(loc.address);
|
|
316 if ( dll !is null )
|
|
317 return dll.image.name~" "~desc;
|
|
318 }
|
|
319
|
|
320 return desc;
|
|
321 }
|
|
322
|
|
323 /**********************************************************************************************
|
|
324
|
|
325 **********************************************************************************************/
|
|
326 void runCommands(string cmd_string)
|
|
327 {
|
|
328 cmd_string = replace(cmd_string, "\\\"", "\"");
|
|
329 auto r = std.regexp.RegExp("(([^;\" \\t]+)|(\"[^\"]+\"))+|;");
|
|
330 string cmd;
|
|
331 string[] cmds;
|
|
332 foreach ( m; r.search(cmd_string) )
|
|
333 {
|
|
334 if ( m.match(0) == ";" ) {
|
|
335 cmdQueue ~= cmd~";";
|
|
336 cmd = null;
|
|
337 }
|
|
338 else
|
|
339 cmd ~= " "~m.match(0);
|
|
340 }
|
|
341 if ( cmd !is null )
|
|
342 cmdQueue ~= cmd~";";
|
|
343 }
|
|
344 }
|