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 APDProperties
|
|
7 {
|
|
8 parser_type = lr
|
|
9 }
|
|
10
|
|
11 APDDeclaration
|
|
12 {
|
|
13 module expression.expression_apd;
|
|
14
|
|
15 import codeview.decl;
|
|
16 import codeview.codeview;
|
|
17 import expression.evaluationcontext;
|
|
18 import expression.datahandler;
|
|
19 import util;
|
|
20
|
|
21 //import internal.aaA;
|
|
22
|
|
23 struct aaA
|
|
24 {
|
|
25 aaA *left;
|
|
26 aaA *right;
|
|
27 hash_t hash;
|
|
28 /* key */
|
|
29 /* value */
|
|
30 }
|
|
31
|
|
32 struct BB
|
|
33 {
|
|
34 aaA*[] b;
|
|
35 size_t nodes; // total number of aaA nodes
|
|
36 }
|
|
37
|
|
38 import std.demangle;
|
|
39 import std.stdio;
|
|
40
|
|
41 import win32.winnt;
|
|
42
|
|
43 /**********************************************************************************************
|
|
44
|
|
45 **********************************************************************************************/
|
|
46 bool castArrayIndex(ubyte[] data, string type, out size_t index)
|
|
47 {
|
|
48 assert(type.length>0);
|
|
49 switch ( type[0] )
|
|
50 {
|
|
51 case 'a':
|
|
52 if ( *cast(char*)data.ptr < 0 )
|
|
53 throw new EvaluationException("Cannot access array with negative index");
|
|
54 case 'h':
|
|
55 index = *cast(ubyte*)data.ptr;
|
|
56 return true;
|
|
57 case 's':
|
|
58 if ( *cast(short*)data.ptr < 0 )
|
|
59 throw new EvaluationException("Cannot access array with negative index");
|
|
60 case 't':
|
|
61 index = *cast(ushort*)data.ptr;
|
|
62 return true;
|
|
63 case 'i':
|
|
64 if ( *cast(int*)data.ptr < 0 )
|
|
65 throw new EvaluationException("Cannot access array with negative index");
|
|
66 case 'k':
|
|
67 index = *cast(uint*)data.ptr;
|
|
68 return true;
|
|
69 case 'l':
|
|
70 if ( *cast(long*)data.ptr < 0 )
|
|
71 throw new EvaluationException("Cannot access array with negative index");
|
|
72 case 'm':
|
|
73 index = cast(size_t)*cast(ulong*)data.ptr;
|
|
74 return true;
|
|
75 default:
|
|
76 }
|
|
77 return false;
|
|
78 }
|
|
79
|
|
80 /**********************************************************************************************
|
|
81
|
|
82 **********************************************************************************************/
|
|
83 // debug = parser;
|
|
84 unittest
|
|
85 {
|
|
86 bool test(string expr)
|
|
87 {
|
|
88 SyntaxTree* root;
|
|
89 bool success;
|
|
90 try success = parse(expr, root);
|
|
91 catch ( ParserException e ) {
|
|
92 debug(parser) writefln("%s", e.toString);
|
|
93 return false;
|
|
94 }
|
|
95 return success;
|
|
96 }
|
|
97
|
|
98 assert(test("a.bc"));
|
|
99 assert(test("bc[def..ghij]"));
|
|
100 assert(!test("\"a\\\"\\\u2f85qwe '\""));
|
|
101 assert(test("a.bc[def..ghij].klmno.pqrstu[0..'a'][\"a\\\"\\u2f85qwe '\"]"));
|
|
102 assert(!test("a.bc.[def..ghij]"));
|
|
103 assert(!test("[def..ghij]"));
|
|
104 assert(!test("a."));
|
|
105 assert(test("asdf[0][i].qwer"));
|
|
106 assert(test("cast(uint)asdf"));
|
|
107 assert(test("(cast(mystruct)asdf).qwer"));
|
|
108 assert(test("(cast(string[])asdf)[0][2..13]"));
|
|
109 assert(test("(cast(char[string])asdf)[\"qwer\"]"));
|
|
110 assert(!test("(cast(mystruct)asdf).(cast(char[][])qwer)[0]"));
|
|
111 assert(test("cast(float)asdf.qwer"));
|
|
112 assert(!test("cast.qwer"));
|
|
113 assert(!test("cast(uint).qwer"));
|
|
114 assert(!test("cast(asdf.qwer).qwer"));
|
|
115 assert(test("(cast(string)mystruct.tzui)[0..4]"));
|
|
116 assert(test("cast(Vec!(float,3))mystruct"));
|
|
117 assert(test("cast(Vec!(float,3,\"asdf\",Vec!(float)))mystruct"));
|
|
118 assert(test("vertices[inds[10193]].y"));
|
|
119 assert(test("*cast(uint*)#eax"));
|
|
120 }
|
|
121
|
|
122 }
|
|
123
|
|
124 Whitespace
|
|
125 {
|
|
126 regexp("[\\t\\n\\r ]+");
|
|
127 }
|
|
128
|
|
129
|
|
130 /**************************************************************************************************
|
|
131 Expressions
|
|
132 **************************************************************************************************/
|
|
133 Expr(EvaluationContext ctx, out SymbolData symdata)
|
|
134 {
|
|
135 Deref Cast DotChain
|
|
136 {
|
|
137 DotChain(ctx, symdata);
|
|
138 Cast(ctx, symdata);
|
|
139 Deref(ctx, symdata);
|
|
140 }
|
|
141 }
|
|
142
|
|
143 Deref(EvaluationContext ctx, ref SymbolData symdata)
|
|
144 {
|
|
145 "*" Deref
|
|
146 {
|
|
147 if ( symdata is null )
|
|
148 throw new EvaluationException("Invalid data for dereferencing");
|
|
149 if ( symdata.type[0] != 'P' )
|
|
150 throw new EvaluationException("Cannot dereference non-pointer of type "~demangleType(symdata.type));
|
|
151 symdata.type = symdata.type[1..$];
|
|
152 assert(symdata.type.length>0);
|
|
153 ubyte[] data = symdata.getData(ctx);
|
|
154 if ( data.length != size_t.sizeof ) {
|
|
155 throw new EvaluationException("Invalid pointer data size = "~.toString(data.length));
|
|
156 }
|
|
157 symdata.ptr = (cast(size_t[])data)[0];
|
|
158 symdata.len = ctx.codeView.sizeofMangled(symdata.type);
|
|
159 symdata.defered_load = true;
|
|
160
|
|
161 Deref(ctx, symdata);
|
|
162 }
|
|
163
|
|
164 epsilon;
|
|
165 }
|
|
166
|
|
167 DotChain(EvaluationContext ctx, out SymbolData symdata)
|
|
168 {
|
|
169 Register
|
|
170 {
|
|
171 Register(ctx, symdata);
|
|
172 }
|
|
173
|
|
174 "(" !("(%d) Expression expected after (")
|
|
175 Expr !("(%d) ) expected")
|
|
176 ")"
|
|
177 RefExpr
|
|
178 {
|
|
179 Expr(ctx, symdata);
|
|
180 RefExpr(ctx, null, null, "", symdata);
|
|
181 }
|
|
182
|
|
183 Ident
|
|
184 RefExpr
|
|
185 {
|
|
186 string id;
|
|
187 Ident(id);
|
|
188
|
|
189 NamedSymbol[] symbols;
|
|
190 NamedSymbol symbol = ctx.findSymbol(id, symbols);
|
|
191 if ( symbol !is null )
|
|
192 symdata = ctx.loadSymbolData(symbol);
|
|
193 else
|
|
194 debug DbgIO.println("symbol %s not found", id);
|
|
195 RefExpr(ctx, symbol, symbols, id, symdata);
|
|
196 }
|
|
197
|
|
198 Lit
|
|
199 { Lit(symdata); }
|
|
200 }
|
|
201
|
|
202 RefExpr(EvaluationContext ctx, NamedSymbol symbol, NamedSymbol[] symbols, string prefix, ref SymbolData symdata)
|
|
203 {
|
|
204 //-------------------------------------------------------------------------
|
|
205 // . Operator
|
|
206 //-------------------------------------------------------------------------
|
|
207 "." Ident RefExpr
|
|
208 {
|
|
209 string id;
|
|
210 Ident(id);
|
|
211 prefix ~= "."~id;
|
|
212
|
|
213 if ( symdata is null )
|
|
214 {
|
|
215 symbol = ctx.findSymbol(prefix, symbols);
|
|
216 if ( symbol !is null )
|
|
217 symdata = ctx.loadSymbolData(symbol);
|
|
218 }
|
|
219 else
|
|
220 {
|
|
221 switch ( symdata.type[0] )
|
|
222 {
|
|
223 //---------------------------------------------------------------------------------
|
|
224 // primitive types
|
|
225 case 'v': case 'b': case 'x': case 'g': case 'h': case 's': case 't': case 'i': case 'k': case 'l': case 'm': case 'f':
|
|
226 case 'd': case 'e': case 'o': case 'p': case 'j': case 'q': case 'r': case 'c': case 'a': case 'u': case 'w':
|
|
227 throw new EvaluationException(
|
|
228 "Type mismatch - unexpected . operator in expression of type "~demangleType(symdata.type)
|
|
229 );
|
|
230 //---------------------------------------------------------------------------------
|
|
231 // array properties
|
|
232 case 'G':
|
|
233 switch ( id )
|
|
234 {
|
|
235 case "length":
|
|
236 symdata.type = symdata.type[1..$];
|
|
237 size_t len = parseNumber(symdata.type);
|
|
238 symdata.type = "k";
|
|
239 symdata.data = (cast(ubyte*)&len)[0..size_t.sizeof].dup;
|
|
240 symdata.defered_load = false;
|
|
241 break;
|
|
242 case "ptr":
|
|
243 // TODO: can this always be guaranteed?
|
|
244 assert(symdata.defered_load);
|
|
245 size_t ptr = symdata.ptr;
|
|
246 symdata.data = (cast(ubyte*)&ptr)[0..size_t.sizeof];
|
|
247 symdata.defered_load = false;
|
|
248 symdata.type = symdata.type[1..$];
|
|
249 parseNumber(symdata.type);
|
|
250 symdata.type = "P"~symdata.type;
|
|
251 break;
|
|
252 default:
|
|
253 throw new EvaluationException(
|
|
254 "Type mismatch - invalid property "~id~" after expression of type "~demangleType(symdata.type)
|
|
255 );
|
|
256 }
|
|
257 break;
|
|
258 case 'A':
|
|
259 switch ( id )
|
|
260 {
|
|
261 case "length":
|
|
262 ubyte[] data = symdata.getData(ctx);
|
|
263 symdata.type = "k";
|
|
264 size_t len = (cast(size_t[])data)[0];
|
|
265 symdata.data = (cast(ubyte*)&len)[0..size_t.sizeof].dup;
|
|
266 symdata.defered_load = false;
|
|
267 break;
|
|
268 case "ptr":
|
|
269 ubyte[] data = symdata.getData(ctx);
|
|
270 symdata.type = "k";
|
|
271 size_t len = (cast(size_t[])data)[1];
|
|
272 symdata.data = (cast(ubyte*)&len)[0..size_t.sizeof].dup;
|
|
273 symdata.defered_load = false;
|
|
274 break;
|
|
275 default:
|
|
276 throw new EvaluationException(
|
|
277 "Type mismatch - invalid property "~id~" after expression of type "~demangleType(symdata.type)
|
|
278 );
|
|
279 }
|
|
280 break;
|
|
281 case 'H':
|
|
282 switch ( id )
|
|
283 {
|
|
284 case "length":
|
|
285 ubyte[] data = symdata.getData(ctx);
|
|
286 symdata.ptr = *cast(size_t*)data.ptr;
|
|
287 symdata.len = BB.sizeof;
|
|
288 symdata.defered_load = true;
|
|
289 data = symdata.getData(ctx);
|
|
290 BB* bb = cast(BB*)data.ptr;
|
|
291
|
|
292 symdata.type = "k";
|
|
293 symdata.data = (cast(ubyte*)&bb.nodes)[0..size_t.sizeof].dup;
|
|
294 symdata.defered_load = false;
|
|
295 break;
|
|
296 default:
|
|
297 throw new EvaluationException(
|
|
298 "Type mismatch - invalid property "~id~" after expression of type "~demangleType(symdata.type)
|
|
299 );
|
|
300 }
|
|
301 break;
|
|
302 //---------------------------------------------------------------------------------
|
|
303 // references to structs/classes
|
|
304 case 'P':
|
|
305 symdata.type = symdata.type[1..$];
|
|
306 if ( symdata.type[0] != 'C' && symdata.type[0] != 'S' )
|
|
307 {
|
|
308 throw new EvaluationException(
|
|
309 "Type mismatch - unexpected . operator after expression of type "~demangleType("P"~symdata.type)
|
|
310 );
|
|
311 }
|
|
312
|
|
313 ubyte[] data = symdata.getData(ctx);
|
|
314 if ( symdata.data.length <= 0 )
|
|
315 throw new EvaluationException("Subexpression evaluated to empty data");
|
|
316 symdata.ptr = (cast(uint[])data)[0];
|
|
317 symdata.len = ctx.codeView.sizeofMangled(symdata.type);
|
|
318 symdata.defered_load = true;
|
|
319
|
|
320 if ( symdata.ptr == 0 )
|
|
321 throw new EvaluationException("pointer is null");
|
|
322 // fall through to struct handling
|
|
323
|
|
324 //---------------------------------------------------------------------------------
|
|
325 // classes/structs
|
|
326 case 'C':
|
|
327 case 'S':
|
|
328 symdata.type = symdata.type[1..$];
|
|
329 string scu_name = demangleNameSkip(symdata.type);
|
|
330 assert ( symdata.type.length <= 0 );
|
|
331 if ( (scu_name in ctx.codeView.UDTsByName) is null )
|
|
332 throw new EvaluationException("unknown type \""~scu_name~"\"");
|
|
333
|
|
334 LeafClassStruc lcs = cast(LeafClassStruc)ctx.codeView.UDTsByName[scu_name];
|
|
335 LeafUnion lu;
|
|
336 LeafFieldList lfl;
|
|
337 uint type_length;
|
|
338
|
|
339 if ( lcs !is null && lcs.field-0x1000 < ctx.codeView.type_strings.length ) {
|
|
340 Leaf[] fields = ctx.codeView.type_strings[lcs.field-0x1000];
|
|
341 lfl = cast(LeafFieldList)fields[0];
|
|
342 type_length = lcs.length.getUint();
|
|
343 }
|
|
344 else
|
|
345 {
|
|
346 lu = cast(LeafUnion)ctx.codeView.UDTsByName[scu_name];
|
|
347 if ( lu !is null && lu.field-0x1000 < ctx.codeView.type_strings.length ) {
|
|
348 Leaf[] fields = ctx.codeView.type_strings[lu.field-0x1000];
|
|
349 lfl = cast(LeafFieldList)fields[0];
|
|
350 type_length = lu.length.getUint();
|
|
351 }
|
|
352 }
|
|
353 if ( lfl is null )
|
|
354 throw new EvaluationException("invalid struct/class debug symbols");
|
|
355
|
|
356 size_t size,
|
|
357 offset;
|
|
358 if ( !ctx.findMember(id, lfl, size, offset, symdata.type) )
|
|
359 throw new EvaluationException("struct \""~scu_name~"\" has no element \""~id~"\"");
|
|
360 assert ( symdata.type.length > 0 );
|
|
361 debug(eval) DbgIO.println("member: type=%s size=%d offset=%d", symdata.type, size, offset);
|
|
362
|
|
363 if ( !symdata.loadByteSlice(offset, offset+size) )
|
|
364 throw new EvaluationException("invalid offset into struct for member \""~id~"\"");
|
|
365 break;
|
|
366 //---------------------------------------------------------------------------------
|
|
367 // unsupported
|
|
368 default:
|
|
369 throw new EvaluationException("yet unsupported type "~demangleType(symdata.type)~" in expression");
|
|
370 }
|
|
371 }
|
|
372
|
|
373 RefExpr(ctx, symbol, symbols, prefix, symdata);
|
|
374 }
|
|
375
|
|
376 //-------------------------------------------------------------------------
|
|
377 // [] Operator
|
|
378 //-------------------------------------------------------------------------
|
|
379 "[" !("(%d) Arguments expected after [")
|
|
380 Args !("(%d) ] expected")
|
|
381 "]"
|
|
382 RefExpr
|
|
383 {
|
|
384 if ( symdata is null )
|
|
385 throw new EvaluationException("Unknown symbol "~prefix);
|
|
386
|
|
387 SymbolData argdata;
|
|
388 size_t start, end;
|
|
389 Args(ctx, argdata, start, end);
|
|
390
|
|
391 bool isIndex = argdata is null;
|
|
392 if ( !isIndex && castArrayIndex(argdata.getData(ctx), argdata.type, start) ) {
|
|
393 isIndex = true;
|
|
394 end = start+1;
|
|
395 }
|
|
396
|
|
397 switch ( symdata.type[0] )
|
|
398 {
|
|
399 //---------------------------------------------------------------------------------
|
|
400 // primitive types
|
|
401 case 'v': case 'b': case 'x': case 'g': case 'h': case 's': case 't': case 'i': case 'k': case 'l': case 'm': case 'f':
|
|
402 case 'd': case 'e': case 'o': case 'p': case 'j': case 'q': case 'r': case 'c': case 'a': case 'u': case 'w':
|
|
403 // pointers, classes/structs
|
|
404 case 'P': case 'C': case 'S':
|
|
405 throw new EvaluationException(
|
|
406 "Type mismatch - unexpected [] operator after expression of type "~demangleType(symdata.type)
|
|
407 );
|
|
408 //---------------------------------------------------------------------------------
|
|
409 // static arrays
|
|
410 case 'G':
|
|
411 if ( !isIndex )
|
|
412 throw new EvaluationException("Cannot access static array with index type "~demangleType(argdata.type));
|
|
413
|
|
414 symdata.type = symdata.type[1..$];
|
|
415 size_t count = parseNumber(symdata.type);
|
|
416 assert(symdata.type.length>0);
|
|
417
|
|
418 if ( end-start > 1 )
|
|
419 {
|
|
420 if ( end > count )
|
|
421 throw new EvaluationException("Array index out of bounds: "~.toString(start)~".."~.toString(end)~" ($="~.toString(count)~")");
|
|
422 size_t size = ctx.codeView.sizeofMangled(symdata.type);
|
|
423 if ( symdata.defered_load ) {
|
|
424 symdata.ptr += start * size;
|
|
425 symdata.len = (end-start) * size;
|
|
426 }
|
|
427 else
|
|
428 symdata.data = symdata.data[start*size .. end*size];
|
|
429 symdata.type = "G"~.toString(end-start)~symdata.type;
|
|
430 }
|
|
431 else
|
|
432 {
|
|
433 if ( !symdata.loadElementSlice(start, end, ctx.codeView) )
|
|
434 throw new EvaluationException("Array index out of bounds: "~.toString(start)~".."~.toString(end)~" ($="~.toString(count)~")");
|
|
435 }
|
|
436 break;
|
|
437 //---------------------------------------------------------------------------------
|
|
438 // dynamic arrays
|
|
439 case 'A':
|
|
440 if ( !isIndex )
|
|
441 throw new EvaluationException("Cannot access dynamic array with index type "~demangleType(argdata.type));
|
|
442
|
|
443 ubyte[] data = symdata.getData(ctx);
|
|
444 if ( data.length < 8 )
|
|
445 throw new EvaluationException("Subexpression evaluated to empty data");
|
|
446
|
|
447 if ( end-start > 1 )
|
|
448 {
|
|
449 if ( end > (cast(size_t[])data)[0] )
|
|
450 throw new EvaluationException("Array index out of bounds: "~.toString(start)~".."~.toString(end)~" ($="~.toString(symdata.len)~")");
|
|
451 size_t size = ctx.codeView.sizeofMangled(symdata.type[1..$]);
|
|
452 (cast(size_t[])data)[1] += start * size,
|
|
453 (cast(size_t[])data)[0] = end-start;
|
|
454 }
|
|
455 else
|
|
456 {
|
|
457 symdata.type = symdata.type[1..$];
|
|
458 assert(symdata.type.length>0);
|
|
459 symdata.ptr = (cast(size_t[])data)[1];
|
|
460 symdata.len = (cast(size_t[])data)[0] * ctx.codeView.sizeofMangled(symdata.type);
|
|
461 symdata.defered_load = true;
|
|
462
|
|
463 if ( !symdata.loadElementSlice(start, end, ctx.codeView) )
|
|
464 throw new EvaluationException("Array index out of bounds: "~.toString(start)~".."~.toString(end)~" ($="~.toString(symdata.len)~")");
|
|
465 }
|
|
466 break;
|
|
467 //---------------------------------------------------------------------------------
|
|
468 // associative arrays
|
|
469 case 'H':
|
|
470 int i;
|
|
471 for ( i = 1; i < symdata.type.length && std.string.find(lowercase, symdata.type[i]) < 0; ++i ) {}
|
|
472 string key_type = symdata.type[1..i+1],
|
|
473 val_type = symdata.type[i+1..$];
|
|
474 size_t val_tsize = ctx.codeView.sizeofMangled(val_type);
|
|
475 TypeInfo key_ti = TypeInfoFromMangled(key_type);
|
|
476
|
|
477 aaA* loadaaA(void* ptr)
|
|
478 {
|
|
479 if ( ptr is null )
|
|
480 return null;
|
|
481 ubyte[] data;
|
|
482 data.length = aaA.sizeof+key_ti.tsize+val_tsize;
|
|
483 if ( data.length != ctx.process.readProcessMemory(cast(uint)ptr, data.ptr, data.length) )
|
|
484 return null;
|
|
485 aaA* a = cast(aaA*)data.ptr;
|
|
486 if ( std.string.find(lowercase, key_type[0]) < 0 )
|
|
487 switch ( key_type[0] )
|
|
488 {
|
|
489 case 'A':
|
|
490 ubyte[] tmp = *cast(ubyte[]*)(a+1);
|
|
491 if ( tmp.length > ctx.process.MEMCHECK_MIN && ctx.process.isInvalidMem(cast(size_t)tmp.ptr, tmp.length) )
|
|
492 return null;
|
|
493 data = new ubyte[tmp.length];
|
|
494 if ( data.length != ctx.process.readProcessMemory(cast(size_t)tmp.ptr, data.ptr, data.length) )
|
|
495 return null;
|
|
496 *cast(ubyte[]*)(a+1) = data;
|
|
497 break;
|
|
498 case 'P':
|
|
499 break;
|
|
500 default:
|
|
501 throw new EvaluationException("only basic, pointer and array key types are supported, yet");
|
|
502 }
|
|
503 return a;
|
|
504 }
|
|
505
|
|
506 ubyte[] findKey(size_t ptr, hash_t hash, ubyte[] key_data)
|
|
507 {
|
|
508 ubyte[] data;
|
|
509 data.length = BB.sizeof;
|
|
510 if ( data.length != ctx.process.readProcessMemory(ptr, data.ptr, data.length) )
|
|
511 return null;
|
|
512 BB* bb = cast(BB*)data.ptr;
|
|
513 size_t blen = bb.b.length*size_t.sizeof;
|
|
514 debug(eval) DbgIO.println("%d nodes, bb.b.length=%d", bb.nodes, bb.b.length);
|
|
515
|
|
516 if ( blen > ctx.process.MEMCHECK_MIN && ctx.process.isInvalidMem(cast(size_t)bb.b.ptr, blen) )
|
|
517 return null;
|
|
518 data = new ubyte[blen];
|
|
519 if ( data.length != ctx.process.readProcessMemory(cast(uint)bb.b.ptr, data.ptr, data.length) )
|
|
520 return null;
|
|
521 bb.b = cast(aaA*[])data;
|
|
522
|
|
523 uint i = hash % bb.b.length;
|
|
524 debug(eval) DbgIO.println("start index=%d", i);
|
|
525 aaA* a = loadaaA(bb.b[i]);
|
|
526 while ( a !is null )
|
|
527 {
|
|
528 if ( hash == a.hash )
|
|
529 {
|
|
530 debug(eval) DbgIO.println("equal 0x%x", a.hash);
|
|
531 auto cmp = key_ti.compare(key_data.ptr, a+1);
|
|
532 debug(eval) DbgIO.println("%s: %d == %d -> %d", key_ti, *cast(uint*)key_data.ptr, *cast(uint*)(a+1), cmp);
|
|
533 if ( cmp == 0 )
|
|
534 return ((cast(ubyte*)(a+1))+key_ti.tsize)[0 .. val_tsize];
|
|
535 a = cmp < 0 ? loadaaA(a.left) : loadaaA(a.right);
|
|
536 }
|
|
537 else {
|
|
538 debug(eval) DbgIO.println("not equal 0x%x", a.hash);
|
|
539 a = hash < a.hash ? loadaaA(a.left) : loadaaA(a.right);
|
|
540 }
|
|
541 }
|
|
542 return null;
|
|
543 }
|
|
544
|
|
545 if ( key_type != argdata.type )
|
|
546 throw new EvaluationException("Invalid key type for associative array. Expected "~demangleType(key_type)~" found "~demangleType(argdata.type));
|
|
547 TypeInfo ti = TypeInfoFromMangled(argdata.type);
|
|
548 hash_t index_hash = ti.getHash(argdata.data.ptr);
|
|
549
|
|
550 debug(eval) DbgIO.println("searching, hash=0x%x", index_hash);
|
|
551 ubyte[] data = symdata.getData(ctx);
|
|
552 symdata.data = findKey((cast(size_t[])data)[0], index_hash, argdata.getData(ctx));
|
|
553 symdata.type = val_type;
|
|
554 break;
|
|
555 //---------------------------------------------------------------------------------
|
|
556 // unsupported
|
|
557 default:
|
|
558 throw new EvaluationException("yet unsupported type "~demangleType(symdata.type)~" in expression");
|
|
559 }
|
|
560
|
|
561 RefExpr(ctx, symbol, null, null, symdata);
|
|
562 }
|
|
563
|
|
564 //-------------------------------------------------------------------------
|
|
565 // end of refexpr
|
|
566 //-------------------------------------------------------------------------
|
|
567 epsilon
|
|
568 {
|
|
569 if ( symdata is null )
|
|
570 throw new EvaluationException("Unknown symbol "~prefix);
|
|
571 }
|
|
572 }
|
|
573
|
|
574 Args(EvaluationContext ctx, out SymbolData argdata, out size_t start, out size_t end)
|
|
575 {
|
|
576 Expr
|
|
577 ".." !("(%d) Second slice argument expected")
|
|
578 Expr=Expr2
|
|
579 {
|
|
580 SymbolData arg1, arg2;
|
|
581 Expr(ctx, arg1);
|
|
582 Expr2(ctx, arg2);
|
|
583
|
|
584 bool isIndex = castArrayIndex(arg1.getData(ctx), arg1.type, start);
|
|
585 isIndex = isIndex && castArrayIndex(arg2.getData(ctx), arg2.type, end);
|
|
586 if ( !isIndex )
|
|
587 throw new EvaluationException("Slices may only have integer indeces, not "~demangleType(arg1.type)~".."~demangleType(arg2.type));
|
|
588 }
|
|
589
|
|
590 Expr
|
|
591 { Expr(ctx, argdata); }
|
|
592 }
|
|
593
|
|
594
|
|
595 /**************************************************************************************************
|
|
596 Registers
|
|
597 **************************************************************************************************/
|
|
598 Register(EvaluationContext ctx, out SymbolData symdata)
|
|
599 {
|
|
600 RegName
|
|
601 {
|
|
602 string name;
|
|
603 ubyte width;
|
|
604 RegName(name, width);
|
|
605
|
|
606 CONTEXT threadCtx;
|
|
607 uint context_flags;
|
|
608 context_flags |= CONTEXT_FULL;
|
|
609 context_flags |= CONTEXT_FLOATING_POINT;
|
|
610 context_flags |= CONTEXT_EXTENDED_REGISTERS;
|
|
611 if ( !ctx.getContext(threadCtx, context_flags) )
|
|
612 throw new EvaluationException("Couldn't get main thread's context");
|
|
613
|
|
614 ubyte* ptr;
|
|
615 switch ( name[1..$] )
|
|
616 {
|
|
617 case "ax":
|
|
618 case "eax":
|
|
619 case "al": ptr = cast(ubyte*)&threadCtx.Eax; break;
|
|
620 case "ah": ptr = (cast(ubyte*)&threadCtx.Eax)+1; break;
|
|
621 case "bx":
|
|
622 case "ebx":
|
|
623 case "bl": ptr = cast(ubyte*)&threadCtx.Ebx; break;
|
|
624 case "bh": ptr = (cast(ubyte*)&threadCtx.Ebx)+1; break;
|
|
625 case "cx":
|
|
626 case "ecx":
|
|
627 case "cl": ptr = cast(ubyte*)&threadCtx.Ecx; break;
|
|
628 case "ch": ptr = (cast(ubyte*)&threadCtx.Ecx)+1; break;
|
|
629 case "dx":
|
|
630 case "edx":
|
|
631 case "dl": ptr = cast(ubyte*)&threadCtx.Edx; break;
|
|
632 case "dh": ptr = (cast(ubyte*)&threadCtx.Edx)+1; break;
|
|
633 case "edi":
|
|
634 case "di": ptr = cast(ubyte*)&threadCtx.Edi; break;
|
|
635 case "esi":
|
|
636 case "si": ptr = cast(ubyte*)&threadCtx.Esi; break;
|
|
637 case "ebp":
|
|
638 case "bp": ptr = cast(ubyte*)&threadCtx.Ebp; break;
|
|
639 case "esp":
|
|
640 case "sp": ptr = cast(ubyte*)&threadCtx.Esp; break;
|
|
641 case "eip": ptr = cast(ubyte*)&threadCtx.Eip; break;
|
|
642 case "efl": ptr = cast(ubyte*)&threadCtx.EFlags; break;
|
|
643 case "cs": ptr = cast(ubyte*)&threadCtx.SegCs; break;
|
|
644 case "ds": ptr = cast(ubyte*)&threadCtx.SegDs; break;
|
|
645 case "es": ptr = cast(ubyte*)&threadCtx.SegEs; break;
|
|
646 case "fs": ptr = cast(ubyte*)&threadCtx.SegFs; break;
|
|
647 case "gs": ptr = cast(ubyte*)&threadCtx.SegGs; break;
|
|
648 default:
|
|
649 int i = name[$-1]-'0';
|
|
650 if ( name[0..2] == "st" )
|
|
651 ptr = cast(ubyte*)&((cast(real[])threadCtx.FloatSave.RegisterArea)[i]);
|
|
652 else if ( name[0..2] == "mm" )
|
|
653 ptr = cast(ubyte*)&((cast(long[])threadCtx.ExtendedRegisters)[4+i*2]);
|
|
654 else if ( name[0..3] == "xmm" )
|
|
655 ptr = cast(ubyte*)&((cast(long[])threadCtx.ExtendedRegisters)[20+i*2]);
|
|
656 else
|
|
657 assert(0);
|
|
658 }
|
|
659
|
|
660 symdata = new SymbolData;
|
|
661 switch ( width )
|
|
662 {
|
|
663 case 8:
|
|
664 symdata.type = "h";
|
|
665 symdata.data = ptr[0..1].dup;
|
|
666 break;
|
|
667 case 16:
|
|
668 symdata.type = "t";
|
|
669 symdata.data = ptr[0..2].dup;
|
|
670 break;
|
|
671 case 32:
|
|
672 symdata.type = "k";
|
|
673 symdata.data = ptr[0..4].dup;
|
|
674 break;
|
|
675 case 64:
|
|
676 symdata.type = "m";
|
|
677 symdata.data = ptr[0..8].dup;
|
|
678 break;
|
|
679 case 80:
|
|
680 symdata.type = "e";
|
|
681 symdata.data = ptr[0..10].dup;
|
|
682 break;
|
|
683 case 128:
|
|
684 symdata.type = "G4k";
|
|
685 symdata.data = ptr[0..16].dup;
|
|
686 break;
|
|
687 default:
|
|
688 assert(0, "unhandled register width "~.toString(width));
|
|
689 }
|
|
690 }
|
|
691 }
|
|
692
|
|
693 RegName(out string name, out ubyte width)
|
|
694 {
|
|
695 regexp("#(e[abcd]x|e[ds]i|e[bs]p|eip|efl)")
|
|
696 { name = _ST_match; width = 32; }
|
|
697
|
|
698 regexp("#([abcd]x|[ds]i|[bs]p|(cdefgs)s)")
|
|
699 { name = _ST_match; width = 16; }
|
|
700
|
|
701 regexp("#[abcd][hl]")
|
|
702 { name = _ST_match; width = 8; }
|
|
703
|
|
704 regexp("#st[0-7]")
|
|
705 { name = _ST_match; width = 8*real.sizeof; }
|
|
706
|
|
707 regexp("#mm[0-7]")
|
|
708 { name = _ST_match; width = 64; }
|
|
709
|
|
710 regexp("#xmm[0-7]")
|
|
711 { name = _ST_match; width = 128; }
|
|
712 }
|
|
713
|
|
714
|
|
715 /**************************************************************************************************
|
|
716 Casts
|
|
717 **************************************************************************************************/
|
|
718 Cast(EvaluationContext ctx, ref SymbolData symdata)
|
|
719 {
|
|
720 "cast" !("(%d) ( expected")
|
|
721 "(" !("(%d) Type expected")
|
|
722 Type !("(%d) ) expected")
|
|
723 ")"
|
|
724 {
|
|
725 symdata.type = "";
|
|
726 Type(ctx, symdata.type);
|
|
727 if ( symdata.type.length <= 0 )
|
|
728 throw new EvaluationException("Unknown type in cast");
|
|
729 }
|
|
730
|
|
731 epsilon;
|
|
732 }
|
|
733
|
|
734 Type(EvaluationContext ctx, ref string mangled)
|
|
735 {
|
|
736 BaseType QuantList
|
|
737 {
|
|
738 string unmangled;
|
|
739 BaseType(ctx, unmangled);
|
|
740
|
|
741 switch ( unmangled )
|
|
742 {
|
|
743 case "void": mangled = "v"; break;
|
|
744 case "bool": mangled = "b"; break;
|
|
745 case "byte": mangled = "g"; break;
|
|
746 case "ubyte": mangled = "h"; break;
|
|
747 case "char": mangled = "a"; break;
|
|
748 case "wchar": mangled = "u"; break;
|
|
749 case "dchar": mangled = "w"; break;
|
|
750 case "short": mangled = "s"; break;
|
|
751 case "ushort": mangled = "t"; break;
|
|
752 case "int": mangled = "i"; break;
|
|
753 case "uint": mangled = "k"; break;
|
|
754 case "long": mangled = "l"; break;
|
|
755 case "ulong": mangled = "m"; break;
|
|
756 case "float": mangled = "f"; break;
|
|
757 case "double": mangled = "d"; break;
|
|
758 case "real": mangled = "e"; break;
|
|
759 default:
|
|
760 Leaf lf;
|
|
761 if ( (unmangled in ctx.codeView.UDTsByName) is null )
|
|
762 {
|
|
763 foreach ( un, l; ctx.codeView.UDTsByName )
|
|
764 {
|
|
765 if ( std.string.find(un, "."~unmangled) > 0 ) {
|
|
766 lf = l;
|
|
767 break;
|
|
768 }
|
|
769 }
|
|
770 }
|
|
771 else
|
|
772 lf = ctx.codeView.UDTsByName[unmangled];
|
|
773
|
|
774 if ( lf !is null )
|
|
775 {
|
|
776 string fqn;
|
|
777 switch ( lf.leaf_index )
|
|
778 {
|
|
779 case LF_CLASS_16t:
|
|
780 mangled = "C";
|
|
781 fqn = (cast(LeafClassStruc)lf).name;
|
|
782 break;
|
|
783 case LF_STRUCTURE_16t:
|
|
784 mangled = "S";
|
|
785 fqn = (cast(LeafClassStruc)lf).name;
|
|
786 break;
|
|
787 case LF_ENUM_16t:
|
|
788 mangled = "E";
|
|
789 fqn = (cast(LeafEnum)lf).name;
|
|
790 break;
|
|
791 default:
|
|
792 assert(0);
|
|
793 }
|
|
794 string[] parts = std.string.split(fqn, ".");
|
|
795 foreach ( p; parts ) {
|
|
796 mangled ~= .toString(p.length);
|
|
797 mangled ~= p;
|
|
798 }
|
|
799 }
|
|
800 else
|
|
801 throw new EvaluationException("Unknown BaseType "~unmangled);
|
|
802 break;
|
|
803 }
|
|
804
|
|
805 QuantList(ctx, mangled);
|
|
806 }
|
|
807 }
|
|
808
|
|
809 BaseType(EvaluationContext ctx, out string type)
|
|
810 {
|
|
811 FQNIdent TplParams
|
|
812 {
|
|
813 FQNIdent(type);
|
|
814 string str;
|
|
815 TplParams(ctx, str);
|
|
816 type ~= str;
|
|
817 }
|
|
818 }
|
|
819
|
|
820 QuantList(EvaluationContext ctx, ref string mangled)
|
|
821 {
|
|
822 Quantifier QuantList
|
|
823 {
|
|
824 Quantifier(ctx, mangled);
|
|
825 QuantList(ctx, mangled);
|
|
826 }
|
|
827
|
|
828 epsilon;
|
|
829 }
|
|
830
|
|
831 Quantifier(EvaluationContext ctx, ref string mangled)
|
|
832 {
|
|
833 "*"
|
|
834 { mangled = "P"~mangled; }
|
|
835
|
|
836 "[" "]"
|
|
837 { mangled = "A"~mangled; }
|
|
838
|
|
839 "["
|
|
840 Integer !("(%d) ] expected")
|
|
841 "]"
|
|
842 {
|
|
843 ulong len;
|
|
844 Integer(len);
|
|
845 mangled = "G"~.toString(len)~mangled;
|
|
846 }
|
|
847
|
|
848 "[" !("(%d) ], type or size expected")
|
|
849 Type !("(%d) ] expected")
|
|
850 "]"
|
|
851 {
|
|
852 string index_mangled;
|
|
853 Type(ctx, index_mangled);
|
|
854 mangled = "H"~index_mangled~mangled;
|
|
855 }
|
|
856 }
|
|
857
|
|
858 TplParams(EvaluationContext ctx, out string str)
|
|
859 {
|
|
860 "!" !("(%d) ( expected")
|
|
861 "(" !("(%d) Template parameters expected")
|
|
862 TplParam
|
|
863 TplParams2 !("(%d) ) expected")
|
|
864 ")"
|
|
865 {
|
|
866 string tmp;
|
|
867 TplParam(ctx, tmp);
|
|
868 str = "!("~tmp;
|
|
869 TplParams2(ctx, tmp);
|
|
870 str ~= tmp~")";
|
|
871 }
|
|
872
|
|
873 epsilon;
|
|
874 }
|
|
875
|
|
876 TplParams2(EvaluationContext ctx, out string str)
|
|
877 {
|
|
878 "," !("(%d) Template parameter expected")
|
|
879 TplParam
|
|
880 TplParams2
|
|
881 {
|
|
882 TplParam(ctx, str);
|
|
883 string tmp;
|
|
884 TplParams2(ctx, tmp);
|
|
885 str ~= tmp;
|
|
886 }
|
|
887
|
|
888 epsilon;
|
|
889 }
|
|
890
|
|
891 TplParam(EvaluationContext ctx, out string str)
|
|
892 {
|
|
893 Type { Type(ctx, str); }
|
|
894 StrLit { StrLit(str); }
|
|
895 }
|
|
896
|
|
897
|
|
898 /**************************************************************************************************
|
|
899 Terminals
|
|
900 **************************************************************************************************/
|
|
901 Lit(out SymbolData litdata)
|
|
902 {
|
|
903 Sign Integer IntegerSuffix
|
|
904 {
|
|
905 litdata = new SymbolData;
|
|
906 IntegerSuffix(litdata.type);
|
|
907 ulong val;
|
|
908 Integer(val);
|
|
909
|
|
910 if ( val > 0x7fffffffffffffff )
|
|
911 litdata.type = "m";
|
|
912 else if ( val > 0xffffffff )
|
|
913 litdata.type = litdata.type[0]=='i'||litdata.type[0]=='l'?"l":"m";
|
|
914 else if ( val > 0x7fffffff && litdata.type[0] == 'i' )
|
|
915 litdata.type = "k";
|
|
916
|
|
917 litdata.data = (cast(ubyte*)&val)[0 .. (litdata.type[0] == 'k' || litdata.type[0] == 'i')?uint.sizeof:ulong.sizeof].dup;
|
|
918 Sign(litdata);
|
|
919 }
|
|
920
|
|
921 // String
|
|
922 regexp("\"(([^\"\\\\]*(\\\\(['\"\\?\\\\abfnrtv]|(x[0-9a-fA-F]{2})|(u[0-9a-fA-F]{4})|(U[0-9a-fA-F]{8})))?)*)\"")
|
|
923 {
|
|
924 litdata = new SymbolData;
|
|
925 litdata.type = "Aa";
|
|
926 litdata.data = cast(ubyte[])_ST_match;
|
|
927 }
|
|
928
|
|
929 // Char
|
|
930 regexp("'(([^'\\\\]|(\\\\(['\"\\?\\\\abfnrtv]|(x[0-9a-fA-F]{2})|(u[0-9a-fA-F]{4})|(U[0-9a-fA-F]{8})))))'")
|
|
931 {
|
|
932 litdata = new SymbolData;
|
|
933 litdata.type = "a";
|
|
934 litdata.data = cast(ubyte[])_ST_match[0..1];
|
|
935 }
|
|
936 }
|
|
937
|
|
938 StrLit(out string str)
|
|
939 {
|
|
940 // Integer
|
|
941 Integer
|
|
942 {
|
|
943 ulong val;
|
|
944 Integer(val);
|
|
945 str = .toString(val);
|
|
946 }
|
|
947
|
|
948 // String
|
|
949 regexp("\"(([^\"\\\\]*(\\\\(['\"\\?\\\\abfnrtv]|(x[0-9a-fA-F]{2})|(u[0-9a-fA-F]{4})|(U[0-9a-fA-F]{8})))?)*)\"")
|
|
950 { str = _ST_match; }
|
|
951
|
|
952 // Char
|
|
953 regexp("'(([^'\\\\]|(\\\\(['\"\\?\\\\abfnrtv]|(x[0-9a-fA-F]{2})|(u[0-9a-fA-F]{4})|(U[0-9a-fA-F]{8})))))'")
|
|
954 { str = _ST_match; }
|
|
955 }
|
|
956
|
|
957 Ident(out string id)
|
|
958 {
|
|
959 regexp("[a-zA-Z_][_a-zA-Z0-9]*")
|
|
960 { id = _ST_match; }
|
|
961 }
|
|
962
|
|
963 FQNIdent(out string id)
|
|
964 {
|
|
965 Ident
|
|
966 { Ident(id); }
|
|
967
|
|
968 FQNIdent "." Ident
|
|
969 {
|
|
970 FQNIdent(id);
|
|
971 string tmp;
|
|
972 Ident(tmp);
|
|
973 id ~= "."~tmp;
|
|
974 }
|
|
975 }
|
|
976
|
|
977 /**************************************************************************************************
|
|
978 Integers
|
|
979 **************************************************************************************************/
|
|
980 Integer(out ulong val)
|
|
981 {
|
|
982 // hex
|
|
983 regexp("0[xX][0-9a-fA-F_]+")
|
|
984 {
|
|
985 foreach ( b; _ST_match[2..$] )
|
|
986 {
|
|
987 val <<= 4;
|
|
988 if ( b > 'F' )
|
|
989 val |= b-'W';
|
|
990 else if ( b > '9' )
|
|
991 val |= b-'7';
|
|
992 else
|
|
993 val |= b-'0';
|
|
994 }
|
|
995 }
|
|
996
|
|
997 // binary
|
|
998 regexp("0[bB][01_]+")
|
|
999 {
|
|
1000 foreach ( b; _ST_match[2..$] )
|
|
1001 {
|
|
1002 val <<= 1;
|
|
1003 if ( b == '1' )
|
|
1004 val |= 1;
|
|
1005 }
|
|
1006 }
|
|
1007
|
|
1008 // octal
|
|
1009 regexp("0[0-7_]+")
|
|
1010 {
|
|
1011 foreach ( b; _ST_match[1..$] ) {
|
|
1012 val <<= 3;
|
|
1013 val |= b-'0';
|
|
1014 }
|
|
1015 }
|
|
1016
|
|
1017 // decimal
|
|
1018 regexp("0|([1-9][0-9_]*)")
|
|
1019 {
|
|
1020 foreach ( b; _ST_match ) {
|
|
1021 val *= 10;
|
|
1022 val += b-'0';
|
|
1023 }
|
|
1024 }
|
|
1025 }
|
|
1026
|
|
1027 IntegerSuffix(out string type)
|
|
1028 {
|
|
1029 "L" "u"
|
|
1030 { type = "m"; }
|
|
1031
|
|
1032 "L" "U"
|
|
1033 { type = "m"; }
|
|
1034
|
|
1035 "u" "L"
|
|
1036 { type = "m"; }
|
|
1037
|
|
1038 "U" "L"
|
|
1039 { type = "m"; }
|
|
1040
|
|
1041 "L"
|
|
1042 { type = "l"; }
|
|
1043
|
|
1044 regexp("[uU]")
|
|
1045 { type = "k"; }
|
|
1046
|
|
1047 epsilon
|
|
1048 { type = "i"; }
|
|
1049 }
|
|
1050
|
|
1051 Sign(ref SymbolData symdata)
|
|
1052 {
|
|
1053 "-"
|
|
1054 {
|
|
1055 switch ( symdata.type[0] )
|
|
1056 {
|
|
1057 case 'i':
|
|
1058 *cast(int*)symdata.data.ptr = 0-*cast(int*)symdata.data.ptr;
|
|
1059 break;
|
|
1060 case 'k':
|
|
1061 *cast(uint*)symdata.data.ptr = 0-*cast(uint*)symdata.data.ptr;
|
|
1062 break;
|
|
1063 case 'l':
|
|
1064 *cast(long*)symdata.data.ptr = 0-*cast(long*)symdata.data.ptr;
|
|
1065 break;
|
|
1066 case 'm':
|
|
1067 *cast(ulong*)symdata.data.ptr = 0-*cast(ulong*)symdata.data.ptr;
|
|
1068 break;
|
|
1069 default:
|
|
1070 assert(0);
|
|
1071 }
|
|
1072 }
|
|
1073
|
|
1074 epsilon;
|
|
1075 }
|