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
|
|
6 import std.ctype;
|
|
7 import std.stdio;
|
|
8 import std.string;
|
|
9 import std.c.string;
|
|
10 import std.c.stdio;
|
|
11 import std.format;
|
|
12 import std.date : getUTCtime, d_time, TicksPerSecond;
|
|
13 import std.demangle;
|
|
14
|
|
15 import win32.winbase;
|
|
16 import win32.windef;
|
|
17
|
|
18 import std.typeinfo.ti_AC;
|
|
19 import std.typeinfo.ti_Acdouble;
|
|
20 import std.typeinfo.ti_Acfloat;
|
|
21 import std.typeinfo.ti_Acreal;
|
|
22 import std.typeinfo.ti_Adouble;
|
|
23 import std.typeinfo.ti_Afloat;
|
|
24 import std.typeinfo.ti_Ag;
|
|
25 import std.typeinfo.ti_Aint;
|
|
26 import std.typeinfo.ti_Along;
|
|
27 import std.typeinfo.ti_Areal;
|
|
28 import std.typeinfo.ti_Ashort;
|
|
29 import std.typeinfo.ti_byte;
|
|
30 import std.typeinfo.ti_C;
|
|
31 import std.typeinfo.ti_cdouble;
|
|
32 import std.typeinfo.ti_cfloat;
|
|
33 import std.typeinfo.ti_char;
|
|
34 import std.typeinfo.ti_creal;
|
|
35 import std.typeinfo.ti_dchar;
|
|
36 import std.typeinfo.ti_delegate;
|
|
37 import std.typeinfo.ti_double;
|
|
38 import std.typeinfo.ti_float;
|
|
39 import std.typeinfo.ti_idouble;
|
|
40 import std.typeinfo.ti_ifloat;
|
|
41 import std.typeinfo.ti_int;
|
|
42 import std.typeinfo.ti_ireal;
|
|
43 import std.typeinfo.ti_long;
|
|
44 import std.typeinfo.ti_ptr;
|
|
45 import std.typeinfo.ti_real;
|
|
46 import std.typeinfo.ti_short;
|
|
47 import std.typeinfo.ti_ubyte;
|
|
48 import std.typeinfo.ti_uint;
|
|
49 import std.typeinfo.ti_ulong;
|
|
50 import std.typeinfo.ti_ushort;
|
|
51 import std.typeinfo.ti_void;
|
|
52 import std.typeinfo.ti_wchar;
|
|
53
|
|
54 /**************************************************************************************************
|
|
55
|
|
56 **************************************************************************************************/
|
|
57 T dmax(T)(T a, T b)
|
|
58 {
|
|
59 return a<b?b:a;
|
|
60 }
|
|
61
|
|
62 T dmin(T)(T a, T b)
|
|
63 {
|
|
64 return a>b?b:a;
|
|
65 }
|
|
66
|
|
67 /**************************************************************************************************
|
|
68
|
|
69 **************************************************************************************************/
|
|
70 uint intFromStr(string str)
|
|
71 {
|
|
72 uint i;
|
|
73 foreach_reverse ( c; str )
|
|
74 i = i<<8 | c;
|
|
75 return i;
|
|
76 }
|
|
77
|
|
78 /**************************************************************************************************
|
|
79
|
|
80 **************************************************************************************************/
|
|
81 string itoa(uint i)
|
|
82 {
|
|
83 if ( i == 0 )
|
|
84 return "0";
|
|
85 string str;
|
|
86 for ( ; i > 0; i /= 10 )
|
|
87 str = "0123456789"[i%10] ~ str;
|
|
88 return str;
|
|
89 }
|
|
90
|
|
91 /**************************************************************************************************
|
|
92
|
|
93 **************************************************************************************************/
|
|
94 string TODO(string file, uint line, string msg)
|
|
95 {
|
|
96 return "TODO - "~file~"("~itoa(line)~"): "~msg~"";
|
|
97 }
|
|
98
|
|
99 /**************************************************************************************************
|
|
100
|
|
101 **************************************************************************************************/
|
|
102 string formatTicks(ulong ticks)
|
|
103 {
|
|
104 SYSTEMTIME stime;
|
|
105 if ( !FileTimeToSystemTime(cast(FILETIME*)&ticks, &stime) )
|
|
106 return "invalid";
|
|
107 string str = format("%02d:%02d:%02d.%03d", stime.wHour, stime.wMinute, stime.wSecond, stime.wMilliseconds);
|
|
108 return str;
|
|
109 }
|
|
110
|
|
111 /**************************************************************************************************
|
|
112 Name lookup for win32 DebugEventCodes.
|
|
113 **************************************************************************************************/
|
|
114 string getEventName(uint event)
|
|
115 {
|
|
116 switch ( event )
|
|
117 {
|
|
118 case EXCEPTION_DEBUG_EVENT : return "EXCEPTION_DEBUG_EVENT";
|
|
119 case CREATE_THREAD_DEBUG_EVENT : return "CREATE_THREAD_DEBUG_EVENT";
|
|
120 case CREATE_PROCESS_DEBUG_EVENT : return "CREATE_PROCESS_DEBUG_EVENT";
|
|
121 case EXIT_THREAD_DEBUG_EVENT : return "EXIT_THREAD_DEBUG_EVENT";
|
|
122 case EXIT_PROCESS_DEBUG_EVENT : return "EXIT_PROCESS_DEBUG_EVENT";
|
|
123 case LOAD_DLL_DEBUG_EVENT : return "LOAD_DLL_DEBUG_EVENT";
|
|
124 case UNLOAD_DLL_DEBUG_EVENT : return "UNLOAD_DLL_DEBUG_EVENT";
|
|
125 case OUTPUT_DEBUG_STRING_EVENT : return "OUTPUT_DEBUG_STRING_EVENT";
|
|
126 case RIP_EVENT: return "RIP_EVENT";
|
|
127 default : break;
|
|
128 }
|
|
129 return "";
|
|
130 }
|
|
131
|
|
132 /**************************************************************************************************
|
|
133 Name lookup for win32 ExceptionCodes.
|
|
134 **************************************************************************************************/
|
|
135 string getExceptionName(uint excpt)
|
|
136 {
|
|
137 switch ( excpt )
|
|
138 {
|
|
139 case EXCEPTION_ACCESS_VIOLATION : return "EXCEPTION_ACCESS_VIOLATION";
|
|
140 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED : return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
|
|
141 case EXCEPTION_BREAKPOINT : return "EXCEPTION_BREAKPOINT";
|
|
142 case EXCEPTION_DATATYPE_MISALIGNMENT : return "EXCEPTION_DATATYPE_MISALIGNMENT";
|
|
143 case EXCEPTION_FLT_DENORMAL_OPERAND : return "EXCEPTION_FLT_DENORMAL_OPERAND";
|
|
144 case EXCEPTION_FLT_DIVIDE_BY_ZERO : return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
|
|
145 case EXCEPTION_FLT_INEXACT_RESULT : return "EXCEPTION_FLT_INEXACT_RESULT";
|
|
146 case EXCEPTION_FLT_INVALID_OPERATION : return "EXCEPTION_FLT_INVALID_OPERATION";
|
|
147 case EXCEPTION_FLT_OVERFLOW : return "EXCEPTION_FLT_OVERFLOW";
|
|
148 case EXCEPTION_FLT_STACK_CHECK : return "EXCEPTION_FLT_STACK_CHECK";
|
|
149 case EXCEPTION_FLT_UNDERFLOW : return "EXCEPTION_FLT_UNDERFLOW";
|
|
150 case EXCEPTION_ILLEGAL_INSTRUCTION : return "EXCEPTION_ILLEGAL_INSTRUCTION";
|
|
151 case EXCEPTION_IN_PAGE_ERROR : return "EXCEPTION_IN_PAGE_ERROR";
|
|
152 case EXCEPTION_INT_DIVIDE_BY_ZERO : return "EXCEPTION_INT_DIVIDE_BY_ZERO";
|
|
153 case EXCEPTION_INT_OVERFLOW : return "EXCEPTION_INT_OVERFLOW";
|
|
154 case EXCEPTION_INVALID_DISPOSITION : return "EXCEPTION_INVALID_DISPOSITION";
|
|
155 case EXCEPTION_NONCONTINUABLE_EXCEPTION : return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
|
|
156 case EXCEPTION_PRIV_INSTRUCTION : return "EXCEPTION_PRIV_INSTRUCTION";
|
|
157 case EXCEPTION_SINGLE_STEP : return "EXCEPTION_SINGLE_STEP";
|
|
158 case EXCEPTION_STACK_OVERFLOW : return "EXCEPTION_STACK_OVERFLOW";
|
|
159 default : break;
|
|
160 }
|
|
161 return "";
|
|
162 }
|
|
163
|
|
164 /**************************************************************************************************
|
|
165 Wrapper for Win32 GetLastError.
|
|
166 **************************************************************************************************/
|
|
167 string lastError()
|
|
168 {
|
|
169 char[4096] msg;
|
|
170 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, null, GetLastError(), 0, msg.ptr, msg.length, null);
|
|
171 return msg[0..strlen(msg.ptr)];
|
|
172 }
|
|
173
|
|
174 /**************************************************************************************************
|
|
175 Simplified number parser for prefixes.
|
|
176 Returns: number represented by the prefix of name, 0 else
|
|
177 **************************************************************************************************/
|
|
178 uint parseNumber(inout string name)
|
|
179 {
|
|
180 uint res;
|
|
181 int i;
|
|
182 while ( name.length > 0 )
|
|
183 {
|
|
184 if ( !isdigit(name[0]) )
|
|
185 break;
|
|
186 res = res*10+(name[0]-'0');
|
|
187 name = name[1..$];
|
|
188 }
|
|
189 return res;
|
|
190 }
|
|
191
|
|
192 /**************************************************************************************************
|
|
193
|
|
194 **************************************************************************************************/
|
|
195 string typeFromMangled(string mangled)
|
|
196 {
|
|
197 if ( mangled is null || mangled.length < 4 || mangled[0..2] != "_D" || !isdigit(mangled[2]) )
|
|
198 return null;
|
|
199 string type = mangled[1..$];
|
|
200 // skip symbol name
|
|
201 while ( type.length > 1 && type[0] == 'D' && isdigit(type[1]) ) {
|
|
202 type = type[1..$];
|
|
203 uint len = parseNumber(type);
|
|
204 type = type[len..$];
|
|
205 }
|
|
206 return type;
|
|
207 }
|
|
208
|
|
209 /**************************************************************************************************
|
|
210
|
|
211 **************************************************************************************************/
|
|
212 string mangleName(string name)
|
|
213 {
|
|
214 string mangled;
|
|
215 string[] idents = split(name, ".");
|
|
216 foreach ( string id; idents )
|
|
217 mangled ~= .toString(id.length)~id;
|
|
218 return mangled;
|
|
219 }
|
|
220
|
|
221 /**************************************************************************************************
|
|
222
|
|
223 **************************************************************************************************/
|
|
224 string demangleType(string mangled)
|
|
225 {
|
|
226 return demangle("_D0"~mangled);
|
|
227 }
|
|
228
|
|
229 /**************************************************************************************************
|
|
230
|
|
231 **************************************************************************************************/
|
|
232 string demangleNameSkip(inout string mangled)
|
|
233 {
|
|
234 string name;
|
|
235 do {
|
|
236 uint len = parseNumber(mangled);
|
|
237 if ( len <= 0 || len > mangled.length )
|
|
238 return null;
|
|
239 if ( name.length > 0 )
|
|
240 name ~= ".";
|
|
241 name ~= mangled[0..len];
|
|
242 mangled = mangled[len..$];
|
|
243 } while ( mangled.length > 0 );
|
|
244 return name;
|
|
245 }
|
|
246
|
|
247 /**************************************************************************************************
|
|
248
|
|
249 **************************************************************************************************/
|
|
250 string demangleName(string mangled)
|
|
251 {
|
|
252 string name;
|
|
253 if ( mangled.length > 2 && mangled[0..2] == "_D" && isNumeric(mangled[2]) )
|
|
254 mangled = mangled[2..$];
|
|
255 else
|
|
256 return mangled;
|
|
257 do {
|
|
258 uint len = parseNumber(mangled);
|
|
259 while ( len <= 0 && mangled.length > 0 ) {
|
|
260 mangled = mangled[1..$];
|
|
261 len = parseNumber(mangled);
|
|
262 }
|
|
263 if ( len <= 0 || len > mangled.length )
|
|
264 return name;
|
|
265 if ( name.length > 0 )
|
|
266 name ~= ".";
|
|
267 name ~= mangled[0..len];
|
|
268 mangled = mangled[len..$];
|
|
269 } while ( mangled.length > 0 );
|
|
270 return name;
|
|
271 }
|
|
272
|
|
273 /**************************************************************************************************
|
|
274 Wraps win32 stdio functions. Respects io redirection into pipes.
|
|
275 **************************************************************************************************/
|
|
276 class DbgIO
|
|
277 {
|
|
278 static HANDLE ddb_read, ddb_write;
|
|
279 static string buffer;
|
|
280
|
|
281 /**********************************************************************************************
|
|
282
|
|
283 **********************************************************************************************/
|
|
284 static this()
|
|
285 {
|
|
286 ddb_read = GetStdHandle(STD_INPUT_HANDLE);
|
|
287 ddb_write = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
288 }
|
|
289
|
|
290 /**********************************************************************************************
|
|
291
|
|
292 **********************************************************************************************/
|
|
293 static string readln()
|
|
294 {
|
|
295 char[128] buf;
|
|
296 uint read;
|
|
297
|
|
298 int nl_index;
|
|
299 do
|
|
300 {
|
|
301 ReadFile(ddb_read, buf.ptr, buf.length, &read, null);
|
|
302 buffer ~= buf[0..read];
|
|
303 nl_index = find(buffer, '\n');
|
|
304 } while ( nl_index < 0 );
|
|
305 string ret = buffer[0..nl_index];
|
|
306 buffer = buffer[nl_index+1..$];
|
|
307 return ret;
|
|
308 }
|
|
309
|
|
310 /**********************************************************************************************
|
|
311
|
|
312 **********************************************************************************************/
|
|
313 static void print(...)
|
|
314 {
|
|
315 string str;
|
|
316
|
|
317 void putc(dchar c)
|
|
318 {
|
|
319 str ~= c;
|
|
320 }
|
|
321
|
|
322 doFormat(&putc, _arguments, _argptr);
|
|
323 uint written;
|
|
324 WriteFile(ddb_write, str.ptr, str.length, &written, null);
|
|
325 }
|
|
326
|
|
327 /**********************************************************************************************
|
|
328
|
|
329 **********************************************************************************************/
|
|
330 static void println(...)
|
|
331 {
|
|
332 string str;
|
|
333
|
|
334 void putc(dchar c)
|
|
335 {
|
|
336 str ~= c;
|
|
337 }
|
|
338
|
|
339 doFormat(&putc, _arguments, _argptr);
|
|
340 uint written;
|
|
341 str ~= '\n';
|
|
342 WriteFile(ddb_write, str.ptr, str.length, &written, null);
|
|
343 }
|
|
344
|
|
345 /**********************************************************************************************
|
|
346
|
|
347 **********************************************************************************************/
|
|
348 static void write(string str)
|
|
349 {
|
|
350 uint written;
|
|
351 WriteFile(ddb_write, str.ptr, str.length, &written, null);
|
|
352 }
|
|
353
|
|
354 /**********************************************************************************************
|
|
355
|
|
356 **********************************************************************************************/
|
|
357 static void writeln(string str)
|
|
358 {
|
|
359 uint written;
|
|
360 str ~= "\n";
|
|
361 WriteFile(ddb_write, str.ptr, str.length, &written, null);
|
|
362 }
|
|
363 }
|
|
364
|
|
365 /**************************************************************************************************
|
|
366
|
|
367 **************************************************************************************************/
|
|
368 TypeInfo TypeInfoFromMangled(string mangled)
|
|
369 {
|
|
370 TypeInfo res;
|
|
371 TypeInfo* ti = &res;
|
|
372
|
|
373 for ( uint i=0; ti !is null && i < mangled.length; ++i )
|
|
374 {
|
|
375 switch ( mangled[i] )
|
|
376 {
|
|
377 case 'C':
|
|
378 debug DbgIO.println("TypeInfoFromMangled: classinfos not supported, yet");
|
|
379 return null;
|
|
380 case 'P':
|
|
381 TypeInfo_Pointer tip = new TypeInfo_Pointer;
|
|
382 *ti = tip;
|
|
383 ti = &tip.m_next;
|
|
384 break;
|
|
385 case 'G':
|
|
386 TypeInfo_StaticArray tia = new TypeInfo_StaticArray;
|
|
387 *ti = tia;
|
|
388 ti = &tia.value;
|
|
389 break;
|
|
390 case 'A':
|
|
391 switch ( mangled[i+1] )
|
|
392 {
|
|
393 case 'v': *ti = new TypeInfo_Av; ti = null; break;
|
|
394 case 'x':
|
|
395 case 'b': *ti = new TypeInfo_Ab; ti = null; break;
|
|
396 case 'g': *ti = new TypeInfo_Ag; ti = null; break;
|
|
397 case 'h': *ti = new TypeInfo_Ah; ti = null; break;
|
|
398 case 's': *ti = new TypeInfo_As; ti = null; break;
|
|
399 case 't': *ti = new TypeInfo_At; ti = null; break;
|
|
400 case 'i': *ti = new TypeInfo_Ai; ti = null; break;
|
|
401 case 'k': *ti = new TypeInfo_Ak; ti = null; break;
|
|
402 case 'l': *ti = new TypeInfo_Al; ti = null; break;
|
|
403 case 'm': *ti = new TypeInfo_Am; ti = null; break;
|
|
404 case 'f': *ti = new TypeInfo_Af; ti = null; break;
|
|
405 case 'd': *ti = new TypeInfo_Ad; ti = null; break;
|
|
406 case 'e': *ti = new TypeInfo_Ae; ti = null; break;
|
|
407 case 'o': *ti = new TypeInfo_Ao; ti = null; break;
|
|
408 case 'p': *ti = new TypeInfo_Ap; ti = null; break;
|
|
409 case 'j': *ti = new TypeInfo_Aj; ti = null; break;
|
|
410 case 'q': *ti = new TypeInfo_Aq; ti = null; break;
|
|
411 case 'r': *ti = new TypeInfo_Ar; ti = null; break;
|
|
412 case 'c': *ti = new TypeInfo_Ac; ti = null; break;
|
|
413 case 'a': *ti = new TypeInfo_Aa; ti = null; break;
|
|
414 case 'u': *ti = new TypeInfo_Au; ti = null; break;
|
|
415 case 'w': *ti = new TypeInfo_Aw; ti = null; break;
|
|
416 default:
|
|
417 TypeInfo_Array tia = new TypeInfo_Array;
|
|
418 *ti = tia;
|
|
419 ti = &tia.value;
|
|
420 }
|
|
421 break;
|
|
422 case 'v': *ti = new TypeInfo_v; ti = null; break;
|
|
423 case 'x':
|
|
424 case 'b': *ti = new TypeInfo_b; ti = null; break;
|
|
425 case 'g': *ti = new TypeInfo_g; ti = null; break;
|
|
426 case 'h': *ti = new TypeInfo_h; ti = null; break;
|
|
427 case 's': *ti = new TypeInfo_s; ti = null; break;
|
|
428 case 't': *ti = new TypeInfo_t; ti = null; break;
|
|
429 case 'i': *ti = new TypeInfo_i; ti = null; break;
|
|
430 case 'k': *ti = new TypeInfo_k; ti = null; break;
|
|
431 case 'l': *ti = new TypeInfo_l; ti = null; break;
|
|
432 case 'm': *ti = new TypeInfo_m; ti = null; break;
|
|
433 case 'f': *ti = new TypeInfo_f; ti = null; break;
|
|
434 case 'd': *ti = new TypeInfo_d; ti = null; break;
|
|
435 case 'e': *ti = new TypeInfo_e; ti = null; break;
|
|
436 case 'o': *ti = new TypeInfo_o; ti = null; break;
|
|
437 case 'p': *ti = new TypeInfo_p; ti = null; break;
|
|
438 case 'j': *ti = new TypeInfo_j; ti = null; break;
|
|
439 case 'q': *ti = new TypeInfo_q; ti = null; break;
|
|
440 case 'r': *ti = new TypeInfo_r; ti = null; break;
|
|
441 case 'c': *ti = new TypeInfo_c; ti = null; break;
|
|
442 case 'a': *ti = new TypeInfo_a; ti = null; break;
|
|
443 case 'u': *ti = new TypeInfo_u; ti = null; break;
|
|
444 case 'w': *ti = new TypeInfo_w; ti = null; break;
|
|
445 default:
|
|
446 debug DbgIO.println("unknown mangled type "~mangled[i]);
|
|
447 assert(0);
|
|
448 }
|
|
449 }
|
|
450
|
|
451 return res;
|
|
452 }
|
|
453
|
|
454 /**************************************************************************************************
|
|
455
|
|
456 **************************************************************************************************/
|
|
457 class DataReader
|
|
458 {
|
|
459 ubyte[] data;
|
|
460 uint cursor;
|
|
461
|
|
462 /**********************************************************************************************
|
|
463
|
|
464 **********************************************************************************************/
|
|
465 this(ubyte[] d)
|
|
466 {
|
|
467 data = d;
|
|
468 }
|
|
469
|
|
470 /**********************************************************************************************
|
|
471
|
|
472 **********************************************************************************************/
|
|
473 void alignCursor(ubyte num)
|
|
474 {
|
|
475 cursor += (num + cursor) % num;
|
|
476 assert(cursor<=data.length);
|
|
477 }
|
|
478
|
|
479 /**********************************************************************************************
|
|
480
|
|
481 **********************************************************************************************/
|
|
482 bool available()
|
|
483 {
|
|
484 return cursor<data.length;
|
|
485 }
|
|
486
|
|
487 /**********************************************************************************************
|
|
488
|
|
489 **********************************************************************************************/
|
|
490 void seek(uint offset)
|
|
491 {
|
|
492 cursor=offset;
|
|
493 if ( cursor > data.length )
|
|
494 throw new Exception("DataReader.seek beyond end of data offset="~.toString(cursor)~", $="~.toString(data.length));
|
|
495 }
|
|
496
|
|
497 /**********************************************************************************************
|
|
498
|
|
499 **********************************************************************************************/
|
|
500 void relseek(int offset)
|
|
501 {
|
|
502 cursor+=offset;
|
|
503 if ( cursor > data.length )
|
|
504 throw new Exception("DataReader.seek beyond end of data offset="~.toString(cursor)~", $="~.toString(data.length));
|
|
505 }
|
|
506
|
|
507 /**********************************************************************************************
|
|
508
|
|
509 **********************************************************************************************/
|
|
510 void peek(out ubyte val)
|
|
511 {
|
|
512 assert(cursor<data.length);
|
|
513 val = data[cursor];
|
|
514 }
|
|
515
|
|
516 /**********************************************************************************************
|
|
517
|
|
518 **********************************************************************************************/
|
|
519 void read(out ubyte val)
|
|
520 {
|
|
521 assert(cursor<data.length);
|
|
522 val = data[cursor];
|
|
523 ++cursor;
|
|
524 }
|
|
525 void read(out char val) { read(*cast(ubyte*)&val); }
|
|
526
|
|
527 /**********************************************************************************************
|
|
528
|
|
529 **********************************************************************************************/
|
|
530 void read(out ushort val)
|
|
531 {
|
|
532 assert(cursor+1<data.length);
|
|
533 val = (cast(ushort[])(data[cursor..cursor+2]))[0];
|
|
534 cursor+=2;
|
|
535 }
|
|
536 void read(out short val) { read(*cast(ushort*)&val); }
|
|
537
|
|
538 /**********************************************************************************************
|
|
539
|
|
540 **********************************************************************************************/
|
|
541 void read(out uint val)
|
|
542 {
|
|
543 assert(cursor+3<data.length);
|
|
544 val = (cast(uint[])(data[cursor..cursor+4]))[0];
|
|
545 cursor+=4;
|
|
546 }
|
|
547 void read(out int val) { read(*cast(uint*)&val); }
|
|
548 void read(out float val) { read(*cast(uint*)&val); }
|
|
549
|
|
550 /**********************************************************************************************
|
|
551
|
|
552 **********************************************************************************************/
|
|
553 void read(out ulong val)
|
|
554 {
|
|
555 assert(cursor+7<data.length);
|
|
556 val = (cast(ulong[])(data[cursor..cursor+8]))[0];
|
|
557 cursor+=8;
|
|
558 }
|
|
559 void read(out long val) { read(*cast(ulong*)&val); }
|
|
560 void read(out double val) { read(*cast(ulong*)&val); }
|
|
561 void read(out cfloat val) { read(*cast(ulong*)&val); }
|
|
562
|
|
563 /**********************************************************************************************
|
|
564
|
|
565 **********************************************************************************************/
|
|
566 void read(out real val)
|
|
567 {
|
|
568 assert(cursor+9<data.length);
|
|
569 val = (cast(real[])(data[cursor..cursor+10]))[0];
|
|
570 cursor+=10;
|
|
571 }
|
|
572
|
|
573 /**********************************************************************************************
|
|
574
|
|
575 **********************************************************************************************/
|
|
576 void read(out string str)
|
|
577 {
|
|
578 assert(cursor<data.length);
|
|
579 ushort len = data[cursor++];
|
|
580 if ( len >= 0xff && data[cursor] == 0 ) {
|
|
581 ++cursor;
|
|
582 read(len);
|
|
583 }
|
|
584
|
|
585 assert(cursor+len<=data.length, "dr cursor="~.toString(cursor)~" len="~.toString(len));
|
|
586 str = (cast(string)data)[cursor..cursor+len];
|
|
587 cursor+=len;
|
|
588 }
|
|
589
|
|
590 /**********************************************************************************************
|
|
591
|
|
592 **********************************************************************************************/
|
|
593 void readA(T)(out T[] array, uint length)
|
|
594 {
|
|
595 uint size = length*T.sizeof;
|
|
596 assert(cursor<=data.length-size);
|
|
597 array = cast(T[])(data[cursor..cursor+size]);
|
|
598 cursor+=size;
|
|
599 }
|
|
600 }
|
|
601
|
|
602 /**************************************************************************************************
|
|
603
|
|
604 **************************************************************************************************/
|
|
605 string getFullPath(string filename)
|
|
606 {
|
|
607 char[] fullpath;
|
|
608 char* filepart;
|
|
609 fullpath.length = 4096;
|
|
610 int len = GetFullPathName(
|
|
611 toStringz(filename),
|
|
612 fullpath.length,
|
|
613 fullpath.ptr,
|
|
614 &filepart
|
|
615 );
|
|
616 if ( len <= 0 )
|
|
617 return null;
|
|
618 fullpath.length = len;
|
|
619
|
|
620 char[] longfullpath;
|
|
621 longfullpath.length = 4096;
|
|
622 len = GetLongPathName(
|
|
623 toStringz(fullpath),
|
|
624 longfullpath.ptr,
|
|
625 longfullpath.length
|
|
626 );
|
|
627 longfullpath.length = len;
|
|
628 return longfullpath;
|
|
629 }
|
|
630
|
|
631 /**************************************************************************************************
|
|
632
|
|
633 **************************************************************************************************/
|
|
634 struct DbgTimer
|
|
635 {
|
|
636 d_time time;
|
|
637
|
|
638 void start()
|
|
639 {
|
|
640 time = getUTCtime;
|
|
641 }
|
|
642
|
|
643 string finish()
|
|
644 {
|
|
645 time = getUTCtime - time;
|
|
646 return format("%d'%03d", time / TicksPerSecond, time % TicksPerSecond);
|
|
647 }
|
|
648 }
|