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