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.parser;
|
|
7
|
|
8 import codeview.codeview;
|
|
9 import codeview.decl;
|
|
10 import codeview.coff;
|
|
11
|
|
12 import util;
|
|
13 import container;
|
|
14
|
|
15 import std.demangle;
|
|
16 import std.string;
|
|
17
|
|
18 class CodeViewException : Exception
|
|
19 {
|
|
20 this(string msg) { super(msg); }
|
|
21 }
|
|
22
|
|
23 class CodeViewParser
|
|
24 {
|
|
25 const uint cv_nb09_sig = intFromStr("NB09");
|
|
26
|
|
27 static:
|
|
28 /**********************************************************************************************
|
|
29 Parses the given CodeView section data from the given COFF image.
|
|
30 **********************************************************************************************/
|
|
31 CodeView parse(COFFImage img, ubyte[] data)
|
|
32 {
|
|
33 if ( data.length <= 0 )
|
|
34 return null;
|
|
35 CodeView cv = new CodeView;
|
|
36
|
|
37 cv.image = img;
|
|
38 cv.global_pub = new SymbolSet;
|
|
39 cv.global_sym = new SymbolSet;
|
|
40 cv.static_sym = new SymbolSet;
|
|
41
|
|
42 DataReader dr = new DataReader(data);
|
|
43 uint sig;
|
|
44 dr.read(sig);
|
|
45 if ( sig != cv_nb09_sig ) {
|
|
46 char[4] sigstr;
|
|
47 sigstr[] = (cast(char*)&sig)[0..4];
|
|
48 debug DbgIO.println("Unsupported CodeView version %s", sigstr);
|
|
49 return null;
|
|
50 }
|
|
51
|
|
52 uint lfoDir;
|
|
53 dr.read(lfoDir);
|
|
54 dr.seek(lfoDir);
|
|
55
|
|
56 ubyte[] buf;
|
|
57 dr.readA(buf, DirHeader.sizeof);
|
|
58 DirHeader* head = cast(DirHeader*)buf.ptr;
|
|
59 assert(head.cbDirHeader==DirHeader.sizeof);
|
|
60 assert(head.cbDirEntry==DirEntry.sizeof);
|
|
61
|
|
62 DirEntry[] entries;
|
|
63 dr.readA(entries, head.cDir);
|
|
64
|
|
65 foreach ( DirEntry entry; entries )
|
|
66 {
|
|
67 ubyte[] section_data;
|
|
68 dr.seek(entry.lfo);
|
|
69 dr.readA(section_data, entry.cb);
|
|
70
|
|
71 switch ( entry.subsection )
|
|
72 {
|
|
73 case sstModule:
|
|
74 Module mod = parseModule(cv, section_data);
|
|
75 assert ( entry.iMod-1 == cv.modulesByIndex.length );
|
|
76 cv.modulesByIndex ~= mod;
|
|
77 cv.modulesByName[mod.name] = mod;
|
|
78 debug(cvsections) DbgIO.println("sstModule section \"%s\"", mod.name);
|
|
79 break;
|
|
80 case sstAlignSym:
|
|
81 debug(cvsections) DbgIO.println("sstAlignSym section");
|
|
82 assert ( entry.iMod <= cv.modulesByIndex.length );
|
|
83 Module mod = cv.modulesByIndex[entry.iMod-1];
|
|
84 parseSymbols(cv, section_data, mod.symbols, true, mod);
|
|
85 break;
|
|
86 case sstSrcModule:
|
|
87 debug(cvsections) DbgIO.println("sstSrcModule section");
|
|
88 assert( entry.iMod <= cv.modulesByIndex.length );
|
|
89 parseSrcModule(cv, section_data, cv.modulesByIndex[entry.iMod-1]);
|
|
90 break;
|
|
91 case sstLibraries:
|
|
92 debug(cvsections) DbgIO.println("sstLibraries section");
|
|
93 parseLibraries(cv, section_data);
|
|
94 break;
|
|
95 case sstGlobalSym:
|
|
96 debug(cvsections) DbgIO.println("sstGlobalSym section");
|
|
97 parsePackedSymbols(cv, section_data, cv.global_sym);
|
|
98 break;
|
|
99 case sstGlobalPub:
|
|
100 debug(cvsections) DbgIO.println("sstGlobalPub section");
|
|
101 parsePackedSymbols(cv, section_data, cv.global_pub);
|
|
102 break;
|
|
103 case sstStaticSym:
|
|
104 debug(cvsections) DbgIO.println("sstStaticSym section");
|
|
105 parsePackedSymbols(cv, section_data, cv.static_sym);
|
|
106 break;
|
|
107 case sstGlobalTypes:
|
|
108 debug(cvsections) DbgIO.println("sstGlobalTypes section");
|
|
109 parseGlobalTypes(cv, section_data, entry.lfo);
|
|
110 break;
|
|
111 case sstSegMap:
|
|
112 debug(cvsections) DbgIO.println("sstSegMap section");
|
|
113 break;
|
|
114 case sstSegName:
|
|
115 debug(cvsections) DbgIO.println("sstSegName section");
|
|
116 break;
|
|
117 case sstFileIndex:
|
|
118 debug(cvsections) DbgIO.println("sstFileIndex section");
|
|
119 break;
|
|
120 case sstSymbols:
|
|
121 case sstTypes:
|
|
122 case sstPublic:
|
|
123 case sstPublicSym:
|
|
124 case sstSrcLnSeg:
|
|
125 case sstMPC:
|
|
126 case sstPreComp:
|
|
127 case sstPreCompMap:
|
|
128 case sstOffsetMap16:
|
|
129 case sstOffsetMap32:
|
|
130 debug DbgIO.println("Unprocessed CV section 0x%x", entry.subsection);
|
|
131 break;
|
|
132 default:
|
|
133 debug DbgIO.println("Unknown CV section 0x%x", entry.subsection);
|
|
134 }
|
|
135 }
|
|
136
|
|
137 updateSymbols(cv, cv.global_pub.named_symbols);
|
|
138 updateSymbols(cv, cv.global_sym.named_symbols);
|
|
139 updateSymbols(cv, cv.static_sym.named_symbols);
|
|
140 foreach ( m; cv.modulesByIndex )
|
|
141 updateSymbols(cv, m.symbols.named_symbols);
|
|
142
|
|
143 cv.globalNamedSymbols = new AVLTree!(NamedSymbol);
|
|
144 foreach ( ns; cv.global_sym.named_symbols )
|
|
145 cv.globalNamedSymbols.insert(ns);
|
|
146 foreach ( ns; cv.global_pub.named_symbols )
|
|
147 cv.globalNamedSymbols.insert(ns);
|
|
148 foreach ( ns; cv.static_sym.named_symbols )
|
|
149 cv.globalNamedSymbols.insert(ns);
|
|
150
|
|
151 cv.updateCodeblocks();
|
|
152
|
|
153 return cv;
|
|
154 }
|
|
155
|
|
156 private:
|
|
157 T min(T)(T a, T b)
|
|
158 {
|
|
159 return a<b?a:b;
|
|
160 }
|
|
161
|
|
162 /**********************************************************************************************
|
|
163 Parse a Module from the given data.
|
|
164 **********************************************************************************************/
|
|
165 Module parseModule(CodeView cv, ubyte[] data)
|
|
166 {
|
|
167 if ( data.length <= 0 )
|
|
168 throw new CodeViewException("parseModule on empty data");
|
|
169 DataReader dr = new DataReader(data);
|
|
170 Module mod = new Module(cv);
|
|
171 ubyte[] buf;
|
|
172 dr.readA(buf, ModuleHeader.sizeof);
|
|
173 mod.header = cast(ModuleHeader*)buf.ptr;
|
|
174 assert(mod.header.Style==intFromStr("CV"));
|
|
175 dr.readA!(SegInfo)(mod.seginfos, mod.header.cSeg);
|
|
176 dr.read(mod.name);
|
|
177 return mod;
|
|
178 }
|
|
179
|
|
180 /**********************************************************************************************
|
|
181
|
|
182 **********************************************************************************************/
|
|
183 void parseSymbols(CodeView cv, ubyte[] data, SymbolSet symbols, bool skip_to_ssearch=false, Module mod=null)
|
|
184 {
|
|
185 if ( data.length <= 0 )
|
|
186 throw new CodeViewException("parseSymbols on empty data");
|
|
187 DataReader dr = new DataReader(data);
|
|
188
|
|
189 uint num_sym;
|
|
190
|
|
191 // skip until S_SSEARCH symbol is found
|
|
192 while ( skip_to_ssearch && dr.available )
|
|
193 {
|
|
194 ushort length, index;
|
|
195 dr.read(length);
|
|
196 dr.read(index);
|
|
197 if ( index == SymbolIndex.S_SSEARCH ) {
|
|
198 dr.relseek(-4);
|
|
199 break;
|
|
200 }
|
|
201 }
|
|
202
|
|
203 uint sym_off;
|
|
204 bool expecting_arguments=false;
|
|
205 ScopeSymbol[uint] scope_syms;
|
|
206 ScopeSymbol parent_scope;
|
|
207
|
|
208 while ( dr.available )
|
|
209 {
|
|
210 ushort length, index;
|
|
211 uint next_symbol, symbol_start;
|
|
212
|
|
213 void addSymbol(Symbol sym)
|
|
214 {
|
|
215 assert( !expecting_arguments || parent_scope !is null );
|
|
216 if ( parent_scope !is null )
|
|
217 {
|
|
218 if ( expecting_arguments )
|
|
219 (cast(ProcedureSymbol)parent_scope).arguments.add(sym);
|
|
220 else
|
|
221 parent_scope.symbols.add(sym);
|
|
222 }
|
|
223 else
|
|
224 symbols.add(sym);
|
|
225 }
|
|
226
|
|
227 symbol_start = dr.cursor;
|
|
228 dr.read(length);
|
|
229 next_symbol = dr.cursor+length;
|
|
230 if ( next_symbol > dr.data.length ) {
|
|
231 debug DbgIO.println("WARNING: length %d for symbol exceeds block size %d - skipping section", length, dr.data.length);
|
|
232 if ( mod !is null )
|
|
233 debug DbgIO.println("in module %s", mod.name);
|
|
234 return;
|
|
235 }
|
|
236 dr.read(index);
|
|
237
|
|
238 ubyte[] buf;
|
|
239 switch ( index )
|
|
240 {
|
|
241 case SymbolIndex.S_COMPILE:
|
|
242 ubyte machine,
|
|
243 language;
|
|
244 ushort flags;
|
|
245 dr.read(machine);
|
|
246 dr.read(language);
|
|
247 dr.read(flags);
|
|
248 string version_string;
|
|
249 dr.read(version_string);
|
|
250 debug(cvsymbols) DbgIO.println("machine: 0x%x, language: %d, flags: 0x%x, version: %s", machine, language, flags, version_string);
|
|
251 break;
|
|
252 case SymbolIndex.S_SSEARCH:
|
|
253 dr.read(sym_off);
|
|
254 ushort pe_section;
|
|
255 dr.read(pe_section);
|
|
256 if ( mod !is null )
|
|
257 mod.pe_section = pe_section;
|
|
258 break;
|
|
259 case SymbolIndex.S_END:
|
|
260 debug(cvsymbols) DbgIO.println("S_END");
|
|
261 if ( parent_scope !is null )
|
|
262 {
|
|
263 if ( parent_scope.parent_scope !is null )
|
|
264 parent_scope = parent_scope.parent_scope;
|
|
265 else
|
|
266 parent_scope = null;
|
|
267 }
|
|
268 else {
|
|
269 debug DbgIO.println("S_END with no active parent scope");
|
|
270 }
|
|
271 expecting_arguments = false;
|
|
272 break;
|
|
273 case SymbolIndex.S_ENDARG:
|
|
274 expecting_arguments = false;
|
|
275 break;
|
|
276 case SymbolIndex.S_RETURN:
|
|
277 dr.readA(buf, CVReturnSymbol.sizeof);
|
|
278 ReturnSymbol rsym = new ReturnSymbol(cast(CVReturnSymbol*)buf.ptr);
|
|
279 if ( rsym.cvdata.style == 1 ) {
|
|
280 ubyte count;
|
|
281 dr.read(count);
|
|
282 dr.readA!(ubyte)(rsym.registers, count);
|
|
283 }
|
|
284 ProcedureSymbol psym = cast(ProcedureSymbol)parent_scope;
|
|
285 assert(psym !is null);
|
|
286 psym.return_sym = rsym;
|
|
287 break;
|
|
288 case SymbolIndex.S_LPROC32:
|
|
289 case SymbolIndex.S_GPROC32:
|
|
290 dr.readA(buf, CVProcedureSymbol.sizeof);
|
|
291 ProcedureSymbol psym = new ProcedureSymbol(cast(SymbolIndex)index, symbol_start, cast(CVProcedureSymbol*)buf.ptr);
|
|
292 dr.read(psym.mangled_name);
|
|
293 psym.name_notype = demangleName(psym.mangled_name);
|
|
294 psym.name_type = demangle(psym.mangled_name);
|
|
295 debug(cvsymbols) DbgIO.println("PROC32 %s (%s) s:%x o:%x", psym.name_type, psym.name_notype, psym.cvdata.segment, psym.cvdata.offset);
|
|
296 scope_syms[symbol_start] = psym;
|
|
297 addSymbol(psym);
|
|
298 assert ( parent_scope is null || psym.cvdata.pParent==parent_scope.lfo );
|
|
299 if ( psym.cvdata.pParent in scope_syms )
|
|
300 {
|
|
301 psym.parent_scope = scope_syms[psym.cvdata.pParent];
|
|
302 psym.parent_scope.symbols.add(psym);
|
|
303 }
|
|
304 parent_scope = psym;
|
|
305 expecting_arguments = true;
|
|
306 break;
|
|
307 case SymbolIndex.S_BPREL32:
|
|
308 dr.readA(buf, CVStackSymbol.sizeof);
|
|
309 StackSymbol stsym = new StackSymbol(cast(CVStackSymbol*)buf.ptr);
|
|
310 dr.read(stsym.mangled_name);
|
|
311 stsym.name_notype = demangleName(stsym.mangled_name);
|
|
312 stsym.name_type = demangle(stsym.mangled_name);
|
|
313 debug(cvsymbols) DbgIO.println(
|
|
314 "BPREL32 %s%s [%s] 0x%x o:%d", parent_scope !is null?"("~parent_scope.name_type~") ":"",
|
|
315 stsym.name_type, stsym.name_notype, stsym.cvtype, cast(int)stsym.cvdata.offset
|
|
316 );
|
|
317 addSymbol(stsym);
|
|
318 break;
|
|
319 case SymbolIndex.S_LDATA32:
|
|
320 case SymbolIndex.S_GDATA32:
|
|
321 case SymbolIndex.S_PUB32:
|
|
322 dr.readA(buf, CVDataSymbol.sizeof);
|
|
323 DataSymbol dsym = new DataSymbol(cast(SymbolIndex)index, cast(CVDataSymbol*)buf.ptr);
|
|
324 dr.read(dsym.mangled_name);
|
|
325 dsym.name_notype = demangleName(dsym.mangled_name);
|
|
326 dsym.name_type = demangle(dsym.mangled_name);
|
|
327 debug(cvsymbols) DbgIO.println("[LG]DATA|PUB32 %s (%s) s:%x o:%x t:0x%x", dsym.name_type, dsym.name_notype, dsym.cvdata.segment, dsym.offset, dsym.cvtype);
|
|
328 addSymbol(dsym);
|
|
329 break;
|
|
330 case SymbolIndex.S_ALIGN:
|
|
331 debug(cvsymbols) DbgIO.println("ALIGN");
|
|
332 break;
|
|
333 case SymbolIndex.S_UDT:
|
|
334 UserDefinedType udt = new UserDefinedType;
|
|
335 dr.read(udt.type_index);
|
|
336 dr.read(udt.name);
|
|
337 cv.udtypes ~= udt;
|
|
338 break;
|
|
339 case SymbolIndex.S_PROCREF:
|
|
340 case SymbolIndex.S_DATAREF:
|
|
341 break;
|
|
342 case SymbolIndex.S_REGISTER:
|
|
343 case SymbolIndex.S_CONSTANT:
|
|
344 case SymbolIndex.S_SKIP:
|
|
345 case SymbolIndex.S_CVRESERVE:
|
|
346 case SymbolIndex.S_OBJNAME:
|
|
347 case SymbolIndex.S_COBOLUDT:
|
|
348 case SymbolIndex.S_MANYREG:
|
|
349 case SymbolIndex.S_ENTRYTHIS:
|
|
350 case SymbolIndex.S_BPREL16:
|
|
351 case SymbolIndex.S_LDATA16:
|
|
352 case SymbolIndex.S_PUB16:
|
|
353 case SymbolIndex.S_LPROC16:
|
|
354 case SymbolIndex.S_GPROC16:
|
|
355 case SymbolIndex.S_THUNK16:
|
|
356 case SymbolIndex.S_BLOCK16:
|
|
357 case SymbolIndex.S_WITH16:
|
|
358 case SymbolIndex.S_LABEL16:
|
|
359 case SymbolIndex.S_CEXMODEL16:
|
|
360 case SymbolIndex.S_VFTPATH16:
|
|
361 case SymbolIndex.S_REGREL16:
|
|
362 case SymbolIndex.S_GDATA16:
|
|
363 case SymbolIndex.S_THUNK32:
|
|
364 case SymbolIndex.S_BLOCK32:
|
|
365 case SymbolIndex.S_WITH32:
|
|
366 case SymbolIndex.S_LABEL32:
|
|
367 case SymbolIndex.S_CEXMODEL32:
|
|
368 case SymbolIndex.S_VFTPATH32:
|
|
369 case SymbolIndex.S_REGREL32:
|
|
370 case SymbolIndex.S_LTHREAD32:
|
|
371 case SymbolIndex.S_GTHREAD32:
|
|
372 debug DbgIO.println("unprocessed symbol index 0x%x", index);
|
|
373 break;
|
|
374 default:
|
|
375 debug DbgIO.println("unknown symbol index 0x%x", index);
|
|
376 }
|
|
377
|
|
378 dr.seek(next_symbol);
|
|
379 }
|
|
380 }
|
|
381
|
|
382 /**********************************************************************************************
|
|
383
|
|
384 **********************************************************************************************/
|
|
385 void parseSrcModule(CodeView cv, ubyte[] data, Module mod)
|
|
386 {
|
|
387 if ( data.length <= 0 )
|
|
388 throw new CodeViewException("parseSrcModule on empty data");
|
|
389 DataReader dr = new DataReader(data);
|
|
390 ushort cFile, cSeg;
|
|
391 dr.read(cFile);
|
|
392 dr.read(cSeg);
|
|
393
|
|
394 SourceModule smod = new SourceModule;
|
|
395 mod.source_module = smod;
|
|
396 cv.source_modules ~= smod;
|
|
397
|
|
398 uint[] baseSrcFile,
|
|
399 start_end;
|
|
400 ushort[] seginds;
|
|
401 dr.readA(baseSrcFile, cast(uint)cFile);
|
|
402 dr.readA(start_end, cast(uint)cSeg*2);
|
|
403 dr.readA(seginds, cast(uint)cSeg);
|
|
404 debug(cvparser) DbgIO.println("Module %s files=%d segs=%d", mod.name, cFile, cSeg);
|
|
405
|
|
406 foreach ( fileoffset; baseSrcFile )
|
|
407 {
|
|
408 dr.seek(fileoffset);
|
|
409 dr.read(cSeg);
|
|
410 ushort pad;
|
|
411 dr.read(pad);
|
|
412
|
|
413 SourceFile file = new SourceFile;
|
|
414 file.source_module = smod;
|
|
415 uint[] baseSrcLn;
|
|
416 dr.readA(baseSrcLn, cast(uint)cSeg);
|
|
417 start_end = null;
|
|
418 dr.readA(start_end, cast(uint)cSeg*2);
|
|
419 dr.read(file.name);
|
|
420 debug(cvparser) DbgIO.println("\tFile %s segs=%d", file.name, cSeg);
|
|
421 smod.files ~= file;
|
|
422
|
|
423 foreach ( int i, segoff; baseSrcLn )
|
|
424 {
|
|
425 dr.seek(segoff);
|
|
426 SourceSegment seg = new SourceSegment;
|
|
427 file.segments ~= seg;
|
|
428 seg.file = file;
|
|
429
|
|
430 seg.start = start_end[i*2];
|
|
431 seg.end = start_end[i*2+1];
|
|
432
|
|
433 dr.read(pad); // segment index
|
|
434 ushort cPair;
|
|
435 dr.read(cPair);
|
|
436 debug(cvparser) DbgIO.println("\t\tSegment %d lines=%d", file.segments.length-1, cPair);
|
|
437
|
|
438 uint[] offset;
|
|
439 ushort[] linenumber;
|
|
440 dr.readA(offset, cast(uint)cPair);
|
|
441 dr.readA(linenumber, cast(uint)cPair);
|
|
442
|
|
443 foreach ( int j, l; linenumber ) {
|
|
444 CodeBlock cb = new CodeBlock(offset[j], l, seg);
|
|
445 file.blocks_by_line[l] ~= cb;
|
|
446 debug(cvparser)
|
|
447 {
|
|
448 bool inserted = cv.codeblocks.insert(cb);
|
|
449 if ( !inserted )
|
|
450 DbgIO.println("failed to insert block %s, already exists", cb);
|
|
451 }
|
|
452 else
|
|
453 cv.codeblocks.insert(cb);
|
|
454 }
|
|
455 }
|
|
456
|
|
457 file.lines = file.blocks_by_line.keys.dup.sort;
|
|
458 }
|
|
459 }
|
|
460
|
|
461 /**********************************************************************************************
|
|
462
|
|
463 **********************************************************************************************/
|
|
464 void parseLibraries(CodeView cv, ubyte[] data)
|
|
465 {
|
|
466 if ( data.length <= 0 )
|
|
467 throw new CodeViewException("parseLibraries on empty data");
|
|
468 DataReader dr = new DataReader(data);
|
|
469 while ( dr.available ) {
|
|
470 string lib;
|
|
471 dr.read(lib);
|
|
472 cv.libraries ~= lib;
|
|
473 }
|
|
474 }
|
|
475
|
|
476 /**********************************************************************************************
|
|
477
|
|
478 **********************************************************************************************/
|
|
479 void parsePackedSymbols(CodeView cv, ubyte[] data, SymbolSet symbols)
|
|
480 {
|
|
481 if ( data.length <= 0 )
|
|
482 throw new CodeViewException("parsePackedSymbols on empty data");
|
|
483 DataReader dr = new DataReader(data);
|
|
484
|
|
485 ubyte[] buf;
|
|
486 dr.readA(buf, PackedSymbolsHeader.sizeof);
|
|
487 PackedSymbolsHeader* gsh = cast(PackedSymbolsHeader*)buf.ptr;
|
|
488
|
|
489 dr.readA(buf, gsh.cbSymbol);
|
|
490 parseSymbols(cv, buf, symbols);
|
|
491 }
|
|
492
|
|
493 /**********************************************************************************************
|
|
494
|
|
495 **********************************************************************************************/
|
|
496 void parseGlobalTypes(CodeView cv, ubyte[] data, uint absolute_offset)
|
|
497 {
|
|
498 DataReader dr = new DataReader(data);
|
|
499 uint flags,
|
|
500 cType;
|
|
501 uint[] offType;
|
|
502 dr.read(flags);
|
|
503 dr.read(cType);
|
|
504 dr.readA(offType, cType);
|
|
505
|
|
506 uint base = dr.cursor;
|
|
507 foreach ( off; offType )
|
|
508 {
|
|
509 dr.seek(base+off);
|
|
510 ushort len;
|
|
511 dr.read(len);
|
|
512 ubyte[] buf;
|
|
513 dr.readA(buf, cast(uint)len);
|
|
514 cv.type_strings ~= parseTypeString(cv, buf);
|
|
515 }
|
|
516 }
|
|
517
|
|
518 /**********************************************************************************************
|
|
519
|
|
520 **********************************************************************************************/
|
|
521 Leaf[] parseTypeString(CodeView cv, ubyte[] data)
|
|
522 {
|
|
523 debug(cvdump) foreach ( b; data )
|
|
524 DbgIO.print("%02x ", b);
|
|
525 debug(cvdump) DbgIO.println("");
|
|
526 DataReader dr = new DataReader(data);
|
|
527 Leaf[] leafs;
|
|
528 bool first = true;
|
|
529 while ( dr.available )
|
|
530 {
|
|
531 ushort leaf_index;
|
|
532 dr.read(leaf_index);
|
|
533 Leaf l;
|
|
534 // debug(cvparser) DbgIO.println("parsing 0x%x", leaf_index);
|
|
535 switch ( leaf_index )
|
|
536 {
|
|
537 case LF_MODIFIER_16t:
|
|
538 LeafModifer lm = new LeafModifer;
|
|
539 l = lm;
|
|
540 dr.read(lm.attribute);
|
|
541 dr.read(lm.index);
|
|
542 break;
|
|
543 case LF_POINTER_16t:
|
|
544 LeafPointer lp = new LeafPointer;
|
|
545 l = lp;
|
|
546 dr.read(lp.attribute);
|
|
547 dr.read(lp.type);
|
|
548 switch ( lp.attribute&0x1f )
|
|
549 {
|
|
550 case 0:
|
|
551 case 10:
|
|
552 break;
|
|
553 default:
|
|
554 debug DbgIO.println("unprocessed pointer type: 0x%x", lp.attribute);
|
|
555 assert(0);
|
|
556 }
|
|
557 break;
|
|
558 case LF_ARRAY_16t:
|
|
559 LeafArray la = new LeafArray;
|
|
560 l = la;
|
|
561 dr.read(la.elemtype);
|
|
562 dr.read(la.idxtype);
|
|
563 la.length = parseNumericLeaf(dr);
|
|
564 dr.read(la.name);
|
|
565 debug(cvparser) DbgIO.println("LF_ARRAY: %d 0x%x", la.length.getUint, 0x1000+cv.type_strings.length);
|
|
566 break;
|
|
567 case LF_PROCEDURE_16t:
|
|
568 LeafProcedure lp = new LeafProcedure;
|
|
569 l = lp;
|
|
570 dr.read(lp.rvtype);
|
|
571 dr.read(lp.call);
|
|
572 dr.read(lp.reserved);
|
|
573 dr.read(lp.cParms);
|
|
574 dr.read(lp.arglist);
|
|
575 break;
|
|
576 case LF_MFUNCTION_16t:
|
|
577 LeafMFunction lmf = new LeafMFunction;
|
|
578 l = lmf;
|
|
579 dr.read(lmf.rvtype);
|
|
580 dr.read(lmf._class);
|
|
581 dr.read(lmf._this);
|
|
582 dr.read(lmf.call);
|
|
583 dr.read(lmf.reserved);
|
|
584 dr.read(lmf.cParms);
|
|
585 dr.read(lmf.arglist);
|
|
586 dr.read(lmf.thisadjust);
|
|
587 break;
|
|
588 case LF_VTSHAPE:
|
|
589 LeafVTShape lvts = new LeafVTShape;
|
|
590 l = lvts;
|
|
591 ushort count;
|
|
592 dr.read(count);
|
|
593 dr.readA(lvts.descriptor, cast(uint)(count+1)>>1);
|
|
594 // skip rest of typestring
|
|
595 dr.seek(dr.data.length);
|
|
596 break;
|
|
597 case LF_CLASS_16t:
|
|
598 case LF_STRUCTURE_16t:
|
|
599 LeafClassStruc lcs = new LeafClassStruc;
|
|
600 l = lcs;
|
|
601 dr.read(lcs.count);
|
|
602 dr.read(lcs.field);
|
|
603 dr.read(lcs.property);
|
|
604 dr.read(lcs.dList);
|
|
605 dr.read(lcs.vshape);
|
|
606 lcs.length = parseNumericLeaf(dr);
|
|
607 dr.read(lcs.name);
|
|
608 lcs.type = cast(ushort)(0x1000+cv.type_strings.length);
|
|
609 debug(cvparser) DbgIO.println(
|
|
610 "%s 0x%x '%s' fl: 0x%x prop: 0x%x, length=0x%x", leaf_index==LF_CLASS_16t?"class":"struct",
|
|
611 lcs.type, lcs.name, lcs.field, lcs.property, lcs.length.getUint
|
|
612 );
|
|
613
|
|
614 cv.UDTsByName[lcs.name] = lcs;
|
|
615 break;
|
|
616 case LF_ENUM_16t:
|
|
617 LeafEnum le = new LeafEnum;
|
|
618 l = le;
|
|
619 dr.read(le.count);
|
|
620 dr.read(le.type);
|
|
621 dr.read(le.field);
|
|
622 dr.read(le.property);
|
|
623 dr.read(le.name);
|
|
624 debug(cvparser) DbgIO.println(
|
|
625 "enum 0x%x '%s' type: 0x%x fl: 0x%x prop: 0x%x", 0x1000+cv.type_strings.length, le.name, le.type, le.field, le.property
|
|
626 );
|
|
627 cv.UDTsByName[le.name] = le;
|
|
628 break;
|
|
629 case LF_UNION_16t:
|
|
630 LeafUnion lu = new LeafUnion;
|
|
631 l = lu;
|
|
632 dr.read(lu.count);
|
|
633 dr.read(lu.field);
|
|
634 dr.read(lu.property);
|
|
635 lu.length = parseNumericLeaf(dr);
|
|
636 dr.read(lu.name);
|
|
637 // skip rest of typestring
|
|
638 dr.seek(dr.data.length);
|
|
639 debug(cvparser) DbgIO.println("Union '%s' count %d fields 0x%x length 0x%x", lu.name, lu.count, lu.field, lu.length.getUint);
|
|
640 cv.UDTsByName[lu.name] = lu;
|
|
641 break;
|
|
642 case LF_OEM_16t:
|
|
643 ushort oem;
|
|
644 dr.read(oem);
|
|
645 assert(oem == OEM_DIGITALMARS);
|
|
646 dr.read(oem);
|
|
647 ushort count;
|
|
648 dr.read(count);
|
|
649 assert(count == 2);
|
|
650 switch ( oem )
|
|
651 {
|
|
652 case D_DYN_ARRAY:
|
|
653 LeafDynArray lda = new LeafDynArray;
|
|
654 l = lda;
|
|
655 dr.read(lda.index_type);
|
|
656 dr.read(lda.elem_type);
|
|
657 debug(cvparser) DbgIO.println("Dynamic array index_type 0x%x elem_type 0x%x", lda.index_type, lda.elem_type);
|
|
658 break;
|
|
659 case D_ASSOC_ARRAY:
|
|
660 LeafAssocArray laa = new LeafAssocArray;
|
|
661 l = laa;
|
|
662 dr.read(laa.key_type);
|
|
663 dr.read(laa.elem_type);
|
|
664 debug(cvparser) DbgIO.println("Associativ array key_type 0x%x elem_type 0x%x", laa.key_type, laa.elem_type);
|
|
665 break;
|
|
666 default:
|
|
667 LeafDelegate ld = new LeafDelegate;
|
|
668 l = ld;
|
|
669 dr.read(ld.this_type);
|
|
670 dr.read(ld.func_type);
|
|
671 debug(cvparser) DbgIO.println("Delegate this_type 0x%x func_type 0x%x", ld.this_type, ld.func_type);
|
|
672 break;
|
|
673 }
|
|
674 break;
|
|
675
|
|
676 case LF_ARGLIST_16t:
|
|
677 LeafArgList lal = new LeafArgList;
|
|
678 l = lal;
|
|
679 dr.read(lal.argcount);
|
|
680 dr.readA(lal.indeces, cast(uint)lal.argcount);
|
|
681 break;
|
|
682 case LF_FIELDLIST_16t:
|
|
683 debug(cvparser) DbgIO.println("fieldlist 0x%x", 0x1000+cv.type_strings.length);
|
|
684 LeafFieldList lfl = new LeafFieldList;
|
|
685 l = lfl;
|
|
686 while ( dr.available )
|
|
687 lfl.fields ~= parseSubfield(dr);
|
|
688 // skip rest of typestring
|
|
689 dr.seek(dr.data.length);
|
|
690 break;
|
|
691 case LF_DERIVED_16t:
|
|
692 LeafDerived ld = new LeafDerived;
|
|
693 l = ld;
|
|
694 ushort count;
|
|
695 dr.read(count);
|
|
696 dr.readA(ld.types, cast(uint)count);
|
|
697 break;
|
|
698 case LF_METHODLIST_16t:
|
|
699 LeafMethodList lml = new LeafMethodList;
|
|
700 l = lml;
|
|
701 // skip rest of typestring
|
|
702 dr.seek(dr.data.length);
|
|
703 break;
|
|
704 default:
|
|
705 debug DbgIO.println("unprocessed leaf index 0x%x at 0x%x", leaf_index, dr.cursor-2);
|
|
706 l = new Leaf;
|
|
707 }
|
|
708 assert ( l !is null );
|
|
709 l.leaf_index = leaf_index;
|
|
710 leafs ~= l;
|
|
711 }
|
|
712 return leafs;
|
|
713 }
|
|
714
|
|
715 /**********************************************************************************************
|
|
716
|
|
717 **********************************************************************************************/
|
|
718 Leaf parseSubfield(DataReader dr)
|
|
719 {
|
|
720 ushort leaf_index;
|
|
721 dr.read(leaf_index);
|
|
722 Leaf l;
|
|
723 switch ( leaf_index )
|
|
724 {
|
|
725 case LF_BCLASS_16t:
|
|
726 LeafBaseClass lbc = new LeafBaseClass;
|
|
727 l = lbc;
|
|
728 dr.read(lbc.type);
|
|
729 dr.read(lbc.attribute);
|
|
730 lbc.offset = parseNumericLeaf(dr);
|
|
731 debug(cvparser) DbgIO.println("SFbclass");
|
|
732 break;
|
|
733 case LF_MEMBER_16t:
|
|
734 LeafMember lm = new LeafMember;
|
|
735 l = lm;
|
|
736 dr.read(lm.type);
|
|
737 dr.read(lm.attribute);
|
|
738 lm.offset = parseNumericLeaf(dr);
|
|
739 dr.read(lm.name);
|
|
740 debug(cvparser) DbgIO.println("SFmember: %s", lm.name);
|
|
741 break;
|
|
742 case LF_METHOD_16t:
|
|
743 LeafMethod lm = new LeafMethod;
|
|
744 l = lm;
|
|
745 dr.read(lm.count);
|
|
746 dr.read(lm.mList);
|
|
747 dr.read(lm.name);
|
|
748 debug(cvparser) DbgIO.println("SFmethod: %d 0x%x %s", lm.count, lm.mList, lm.name);
|
|
749 break;
|
|
750 case LF_ENUMERATE:
|
|
751 LeafEnumNameValue le = new LeafEnumNameValue;
|
|
752 l = le;
|
|
753 dr.read(le.attribute);
|
|
754 le.value = parseNumericLeaf(dr);
|
|
755 dr.read(le.name);
|
|
756 debug(cvparser) DbgIO.println("SFenumerate: %s %d", le.name, le.value.getUint);
|
|
757 break;
|
|
758 case LF_NESTTYPE_16t:
|
|
759 LeafNestedType ln = new LeafNestedType;
|
|
760 l = ln;
|
|
761 dr.read(ln.index);
|
|
762 dr.read(ln.name);
|
|
763 debug(cvparser) DbgIO.println("SFnesttype: %s", ln.name);
|
|
764 break;
|
|
765 case LF_STMEMBER_16t:
|
|
766 LeafStaticDataMember ls = new LeafStaticDataMember;
|
|
767 l = ls;
|
|
768 dr.read(ls.type);
|
|
769 dr.read(ls.attribute);
|
|
770 dr.read(ls.name);
|
|
771 debug(cvparser) DbgIO.println("SFstmember: %s", ls.name);
|
|
772 break;
|
|
773 case LF_SKIP_16t:
|
|
774 dr.seek(dr.data.length);
|
|
775 debug(cvparser) DbgIO.println("SFskip");
|
|
776 break;
|
|
777 default:
|
|
778 debug DbgIO.println("unprocessed subfield index 0x%x", leaf_index);
|
|
779 l = new Leaf;
|
|
780 }
|
|
781 if ( dr.available )
|
|
782 {
|
|
783 ubyte pad;
|
|
784 dr.peek(pad);
|
|
785 if ( pad > 0xf0 )
|
|
786 dr.relseek(pad&0xf);
|
|
787 }
|
|
788 assert ( l !is null );
|
|
789 l.leaf_index = leaf_index;
|
|
790 return l;
|
|
791 }
|
|
792
|
|
793 /**********************************************************************************************
|
|
794
|
|
795 **********************************************************************************************/
|
|
796 LeafNumeric parseNumericLeaf(DataReader dr)
|
|
797 {
|
|
798 LeafNumeric nl = new LeafNumeric;
|
|
799 dr.read(nl.leaf_index);
|
|
800 if ( nl.leaf_index < 0x8000 ) {
|
|
801 nl.us = cast(ushort)nl.leaf_index;
|
|
802 nl.leaf_index = LF_USHORT;
|
|
803 }
|
|
804 else switch ( nl.leaf_index )
|
|
805 {
|
|
806 case LF_VARSTRING: dr.read(nl.str); break;
|
|
807 case LF_CHAR: dr.read(nl.c); break;
|
|
808 case LF_SHORT: dr.read(nl.s); break;
|
|
809 case LF_USHORT: dr.read(nl.us); break;
|
|
810 case LF_LONG: dr.read(nl.i); break;
|
|
811 case LF_ULONG: dr.read(nl.ui); break;
|
|
812 case LF_REAL32: dr.read(nl.f); break;
|
|
813 case LF_REAL64: dr.read(nl.d); break;
|
|
814 case LF_REAL80: dr.read(nl.r); break;
|
|
815 case LF_QUADWORD: dr.read(nl.l); break;
|
|
816 case LF_UQUADWORD: dr.read(nl.ul); break;
|
|
817 case LF_COMPLEX32: dr.read(nl.cf); break;
|
|
818 case LF_COMPLEX64:
|
|
819 case LF_COMPLEX80:
|
|
820 case LF_REAL48:
|
|
821 case LF_COMPLEX128:
|
|
822 case LF_REAL128:
|
|
823 default:
|
|
824 debug DbgIO.println("unknown leaftype %x", nl.leaf_index);
|
|
825 }
|
|
826 return nl;
|
|
827 }
|
|
828
|
|
829 /**********************************************************************************************
|
|
830 Updates symbol size fields and mangled_names. Since both can only
|
|
831 be determined fully after sstGlobalTypes have been read.
|
|
832 **********************************************************************************************/
|
|
833 void updateSymbols(CodeView cv, NamedSymbol[] syms)
|
|
834 {
|
|
835 foreach ( s; syms )
|
|
836 {
|
|
837 if ( s.mangled_name is null || s.mangled_name.length <= 0 )
|
|
838 s.mangled_name = cv.mangle(s);
|
|
839
|
|
840 ScopeSymbol scs = cast(ScopeSymbol)s;
|
|
841 if ( scs !is null )
|
|
842 updateSymbols(cv, scs.symbols.named_symbols);
|
|
843 ProcedureSymbol ps = cast(ProcedureSymbol)s;
|
|
844 if ( ps !is null )
|
|
845 updateSymbols(cv, ps.arguments.named_symbols);
|
|
846
|
|
847 string type = cv.mangleType(s);
|
|
848 if ( type is null )
|
|
849 continue;
|
|
850
|
|
851 DataSymbol ds = cast(DataSymbol)s;
|
|
852 if ( ds !is null )
|
|
853 ds.size = cv.sizeofCV(ds.cvdata.type);
|
|
854 else
|
|
855 {
|
|
856 StackSymbol ss = cast(StackSymbol)s;
|
|
857 if ( ss !is null )
|
|
858 ss.size = cv.sizeofCV(ss.cvdata.type);
|
|
859 }
|
|
860 }
|
|
861 }
|
|
862 }
|