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 module codeview.codeview;
|
|
7
|
|
8 import std.ctype;
|
|
9 import std.string;
|
|
10 import std.math;
|
|
11
|
|
12 import util;
|
|
13 import container;
|
|
14 import codeview.coff;
|
|
15 import codeview.decl;
|
|
16
|
|
17 public import codeview.debuginfo;
|
|
18
|
|
19 //=================================================================================================
|
|
20 // classes for accessing CodeView data
|
|
21
|
|
22 abstract class Symbol
|
|
23 {
|
|
24 SymbolIndex symbol_index;
|
|
25
|
|
26 this(SymbolIndex si) { symbol_index = si; }
|
|
27 }
|
|
28
|
|
29 class ReturnSymbol : Symbol
|
|
30 {
|
|
31 CVReturnSymbol* cvdata;
|
|
32 ubyte[] registers;
|
|
33
|
|
34 this(CVReturnSymbol* cv) { super(SymbolIndex.S_RETURN); cvdata = cv; }
|
|
35 }
|
|
36
|
|
37 class StringWrap
|
|
38 {
|
|
39 string str;
|
|
40
|
|
41 this(string _str) { str = _str; }
|
|
42
|
|
43 int opCmp(Object o)
|
|
44 {
|
|
45 NamedSymbol ns = cast(NamedSymbol)o;
|
|
46 if ( ns !is null )
|
|
47 return -ns.opCmp(this);
|
|
48
|
|
49 StringWrap sw = cast(StringWrap)o;
|
|
50 if ( sw is null )
|
|
51 return -1;
|
|
52 if ( str == sw.str )
|
|
53 return 0;
|
|
54 if ( str < sw.str )
|
|
55 return -1;
|
|
56 return 1;
|
|
57 }
|
|
58 }
|
|
59
|
|
60 abstract class NamedSymbol : Symbol
|
|
61 {
|
|
62 string mangled_name,
|
|
63 name_type,
|
|
64 name_notype;
|
|
65
|
|
66 this(SymbolIndex si) { super(si); }
|
|
67
|
|
68 int opCmp(Object o)
|
|
69 {
|
|
70 string str;
|
|
71 NamedSymbol ns = cast(NamedSymbol)o;
|
|
72 if ( ns is null )
|
|
73 {
|
|
74 StringWrap sw = cast(StringWrap)o;
|
|
75 if ( sw is null )
|
|
76 return -1;
|
|
77 str = sw.str;
|
|
78 }
|
|
79 else
|
|
80 str = ns.name_notype;
|
|
81 if ( name_notype == str )
|
|
82 return 0;
|
|
83 if ( name_notype < str )
|
|
84 return -1;
|
|
85 return 1;
|
|
86 }
|
|
87 }
|
|
88
|
|
89 class StackSymbol : NamedSymbol
|
|
90 {
|
|
91 CVStackSymbol* cvdata;
|
|
92 int size;
|
|
93
|
|
94 this(CVStackSymbol* cv)
|
|
95 {
|
|
96 super(SymbolIndex.S_BPREL32);
|
|
97 cvdata=cv;
|
|
98 }
|
|
99
|
|
100 uint offset() { return cvdata.offset; }
|
|
101 uint cvtype() { return cvdata.type; }
|
|
102 }
|
|
103
|
|
104 class DataSymbol : NamedSymbol
|
|
105 {
|
|
106 CVDataSymbol* cvdata;
|
|
107 uint size;
|
|
108
|
|
109 this(SymbolIndex si, CVDataSymbol* cv)
|
|
110 {
|
|
111 super(si);
|
|
112 cvdata=cv;
|
|
113 }
|
|
114
|
|
115 uint offset() { return cvdata.offset; }
|
|
116 uint cvtype() { return cvdata.type; }
|
|
117 }
|
|
118
|
|
119 abstract class ScopeSymbol : NamedSymbol
|
|
120 {
|
|
121 ScopeSymbol parent_scope;
|
|
122 SymbolSet symbols;
|
|
123 uint lfo;
|
|
124
|
|
125 this(SymbolIndex si, uint _lfo) { super(si); lfo = _lfo; symbols = new SymbolSet; }
|
|
126 }
|
|
127
|
|
128 class ProcedureSymbol : ScopeSymbol
|
|
129 {
|
|
130 CVProcedureSymbol* cvdata;
|
|
131 SymbolSet arguments;
|
|
132 ReturnSymbol return_sym;
|
|
133
|
|
134 this(SymbolIndex si, uint lfo, CVProcedureSymbol* cvd)
|
|
135 {
|
|
136 super(si,lfo);
|
|
137 cvdata = cvd;
|
|
138 arguments = new SymbolSet;
|
|
139 }
|
|
140 }
|
|
141
|
|
142 class SymbolSet
|
|
143 {
|
|
144 ProcedureSymbol[] proc_symbols;
|
|
145 StackSymbol[] stack_symbols;
|
|
146 DataSymbol[] data_symbols;
|
|
147 NamedSymbol[] named_symbols;
|
|
148 Symbol[] symbols;
|
|
149
|
|
150 void opCatAssign(SymbolSet s)
|
|
151 {
|
|
152 symbols ~= s.symbols;
|
|
153 named_symbols ~= s.named_symbols;
|
|
154 data_symbols ~= s.data_symbols;
|
|
155 stack_symbols ~= s.stack_symbols;
|
|
156 proc_symbols ~= s.proc_symbols;
|
|
157 }
|
|
158
|
|
159 void add(Symbol s)
|
|
160 {
|
|
161 NamedSymbol ns = cast(NamedSymbol)s;
|
|
162 if ( ns is null ) {
|
|
163 symbols ~= s;
|
|
164 return;
|
|
165 }
|
|
166 named_symbols ~= ns;
|
|
167 ClassInfo ci = s.classinfo;
|
|
168 if ( ci == ProcedureSymbol.classinfo )
|
|
169 proc_symbols ~= cast(ProcedureSymbol)s;
|
|
170 else if ( ci == StackSymbol.classinfo )
|
|
171 stack_symbols ~= cast(StackSymbol)s;
|
|
172 else if ( ci == DataSymbol.classinfo )
|
|
173 data_symbols ~= cast(DataSymbol)s;
|
|
174 }
|
|
175
|
|
176 /**********************************************************************************************
|
|
177 Find procedure symbol covering the given address.
|
|
178 **********************************************************************************************/
|
|
179 ProcedureSymbol findProcedureSymbol(uint address)
|
|
180 {
|
|
181 foreach ( ps; proc_symbols )
|
|
182 if ( address >= ps.cvdata.offset && address < ps.cvdata.offset+ps.cvdata.proc_length )
|
|
183 return ps;
|
|
184 return null;
|
|
185 }
|
|
186
|
|
187 /**********************************************************************************************
|
|
188 Find data symbol covering the given address.
|
|
189 **********************************************************************************************/
|
|
190 DataSymbol findDataSymbol(uint address, uint segment)
|
|
191 {
|
|
192 foreach ( ds; data_symbols )
|
|
193 {
|
|
194 if ( segment > 0 && ds.cvdata.segment != segment )
|
|
195 continue;
|
|
196 if ( address == ds.cvdata.offset )
|
|
197 return ds;
|
|
198 }
|
|
199 return null;
|
|
200 }
|
|
201
|
|
202 /**********************************************************************************************
|
|
203 Find data symbol by name.
|
|
204 **********************************************************************************************/
|
|
205 DataSymbol findDataSymbol(string name)
|
|
206 {
|
|
207 foreach ( ds; data_symbols )
|
|
208 {
|
|
209 if ( ds.name_notype == name )
|
|
210 return ds;
|
|
211 }
|
|
212 return null;
|
|
213 }
|
|
214
|
5
|
215 /**********************************************************************************************
|
|
216 Find matching data symbols by a substring in its name.
|
|
217 **********************************************************************************************/
|
|
218 DataSymbol[] findDataSymbolBySubstring(string name)
|
|
219 {
|
|
220 DataSymbol[] found;
|
|
221 foreach ( ds; data_symbols )
|
|
222 {
|
|
223 if ( find(ds.name_notype,name)>=0 )
|
|
224 found~=ds;
|
|
225 }
|
|
226 return found;
|
|
227 }
|
|
228
|
1
|
229 /**********************************************************************************************
|
|
230 Find nearest data symbol to the given address.
|
|
231 **********************************************************************************************/
|
|
232 DataSymbol findNearestDataSymbol(uint address, inout uint min_dist, uint segment)
|
|
233 {
|
|
234 DataSymbol min_ds;
|
|
235 foreach ( ds; data_symbols )
|
|
236 {
|
|
237 if ( address < ds.cvdata.offset || ds.cvdata.segment != segment )
|
|
238 continue;
|
|
239 uint dist = abs(cast(int)address-cast(int)ds.cvdata.offset);
|
|
240 if ( dist < min_dist ) {
|
|
241 min_dist = dist;
|
|
242 min_ds = ds;
|
|
243 }
|
|
244 }
|
|
245 return min_ds;
|
|
246 }
|
|
247 }
|
|
248
|
|
249 class Module
|
|
250 {
|
|
251 ModuleHeader* header;
|
|
252 SegInfo[] seginfos;
|
|
253 string name;
|
|
254 ushort pe_section;
|
|
255
|
|
256 SymbolSet symbols;
|
|
257
|
|
258 SourceModule source_module;
|
|
259
|
|
260 CodeView codeview;
|
|
261
|
|
262 this(CodeView cv)
|
|
263 {
|
|
264 symbols = new SymbolSet;
|
|
265 codeview = cv;
|
|
266 }
|
|
267 }
|
|
268
|
|
269 class Location
|
|
270 {
|
|
271 string path;
|
|
272
|
|
273 ScopeSymbol scope_sym;
|
|
274 DataSymbol data_sym;
|
|
275 Module mod;
|
|
276 CodeBlock codeblock;
|
|
277 CodeView codeview;
|
|
278 uint address;
|
|
279
|
|
280 this(uint addr, CodeView cv)
|
|
281 {
|
|
282 codeview = cv;
|
|
283 address = addr;
|
|
284 }
|
|
285
|
|
286 this(uint addr)
|
|
287 {
|
|
288 address = addr;
|
|
289 }
|
|
290
|
|
291 this(string p)
|
|
292 {
|
|
293 path = p;
|
|
294 }
|
|
295
|
|
296 uint line()
|
|
297 {
|
|
298 if ( codeblock is null )
|
|
299 return 0;
|
|
300 return codeblock.line;
|
|
301 }
|
|
302
|
|
303 string file()
|
|
304 {
|
|
305 if ( codeblock is null || codeblock.segment is null )
|
|
306 return null;
|
|
307 return codeblock.segment.file.name;
|
|
308 }
|
|
309
|
|
310 size_t getCodeBase()
|
|
311 {
|
|
312 return mod.codeview.image.getCodeBase;
|
|
313 }
|
|
314
|
|
315 bool bind(ImageSet images, string[] source_search_paths)
|
|
316 {
|
|
317 if ( path is null )
|
|
318 return false;
|
|
319
|
|
320 if ( find(path, '"') >= 0 )
|
|
321 path = replace(path, "\"", "");
|
|
322
|
|
323 string[] file_line = split(path, ":");
|
|
324 if ( file_line is null || file_line.length < 2 || !isNumeric(file_line[$-1]) ) {
|
|
325 DbgIO.println("Invalid location format. Use <part of filename>:<linenumber>");
|
|
326 return false;
|
|
327 }
|
|
328
|
|
329 string file = join(file_line[0..$-1], ":"),
|
|
330 line = file_line[$-1];
|
|
331
|
|
332 if ( find(file, '/') >= 0 )
|
|
333 file = replace(file, "/", "\\");
|
4
|
334 debug DbgIO.println("searching in %s", file);
|
1
|
335 SourceFile[] sfs = images.findSrcFiles(file);
|
|
336 if ( sfs.length == 0 )
|
|
337 sfs = images.findSrcFiles(file, source_search_paths);
|
|
338 if ( sfs.length == 0 ) {
|
|
339 DbgIO.println("Source file \"%s\" not found", file);
|
|
340 return false;
|
|
341 }
|
|
342
|
|
343 uint linenum = cast(uint)atoi(line);
|
|
344 Location loc;
|
|
345 foreach ( sf; sfs )
|
|
346 {
|
|
347 debug DbgIO.println("searching sf %s", sf.name);
|
|
348 auto loc2 = images.findSrcLine(sf, linenum);
|
|
349 if ( loc is null )
|
|
350 loc = loc2;
|
|
351 else if ( loc2 !is null && loc2.line < loc.line )
|
|
352 loc = loc2;
|
|
353 }
|
|
354 if ( loc is null )
|
|
355 DbgIO.println("Line %d in \"%s\" not found", linenum, sfs[0].name);
|
|
356
|
|
357 scope_sym = loc.scope_sym;
|
|
358 data_sym = loc.data_sym;
|
|
359 mod = loc.mod;
|
|
360 codeblock = loc.codeblock;
|
|
361 address = loc.address;
|
|
362 path = null;
|
|
363 return true;
|
|
364 }
|
|
365 }
|
|
366
|
|
367 class UserDefinedType
|
|
368 {
|
|
369 ushort type_index;
|
|
370 string name;
|
|
371 }
|
|
372
|
|
373 /**************************************************************************************************
|
|
374 Represents the CodeView information of an executable image. Provides methods to browse the
|
|
375 information. Objects of this class get created by CodeViewParser.parse.
|
|
376 **************************************************************************************************/
|
|
377 class CodeView : DebugInfo
|
|
378 {
|
|
379 Module[string] modulesByName;
|
|
380 Module[] modulesByIndex;
|
|
381
|
|
382 SymbolSet global_pub,
|
|
383 global_sym,
|
|
384 static_sym;
|
|
385 UserDefinedType[] udtypes;
|
|
386 Leaf[][] type_strings;
|
|
387
|
|
388 Leaf[string] UDTsByName;
|
|
389
|
|
390 string[] libraries,
|
|
391 segnames;
|
|
392
|
|
393 COFFImage image;
|
|
394
|
|
395 AVLTree!(NamedSymbol) globalNamedSymbols;
|
|
396
|
|
397 size_t getCodeBase()
|
|
398 {
|
|
399 return image.getCodeBase;
|
|
400 }
|
|
401
|
|
402 /**********************************************************************************************
|
|
403 Find the module and segment covering the given address.
|
|
404 **********************************************************************************************/
|
|
405 Module findModule(uint vaddress, out uint segment)
|
|
406 {
|
|
407 uint address = vaddress-image.getCodeBase;
|
|
408 foreach ( m; modulesByIndex )
|
|
409 {
|
|
410 foreach ( s; m.seginfos )
|
|
411 {
|
|
412 if ( address < s.offset )
|
|
413 continue;
|
|
414 if ( address-s.offset < s.cbSeg ) {
|
|
415 segment = s.Seg;
|
|
416 return m;
|
|
417 }
|
|
418 }
|
|
419 }
|
|
420 return null;
|
|
421 }
|
|
422
|
|
423 /**********************************************************************************************
|
|
424 Find next source line from the given location.
|
|
425 **********************************************************************************************/
|
|
426 Location findNextSrcLine(Location loc)
|
|
427 {
|
|
428 if ( loc is null || loc.codeblock is null || loc.codeblock.segment is null )
|
|
429 return null;
|
|
430 Location nextloc = findLocation(loc.codeblock.end+image.getCodeBase);
|
|
431 return nextloc;
|
|
432 }
|
|
433
|
|
434 /**********************************************************************************************
|
|
435 Find previous source line from location that isn't covered by a source codeblock.
|
|
436 **********************************************************************************************/
|
|
437 Location findPrevSrcLine(Location loc)
|
|
438 {
|
|
439 if ( loc is null )
|
|
440 return null;
|
|
441 if ( loc.codeblock !is null )
|
|
442 return loc;
|
|
443
|
|
444 AVLNode!(CodeBlock) node;
|
|
445 if ( !codeblocks.find(loc.address-1+image.getCodeBase, node) )
|
|
446 {
|
|
447 if ( node.value.start > loc.address )
|
|
448 {
|
|
449 if ( !node.findPrev(node) )
|
|
450 return null;
|
|
451 }
|
|
452 }
|
|
453 Location prevloc = new Location(node.value.start, this);
|
|
454 prevloc.codeblock = node.value;
|
|
455 findSymbolForLocation(prevloc);
|
|
456 assert(prevloc.line != 0);
|
|
457 return prevloc;
|
|
458 }
|
|
459
|
|
460 /**********************************************************************************************
|
|
461 Find first source line in the given file that has a line number >= line
|
|
462 and a start address >= min_start.
|
|
463 **********************************************************************************************/
|
|
464 Location findSrcLine(SourceFile sf, uint min_line, size_t min_start=0)
|
|
465 {
|
|
466 if ( sf is null )
|
|
467 return null;
|
|
468
|
|
469 pragma(msg, TODO(__FILE__,__LINE__,"use binary search here"));
|
|
470 foreach ( l; sf.lines )
|
|
471 {
|
|
472 if ( l < min_line )
|
|
473 continue;
|
|
474 foreach ( cb; sf.blocks_by_line[l] )
|
|
475 {
|
|
476 if ( cb.start < min_start || cb.end <= cb.start )
|
|
477 continue;
|
|
478 Location loc = new Location(cb.start+image.getCodeBase, this);
|
|
479 loc.codeblock = cb;
|
|
480 findSymbolForLocation(loc);
|
|
481 return loc;
|
|
482 }
|
|
483 }
|
|
484 return null;
|
|
485 }
|
|
486
|
|
487 /**********************************************************************************************
|
|
488 Find all debug information available for the given address.
|
|
489 **********************************************************************************************/
|
|
490 Location findLocation(uint vaddress)
|
|
491 {
|
|
492 Location loc = new Location(vaddress, this);
|
|
493 CodeBlock cb = findCodeBlockAbs(vaddress);
|
|
494 loc.codeblock = cb;
|
|
495 findSymbolForLocation(loc);
|
|
496 return loc;
|
|
497 }
|
|
498
|
|
499 /**********************************************************************************************
|
|
500 Fill out symbol information (as opposed to source line information) in the given location.
|
|
501 **********************************************************************************************/
|
|
502 void findSymbolForLocation(Location loc)
|
|
503 {
|
|
504 ProcedureSymbol psym = findProcedureSymbol(loc.address);
|
|
505 if ( psym !is null )
|
|
506 loc.scope_sym = psym;
|
|
507 else
|
|
508 {
|
|
509 DataSymbol dsym = findDataSymbol(loc.address, 2);
|
|
510 if ( dsym !is null )
|
|
511 loc.data_sym = dsym;
|
|
512 }
|
|
513
|
|
514 uint seg;
|
|
515 Module mod = findModule(loc.address, seg);
|
|
516 if ( mod !is null )
|
|
517 {
|
|
518 loc.mod = mod;
|
|
519 if ( loc.data_sym is null )
|
|
520 {
|
|
521 uint min_dist = uint.max;
|
|
522 loc.data_sym = global_sym.findNearestDataSymbol(loc.address-image.getCodeBase, min_dist, image.code_section_index+1);
|
|
523 if ( loc.data_sym is null )
|
|
524 loc.data_sym = global_pub.findNearestDataSymbol(loc.address-image.getCodeBase, min_dist, image.code_section_index+1);
|
|
525 }
|
|
526 }
|
|
527 }
|
|
528
|
|
529 /**********************************************************************************************
|
|
530 Find procedure symbol covering the given address.
|
|
531 **********************************************************************************************/
|
|
532 ProcedureSymbol findProcedureSymbol(uint vaddress)
|
|
533 {
|
|
534 uint address = vaddress-image.getCodeBase;
|
|
535 ProcedureSymbol ps;
|
|
536 foreach ( m; modulesByIndex )
|
|
537 {
|
|
538 ps = m.symbols.findProcedureSymbol(address);
|
|
539 if ( ps !is null )
|
|
540 return ps;
|
|
541 }
|
|
542 ps = global_sym.findProcedureSymbol(address);
|
|
543 if ( ps is null )
|
|
544 ps = static_sym.findProcedureSymbol(address);
|
|
545 if ( ps is null )
|
|
546 ps = global_pub.findProcedureSymbol(address);
|
|
547 return ps;
|
|
548 }
|
|
549
|
|
550 /**********************************************************************************************
|
|
551 Find data symbol covering the given address.
|
|
552 **********************************************************************************************/
|
|
553 DataSymbol findDataSymbol(uint vaddress, uint segment=0)
|
|
554 {
|
|
555 uint address = vaddress-image.getCodeBase;
|
|
556 DataSymbol ps;
|
|
557 foreach ( m; modulesByIndex )
|
|
558 {
|
|
559 ps = m.symbols.findDataSymbol(address, segment);
|
|
560 if ( ps !is null )
|
|
561 break;
|
|
562 }
|
|
563 ps = global_sym.findDataSymbol(address, segment);
|
|
564 if ( ps is null )
|
|
565 ps = static_sym.findDataSymbol(address, segment);
|
|
566 if ( ps is null )
|
|
567 ps = global_pub.findDataSymbol(address, segment);
|
|
568 return ps;
|
|
569 }
|
|
570
|
|
571 /**********************************************************************************************
|
|
572 Creates a D mangled name from a CodeView symbol.
|
|
573 Uses available mangled type info if available, mangles CodeView type info else.
|
|
574 Returns: Symbol name with mangled type info.
|
|
575 **********************************************************************************************/
|
|
576 string mangle(NamedSymbol s)
|
|
577 {
|
|
578 // use mangled typeinfo if available
|
|
579 if ( s.mangled_name !is null && s.mangled_name.length > 2 && s.mangled_name[0..2] == "_D" && isdigit(s.mangled_name[2]) )
|
|
580 return s.mangled_name;
|
|
581
|
|
582 return "_D"~mangleName(s.name_type)~mangleType(s);
|
|
583 }
|
|
584
|
|
585 /**********************************************************************************************
|
|
586 Creates the type part of a D mangled name for a CodeView symbol.
|
|
587 **********************************************************************************************/
|
|
588 string mangleType(Symbol s)
|
|
589 {
|
|
590 DataSymbol ds = cast(DataSymbol)s;
|
|
591 ushort cvtype;
|
|
592 if ( ds !is null )
|
|
593 cvtype = ds.cvdata.type;
|
|
594 else
|
|
595 {
|
|
596 StackSymbol ss = cast(StackSymbol)s;
|
|
597 if ( ss !is null )
|
|
598 cvtype = ss.cvdata.type;
|
|
599 else {
|
|
600 pragma(msg, TODO(__FILE__,__LINE__,"implement procedure symbol mangling"));
|
|
601 }
|
|
602 }
|
|
603 return mangleCVtype(cvtype);
|
|
604 }
|
|
605
|
|
606 /**********************************************************************************************
|
|
607 Creates the type part of a D mangled name for a CodeView type index.
|
|
608 **********************************************************************************************/
|
|
609 string mangleCVtype(ushort cvtype)
|
|
610 {
|
|
611 if ( cvtype >= 0x1000 )
|
|
612 {
|
|
613 uint typeindex = cvtype-0x1000;
|
|
614 if ( typeindex >= type_strings.length ) {
|
|
615 debug DbgIO.println("undefined complex type 0x%x largest known type 0x%x", cvtype, type_strings.length-1);
|
|
616 return null;
|
|
617 }
|
|
618 Leaf[] typestring = type_strings[typeindex];
|
|
619
|
|
620 while ( typestring.length > 0 )
|
|
621 {
|
|
622 switch ( typestring[0].leaf_index )
|
|
623 {
|
|
624 case LF_MODIFIER_16t:
|
|
625 LeafModifer lm = cast(LeafModifer)typestring[0];
|
|
626 assert ( lm !is null );
|
|
627 return mangleCVtype(lm.index);
|
|
628 case LF_POINTER_16t:
|
|
629 LeafPointer lp = cast(LeafPointer)typestring[0];
|
|
630 assert ( lp !is null );
|
|
631 return "P"~mangleCVtype(lp.type);
|
|
632 // do not insert new cases here
|
|
633 case LF_CLASS_16t:
|
|
634 LeafClassStruc lcs = cast(LeafClassStruc)typestring[0];
|
|
635 assert ( lcs !is null );
|
|
636 return "C"~mangleName(lcs.name);
|
|
637 case LF_ARRAY_16t:
|
|
638 LeafArray la = cast(LeafArray)typestring[0];
|
|
639 assert ( la !is null );
|
|
640 debug(cvparser) DbgIO.println("Static array elemtype 0x%x idxtype 0x%x length %d", la.elemtype, la.idxtype, la.length.getUint);
|
|
641 uint count = la.length.getUint,
|
|
642 elmsize = sizeofCV(la.elemtype);
|
|
643 if ( elmsize > 0 ) {
|
|
644 count /= elmsize;
|
|
645 assert(la.length.getUint % sizeofCV(la.elemtype) == 0);
|
|
646 }
|
|
647 else
|
|
648 debug DbgIO.println("WARNING: elm size == 0");
|
|
649 return "G"~.toString(count)~mangleCVtype(la.elemtype);
|
|
650 case LF_OEM_16t:
|
|
651 LeafDynArray lda = cast(LeafDynArray)typestring[0];
|
|
652 if ( lda !is null )
|
|
653 return "A"~mangleCVtype(lda.elem_type);
|
|
654 LeafAssocArray laa = cast(LeafAssocArray)typestring[0];
|
|
655 if ( laa !is null )
|
|
656 return "H"~mangleCVtype(laa.key_type)~mangleCVtype(laa.elem_type);
|
|
657 LeafDelegate ld = cast(LeafDelegate)typestring[0];
|
|
658 if ( ld !is null )
|
|
659 return "D"~mangleCVtype(ld.func_type);
|
|
660 assert(0);
|
|
661
|
|
662 case LF_STRUCTURE_16t:
|
|
663 LeafClassStruc lcs = cast(LeafClassStruc)typestring[0];
|
|
664 assert ( lcs !is null );
|
|
665 return "S"~mangleName(lcs.name);
|
|
666 case LF_PROCEDURE_16t:
|
|
667 case LF_METHODLIST_16t:
|
|
668 debug(cvparser) DbgIO.println("unmangled procedure or methodlist in complex type");
|
|
669 return "";
|
|
670 case LF_UNION_16t:
|
|
671 LeafUnion lu = cast(LeafUnion)typestring[0];
|
|
672 return "S"~mangleName(lu.name);
|
|
673 default:
|
|
674 DbgIO.println("mangleCVtype: unsupported type leaf 0x%x", typestring[0].leaf_index);
|
|
675 typestring = typestring[1..$];
|
|
676 }
|
|
677 }
|
|
678 return null;
|
|
679 }
|
|
680
|
|
681 switch ( cvtype )
|
|
682 {
|
|
683 case T_NOTYPE:
|
|
684 return null;
|
|
685 case T_VOID:
|
|
686 return "v";
|
|
687 case T_PVOID: case T_PFVOID: case T_PHVOID: case T_32PVOID: case T_32PFVOID:
|
|
688 return "Pv";
|
|
689
|
|
690 case T_CHAR:
|
|
691 return "g";
|
|
692 case T_UCHAR:
|
|
693 return "h";
|
|
694 case T_RCHAR:
|
|
695 return "a";
|
|
696 case T_WCHAR:
|
|
697 return "u";
|
|
698 case T_DCHAR:
|
|
699 return "w";
|
|
700 case T_32PDCHAR: case T_32PFDCHAR:
|
|
701 return "Pw";
|
|
702 case T_PFRCHAR: case T_PHRCHAR: case T_32PRCHAR: case T_32PFRCHAR: case T_PRCHAR:
|
|
703 return "Pa";
|
|
704 case T_PFWCHAR: case T_PHWCHAR: case T_32PWCHAR: case T_32PFWCHAR: case T_PWCHAR:
|
|
705 return "Pu";
|
|
706 case T_PFCHAR: case T_PHCHAR: case T_32PCHAR: case T_32PFCHAR: case T_PCHAR:
|
|
707 return "Pg";
|
|
708 case T_PFUCHAR: case T_PHUCHAR: case T_32PUCHAR: case T_32PFUCHAR: case T_PUCHAR:
|
|
709 return "Ph";
|
|
710
|
|
711 case T_SHORT: case T_INT2:
|
|
712 return "s";
|
|
713 case T_USHORT: case T_UINT2:
|
|
714 return "t";
|
|
715 case T_PINT2: case T_PSHORT: case T_32PSHORT:
|
|
716 return "Ps";
|
|
717 case T_PUSHORT: case T_PUINT2: case T_32PUSHORT:
|
|
718 return "Pt";
|
|
719 case T_INT4:
|
|
720 case T_LONG:
|
|
721 return "i";
|
|
722 case T_UINT4:
|
|
723 case T_ULONG:
|
|
724 return "k";
|
|
725 case T_32PINT4: case T_PINT4:
|
|
726 return "Pi";
|
|
727 case T_32PUINT4: case T_PUINT4:
|
|
728 return "Pk";
|
|
729 case T_QUAD:
|
|
730 return "l";
|
|
731 case T_UQUAD:
|
|
732 return "m";
|
|
733 case T_32PQUAD: case T_PQUAD:
|
|
734 return "Pl";
|
|
735 case T_32PUQUAD: case T_PUQUAD:
|
|
736 return "Pm";
|
|
737 case T_REAL32:
|
|
738 return "f";
|
|
739 case T_32PREAL32: case T_PREAL32:
|
|
740 return "Pf";
|
|
741 case T_REAL64:
|
|
742 return "d";
|
|
743 case T_32PREAL64: case T_PREAL64:
|
|
744 return "Pd";
|
|
745 case T_REAL80:
|
|
746 return "e";
|
|
747 case T_PREAL80: case T_PFREAL80: case T_PHREAL80: case T_32PREAL80: case T_32PFREAL80:
|
|
748 return "Pe";
|
|
749 case T_BOOL08:
|
|
750 return "b";
|
|
751 case T_32PBOOL08: case T_32PFBOOL08:
|
|
752 return "Pb";
|
|
753 case T_CPLX80:
|
|
754 return "c";
|
|
755 case T_CPLX64:
|
|
756 return "r";
|
|
757 case T_CPLX32:
|
|
758 return "q";
|
|
759 case T_32PCPLX80: case T_32PFCPLX80:
|
|
760 return "Pc";
|
|
761 case T_32PCPLX64: case T_32PFCPLX64:
|
|
762 return "Pr";
|
|
763 case T_32PCPLX32: case T_32PFCPLX32:
|
|
764 return "Pq";
|
|
765 default:
|
|
766 debug DbgIO.println("mangleCVtype: unknown codeview type 0x%x", cvtype);
|
|
767 }
|
|
768 return null;
|
|
769 }
|
|
770
|
|
771
|
|
772 /**************************************************************************************************
|
|
773 Returns: size of demangled type
|
|
774 **************************************************************************************************/
|
|
775 uint sizeofMangled(string m)
|
|
776 {
|
|
777 assert(m.length > 0);
|
|
778 switch ( m[0] )
|
|
779 {
|
|
780 case 'A': return ulong.sizeof;
|
|
781 case 'G':
|
|
782 string n = m[1..$];
|
|
783 size_t count = parseNumber(n);
|
|
784 return count*sizeofMangled(n);
|
|
785 case 'P': return size_t.sizeof;
|
|
786 case 'H': return size_t.sizeof;
|
|
787 case 'v': return void.sizeof;
|
|
788 case 'b': return bit.sizeof;
|
|
789 case 'x': return bool.sizeof;
|
|
790 case 'g': return byte.sizeof;
|
|
791 case 'h': return ubyte.sizeof;
|
|
792 case 's': return short.sizeof;
|
|
793 case 't': return ushort.sizeof;
|
|
794 case 'i': return int.sizeof;
|
|
795 case 'k': return uint.sizeof;
|
|
796 case 'l': return long.sizeof;
|
|
797 case 'm': return ulong.sizeof;
|
|
798 case 'f': return float.sizeof;
|
|
799 case 'd': return double.sizeof;
|
|
800 case 'e': return real.sizeof;
|
|
801 case 'o': return ifloat.sizeof;
|
|
802 case 'p': return idouble.sizeof;
|
|
803 case 'j': return ireal.sizeof;
|
|
804 case 'q': return cfloat.sizeof;
|
|
805 case 'r': return cdouble.sizeof;
|
|
806 case 'c': return creal.sizeof;
|
|
807 case 'a': return char.sizeof;
|
|
808 case 'u': return wchar.sizeof;
|
|
809 case 'w': return dchar.sizeof;
|
|
810 case 'C':
|
|
811 case 'S':
|
|
812 string mangled_name = m[1..$],
|
|
813 name = demangleNameSkip(mangled_name);
|
|
814 if ( name in UDTsByName ) {
|
|
815 LeafClassStruc lcs = cast(LeafClassStruc)UDTsByName[name];
|
|
816 if ( lcs !is null )
|
|
817 return lcs.length.getUint;
|
|
818 LeafUnion lu = cast(LeafUnion)UDTsByName[name];
|
|
819 if ( lu !is null )
|
|
820 return lu.length.getUint;
|
|
821 }
|
|
822 assert(0, "unknown struct in sizeofMangled: "~name);
|
|
823 default:
|
|
824 assert(0, "unknown type in sizeofMangled: "~m);
|
|
825 }
|
|
826 return 0;
|
|
827 }
|
|
828
|
|
829
|
|
830 /**********************************************************************************************
|
|
831 Calculates the size of the type specified by a CodeView type index.
|
|
832 **********************************************************************************************/
|
|
833 uint sizeofCV(uint cvtype)
|
|
834 {
|
|
835 if ( cvtype >= 0x1000 )
|
|
836 {
|
|
837 uint typeindex = cvtype-0x1000;
|
|
838 if ( typeindex >= type_strings.length ) {
|
|
839 debug DbgIO.println("sizeofCV: undefined complex type 0x%x", cvtype);
|
|
840 return 0;
|
|
841 }
|
|
842 Leaf[] typestring = type_strings[typeindex];
|
|
843 while ( typestring.length > 0 )
|
|
844 {
|
|
845 switch ( typestring[0].leaf_index )
|
|
846 {
|
|
847 case LF_MODIFIER_16t:
|
|
848 LeafModifer lm = cast(LeafModifer)typestring[0];
|
|
849 assert ( lm !is null );
|
|
850 return sizeofCV(lm.index);
|
|
851 case LF_ARRAY_16t:
|
|
852 LeafArray la = cast(LeafArray)typestring[0];
|
|
853 assert ( la !is null );
|
|
854 return la.length.getUint;
|
|
855 case LF_POINTER_16t:
|
|
856 case LF_CLASS_16t:
|
|
857 return 4;
|
|
858 case LF_STRUCTURE_16t:
|
|
859 LeafClassStruc lcs = cast(LeafClassStruc)typestring[0];
|
|
860 assert ( lcs !is null );
|
|
861 return lcs.length.getUint;
|
|
862 case LF_PROCEDURE_16t:
|
|
863 case LF_METHODLIST_16t:
|
|
864 debug DbgIO.println("unmangled procedure or methodlist in complex type");
|
|
865 return 0;
|
|
866 case LF_UNION_16t:
|
|
867 LeafUnion lu = cast(LeafUnion)typestring[0];
|
|
868 return lu.length.getUint;
|
|
869 case LF_OEM_16t:
|
|
870 LeafDynArray lda = cast(LeafDynArray)typestring[0];
|
|
871 if ( lda !is null )
|
|
872 return size_t.sizeof*2;
|
|
873 LeafAssocArray laa = cast(LeafAssocArray)typestring[0];
|
|
874 if ( laa !is null )
|
|
875 return size_t.sizeof;
|
|
876 LeafDelegate ld = cast(LeafDelegate)typestring[0];
|
|
877 if ( ld !is null )
|
|
878 return size_t.sizeof*2;
|
|
879 assert(0);
|
|
880
|
|
881 default:
|
|
882 DbgIO.println("sizeofCV: unsupported complex type leaf 0x%x", typestring[0].leaf_index);
|
|
883 typestring = typestring[1..$];
|
|
884 }
|
|
885 }
|
|
886 return 0;
|
|
887 }
|
|
888
|
|
889 switch ( cvtype )
|
|
890 {
|
|
891 case T_NOTYPE:
|
|
892 return 0;
|
|
893 case T_VOID:
|
|
894 case T_CHAR:
|
|
895 case T_UCHAR:
|
|
896 case T_RCHAR:
|
|
897 case T_BOOL08:
|
|
898 return 1;
|
|
899 case T_SHORT: case T_INT2:
|
|
900 case T_USHORT: case T_UINT2:
|
|
901 case T_WCHAR:
|
|
902 return 2;
|
|
903 case T_PVOID: case T_PFVOID: case T_PHVOID: case T_32PVOID: case T_32PFVOID:
|
|
904 case T_DCHAR: case T_32PDCHAR: case T_32PFDCHAR:
|
|
905 case T_PFCHAR: case T_PHCHAR: case T_32PCHAR: case T_32PFCHAR: case T_PCHAR:
|
|
906 case T_PFUCHAR: case T_PHUCHAR: case T_32PUCHAR: case T_32PFUCHAR: case T_PUCHAR:
|
|
907 case T_PRCHAR: case T_PFRCHAR: case T_PHRCHAR: case T_32PRCHAR: case T_32PFRCHAR:
|
|
908 case T_PWCHAR: case T_PFWCHAR: case T_PHWCHAR: case T_32PWCHAR: case T_32PFWCHAR:
|
|
909 case T_PINT2: case T_PSHORT: case T_32PSHORT:
|
|
910 case T_PUSHORT: case T_PUINT2: case T_32PUSHORT:
|
|
911 case T_32PBOOL08: case T_32PFBOOL08:
|
|
912 case T_INT4:
|
|
913 case T_UINT4:
|
|
914 case T_32PINT4: case T_PINT4:
|
|
915 case T_32PUINT4: case T_PUINT4:
|
|
916 case T_32PQUAD: case T_PQUAD:
|
|
917 case T_32PUQUAD: case T_PUQUAD:
|
|
918 case T_ULONG:
|
|
919 case T_REAL32:
|
|
920 case T_32PREAL32: case T_PREAL32:
|
|
921 case T_32PREAL64: case T_PREAL64:
|
|
922 case T_PREAL80: case T_PFREAL80: case T_PHREAL80: case T_32PREAL80: case T_32PFREAL80:
|
|
923 case T_CPLX32:
|
|
924 case T_32PCPLX32: case T_32PFCPLX32:
|
|
925 case T_32PCPLX64: case T_32PFCPLX64:
|
|
926 case T_32PCPLX80: case T_32PFCPLX80:
|
|
927 return 4;
|
|
928 case T_QUAD:
|
|
929 case T_UQUAD:
|
|
930 case T_REAL64:
|
|
931 case T_CPLX64:
|
|
932 return 8;
|
|
933 case T_CPLX80:
|
|
934 case T_REAL80:
|
|
935 return 10;
|
|
936 default:
|
|
937 debug DbgIO.println("sizeofCV: unknown codeview type 0x%x", cvtype);
|
|
938 }
|
|
939 return 0;
|
|
940 }
|
|
941 }
|