diff src/codeview/parser.d @ 1:4a9dcbd9e54f

-files of 0.13 beta -fixes so that it now compiles with the current dmd version
author marton@basel.hu
date Tue, 05 Apr 2011 20:44:01 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/codeview/parser.d	Tue Apr 05 20:44:01 2011 +0200
@@ -0,0 +1,862 @@
+/*  Ddbg - Win32 Debugger for the D programming language
+ *  Copyright (c) 2007 Jascha Wetzel
+ *  All rights reserved. See LICENSE.TXT for details.
+ */
+
+module codeview.parser;
+
+import codeview.codeview;
+import codeview.decl;
+import codeview.coff;
+
+import util;
+import container;
+
+import std.demangle;
+import std.string;
+
+class CodeViewException : Exception
+{
+	this(string msg) { super(msg); }
+}
+
+class CodeViewParser
+{
+	const uint cv_nb09_sig = intFromStr("NB09");
+
+static:
+    /**********************************************************************************************
+        Parses the given CodeView section data from the given COFF image.
+    **********************************************************************************************/
+	CodeView parse(COFFImage img, ubyte[] data)
+	{
+		if ( data.length <= 0 )
+			return null;
+		CodeView cv = new CodeView;
+
+		cv.image = img;
+		cv.global_pub = new SymbolSet;
+		cv.global_sym = new SymbolSet;
+		cv.static_sym = new SymbolSet;
+
+		DataReader dr = new DataReader(data);
+		uint sig;
+		dr.read(sig);
+		if ( sig != cv_nb09_sig ) {
+			char[4] sigstr;
+			sigstr[] = (cast(char*)&sig)[0..4];
+			debug DbgIO.println("Unsupported CodeView version %s", sigstr);
+			return null;
+		}
+
+		uint lfoDir;
+		dr.read(lfoDir);
+		dr.seek(lfoDir);
+
+		ubyte[] buf;
+		dr.readA(buf, DirHeader.sizeof);
+		DirHeader* head = cast(DirHeader*)buf.ptr;
+		assert(head.cbDirHeader==DirHeader.sizeof);
+		assert(head.cbDirEntry==DirEntry.sizeof);
+
+		DirEntry[] entries;
+		dr.readA(entries, head.cDir);
+
+		foreach ( DirEntry entry; entries )
+		{
+			ubyte[] section_data;
+			dr.seek(entry.lfo);
+			dr.readA(section_data, entry.cb);
+
+			switch ( entry.subsection )
+			{
+				case sstModule:
+					Module mod = parseModule(cv, section_data);
+					assert ( entry.iMod-1 == cv.modulesByIndex.length );
+					cv.modulesByIndex ~= mod;
+					cv.modulesByName[mod.name] = mod;
+					debug(cvsections) DbgIO.println("sstModule section \"%s\"", mod.name);
+					break;
+				case sstAlignSym:
+					debug(cvsections) DbgIO.println("sstAlignSym section");
+					assert ( entry.iMod <= cv.modulesByIndex.length );
+					Module mod = cv.modulesByIndex[entry.iMod-1];
+					parseSymbols(cv, section_data, mod.symbols, true, mod);
+					break;
+				case sstSrcModule:
+					debug(cvsections) DbgIO.println("sstSrcModule section");
+					assert( entry.iMod <= cv.modulesByIndex.length );
+					parseSrcModule(cv, section_data, cv.modulesByIndex[entry.iMod-1]);
+					break;
+				case sstLibraries:
+					debug(cvsections) DbgIO.println("sstLibraries section");
+					parseLibraries(cv, section_data);
+					break;
+				case sstGlobalSym:
+					debug(cvsections) DbgIO.println("sstGlobalSym section");
+					parsePackedSymbols(cv, section_data, cv.global_sym);
+					break;
+				case sstGlobalPub:
+					debug(cvsections) DbgIO.println("sstGlobalPub section");
+					parsePackedSymbols(cv, section_data, cv.global_pub);
+					break;
+				case sstStaticSym:
+					debug(cvsections) DbgIO.println("sstStaticSym section");
+					parsePackedSymbols(cv, section_data, cv.static_sym);
+					break;
+				case sstGlobalTypes:
+					debug(cvsections) DbgIO.println("sstGlobalTypes section");
+					parseGlobalTypes(cv, section_data, entry.lfo);
+					break;
+				case sstSegMap:
+					debug(cvsections) DbgIO.println("sstSegMap section");
+					break;
+				case sstSegName:
+					debug(cvsections) DbgIO.println("sstSegName section");
+					break;
+				case sstFileIndex:
+					debug(cvsections) DbgIO.println("sstFileIndex section");
+					break;
+				case sstSymbols:
+				case sstTypes:
+				case sstPublic:
+				case sstPublicSym:
+				case sstSrcLnSeg:
+				case sstMPC:
+				case sstPreComp:
+				case sstPreCompMap:
+				case sstOffsetMap16:
+				case sstOffsetMap32:
+					debug DbgIO.println("Unprocessed CV section 0x%x", entry.subsection);
+					break;
+				default:
+					debug DbgIO.println("Unknown CV section 0x%x", entry.subsection);
+			}
+		}
+
+		updateSymbols(cv, cv.global_pub.named_symbols);
+		updateSymbols(cv, cv.global_sym.named_symbols);
+		updateSymbols(cv, cv.static_sym.named_symbols);
+		foreach ( m; cv.modulesByIndex )
+			updateSymbols(cv, m.symbols.named_symbols);
+
+        cv.globalNamedSymbols = new AVLTree!(NamedSymbol);
+        foreach ( ns; cv.global_sym.named_symbols )
+            cv.globalNamedSymbols.insert(ns);
+        foreach ( ns; cv.global_pub.named_symbols )
+            cv.globalNamedSymbols.insert(ns);
+        foreach ( ns; cv.static_sym.named_symbols )
+            cv.globalNamedSymbols.insert(ns);
+
+        cv.updateCodeblocks();
+
+		return cv;
+	}
+
+private:
+    T min(T)(T a, T b)
+    {
+        return a<b?a:b;
+    }
+
+    /**********************************************************************************************
+        Parse a Module from the given data.
+    **********************************************************************************************/
+	Module parseModule(CodeView cv, ubyte[] data)
+	{
+		if ( data.length <= 0 )
+			throw new CodeViewException("parseModule on empty data");
+		DataReader dr = new DataReader(data);
+		Module mod = new Module(cv);
+		ubyte[] buf;
+		dr.readA(buf, ModuleHeader.sizeof);
+		mod.header = cast(ModuleHeader*)buf.ptr;
+		assert(mod.header.Style==intFromStr("CV"));
+		dr.readA!(SegInfo)(mod.seginfos, mod.header.cSeg);
+		dr.read(mod.name);
+		return mod;
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void parseSymbols(CodeView cv, ubyte[] data, SymbolSet symbols, bool skip_to_ssearch=false, Module mod=null)
+	{
+		if ( data.length <= 0 )
+			throw new CodeViewException("parseSymbols on empty data");
+		DataReader dr = new DataReader(data);
+
+		uint num_sym;
+
+		// skip until S_SSEARCH symbol is found
+		while ( skip_to_ssearch && dr.available )
+		{
+			ushort	length, index;
+			dr.read(length);
+			dr.read(index);
+			if ( index == SymbolIndex.S_SSEARCH ) {
+				dr.relseek(-4);
+				break;
+			}
+		}
+
+		uint sym_off;
+		bool expecting_arguments=false;
+		ScopeSymbol[uint]	scope_syms;
+		ScopeSymbol			parent_scope;
+
+		while ( dr.available )
+		{
+			ushort	length, index;
+			uint	next_symbol, symbol_start;
+
+			void addSymbol(Symbol sym)
+			{
+				assert( !expecting_arguments || parent_scope !is null );
+				if ( parent_scope !is null )
+				{
+					if ( expecting_arguments )
+						(cast(ProcedureSymbol)parent_scope).arguments.add(sym);
+					else
+						parent_scope.symbols.add(sym);
+				}
+				else
+					symbols.add(sym);
+			}
+
+			symbol_start = dr.cursor;
+			dr.read(length);
+			next_symbol = dr.cursor+length;
+            if ( next_symbol > dr.data.length ) {
+                debug DbgIO.println("WARNING: length %d for symbol exceeds block size %d - skipping section", length, dr.data.length);
+                if ( mod !is null )
+                debug DbgIO.println("in module %s", mod.name);
+                return;
+            }
+			dr.read(index);
+
+			ubyte[] buf;
+			switch ( index )
+			{
+				case SymbolIndex.S_COMPILE:
+					ubyte	machine,
+							language;
+					ushort	flags;
+					dr.read(machine);
+					dr.read(language);
+					dr.read(flags);
+					string version_string;
+					dr.read(version_string);
+					debug(cvsymbols) DbgIO.println("machine: 0x%x, language: %d, flags: 0x%x, version: %s", machine, language, flags, version_string);
+					break;
+				case SymbolIndex.S_SSEARCH:
+					dr.read(sym_off);
+					ushort pe_section;
+					dr.read(pe_section);
+					if ( mod !is null )
+						mod.pe_section = pe_section;
+					break;
+				case SymbolIndex.S_END:
+					debug(cvsymbols) DbgIO.println("S_END");
+					if ( parent_scope !is null )
+					{
+						if ( parent_scope.parent_scope !is null )
+							parent_scope = parent_scope.parent_scope;
+						else
+							parent_scope = null;
+					}
+					else {
+						debug DbgIO.println("S_END with no active parent scope");
+					}
+					expecting_arguments = false;
+					break;
+				case SymbolIndex.S_ENDARG:
+					expecting_arguments = false;
+					break;
+				case SymbolIndex.S_RETURN:
+					dr.readA(buf, CVReturnSymbol.sizeof);
+					ReturnSymbol rsym = new ReturnSymbol(cast(CVReturnSymbol*)buf.ptr);
+					if ( rsym.cvdata.style == 1 ) {
+						ubyte count;
+						dr.read(count);
+						dr.readA!(ubyte)(rsym.registers, count);
+					}
+					ProcedureSymbol psym = cast(ProcedureSymbol)parent_scope;
+					assert(psym !is null);
+					psym.return_sym = rsym;
+					break;
+				case SymbolIndex.S_LPROC32:
+				case SymbolIndex.S_GPROC32:
+					dr.readA(buf, CVProcedureSymbol.sizeof);
+					ProcedureSymbol psym = new ProcedureSymbol(cast(SymbolIndex)index, symbol_start, cast(CVProcedureSymbol*)buf.ptr);
+					dr.read(psym.mangled_name);
+					psym.name_notype = demangleName(psym.mangled_name);
+					psym.name_type = demangle(psym.mangled_name);
+					debug(cvsymbols) DbgIO.println("PROC32 %s (%s) s:%x o:%x", psym.name_type, psym.name_notype, psym.cvdata.segment, psym.cvdata.offset);
+					scope_syms[symbol_start] = psym;
+					addSymbol(psym);
+					assert ( parent_scope is null || psym.cvdata.pParent==parent_scope.lfo );
+					if ( psym.cvdata.pParent in scope_syms )
+					{
+						psym.parent_scope = scope_syms[psym.cvdata.pParent];
+						psym.parent_scope.symbols.add(psym);
+					}
+					parent_scope = psym;
+					expecting_arguments = true;
+					break;
+				case SymbolIndex.S_BPREL32:
+					dr.readA(buf, CVStackSymbol.sizeof);
+					StackSymbol stsym = new StackSymbol(cast(CVStackSymbol*)buf.ptr);
+					dr.read(stsym.mangled_name);
+					stsym.name_notype = demangleName(stsym.mangled_name);
+					stsym.name_type = demangle(stsym.mangled_name);
+					debug(cvsymbols) DbgIO.println(
+						"BPREL32 %s%s [%s] 0x%x o:%d", parent_scope !is null?"("~parent_scope.name_type~") ":"",
+						stsym.name_type, stsym.name_notype, stsym.cvtype, cast(int)stsym.cvdata.offset
+					);
+					addSymbol(stsym);
+					break;
+				case SymbolIndex.S_LDATA32:
+				case SymbolIndex.S_GDATA32:
+				case SymbolIndex.S_PUB32:
+					dr.readA(buf, CVDataSymbol.sizeof);
+					DataSymbol dsym = new DataSymbol(cast(SymbolIndex)index, cast(CVDataSymbol*)buf.ptr);
+					dr.read(dsym.mangled_name);
+					dsym.name_notype = demangleName(dsym.mangled_name);
+					dsym.name_type = demangle(dsym.mangled_name);
+					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);
+					addSymbol(dsym);
+					break;
+				case SymbolIndex.S_ALIGN:
+					debug(cvsymbols) DbgIO.println("ALIGN");
+					break;
+				case SymbolIndex.S_UDT:
+					UserDefinedType udt = new UserDefinedType;
+					dr.read(udt.type_index);
+					dr.read(udt.name);
+					cv.udtypes ~= udt;
+					break;
+                case SymbolIndex.S_PROCREF:
+                case SymbolIndex.S_DATAREF:
+                    break;
+				case SymbolIndex.S_REGISTER:
+				case SymbolIndex.S_CONSTANT:
+				case SymbolIndex.S_SKIP:
+				case SymbolIndex.S_CVRESERVE:
+				case SymbolIndex.S_OBJNAME:
+				case SymbolIndex.S_COBOLUDT:
+				case SymbolIndex.S_MANYREG:
+				case SymbolIndex.S_ENTRYTHIS:
+				case SymbolIndex.S_BPREL16:
+				case SymbolIndex.S_LDATA16:
+				case SymbolIndex.S_PUB16:
+				case SymbolIndex.S_LPROC16:
+				case SymbolIndex.S_GPROC16:
+				case SymbolIndex.S_THUNK16:
+				case SymbolIndex.S_BLOCK16:
+				case SymbolIndex.S_WITH16:
+				case SymbolIndex.S_LABEL16:
+				case SymbolIndex.S_CEXMODEL16:
+				case SymbolIndex.S_VFTPATH16:
+				case SymbolIndex.S_REGREL16:
+				case SymbolIndex.S_GDATA16:
+				case SymbolIndex.S_THUNK32:
+				case SymbolIndex.S_BLOCK32:
+				case SymbolIndex.S_WITH32:
+				case SymbolIndex.S_LABEL32:
+				case SymbolIndex.S_CEXMODEL32:
+				case SymbolIndex.S_VFTPATH32:
+				case SymbolIndex.S_REGREL32:
+				case SymbolIndex.S_LTHREAD32:
+				case SymbolIndex.S_GTHREAD32:
+					debug DbgIO.println("unprocessed symbol index 0x%x", index);
+					break;
+				default:
+					debug DbgIO.println("unknown symbol index 0x%x", index);
+			}
+
+            dr.seek(next_symbol);
+		}
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void parseSrcModule(CodeView cv, ubyte[] data, Module mod)
+	{
+		if ( data.length <= 0 )
+			throw new CodeViewException("parseSrcModule on empty data");
+		DataReader dr = new DataReader(data);
+		ushort cFile, cSeg;
+		dr.read(cFile);
+		dr.read(cSeg);
+
+		SourceModule smod = new SourceModule;
+		mod.source_module = smod;
+		cv.source_modules ~= smod;
+
+        uint[]	    baseSrcFile,
+                    start_end;
+        ushort[]	seginds;
+		dr.readA(baseSrcFile, cast(uint)cFile);
+		dr.readA(start_end, cast(uint)cSeg*2);
+		dr.readA(seginds, cast(uint)cSeg);
+		debug(cvparser) DbgIO.println("Module %s files=%d segs=%d", mod.name, cFile, cSeg);
+
+		foreach ( fileoffset; baseSrcFile )
+		{
+			dr.seek(fileoffset);
+			dr.read(cSeg);
+			ushort pad;
+			dr.read(pad);
+
+			SourceFile file = new SourceFile;
+			file.source_module = smod;
+            uint[]  baseSrcLn;
+			dr.readA(baseSrcLn, cast(uint)cSeg);
+			start_end = null;
+			dr.readA(start_end, cast(uint)cSeg*2);
+			dr.read(file.name);
+            debug(cvparser) DbgIO.println("\tFile %s segs=%d", file.name, cSeg);
+			smod.files ~= file;
+
+			foreach ( int i, segoff; baseSrcLn )
+			{
+				dr.seek(segoff);
+				SourceSegment seg = new SourceSegment;
+				file.segments ~= seg;
+				seg.file = file;
+
+				seg.start  = start_end[i*2];
+				seg.end    = start_end[i*2+1];
+
+				dr.read(pad);   // segment index
+				ushort cPair;
+				dr.read(cPair);
+                debug(cvparser) DbgIO.println("\t\tSegment %d lines=%d", file.segments.length-1, cPair);
+
+                uint[]		offset;
+                ushort[]	linenumber;
+				dr.readA(offset, cast(uint)cPair);
+				dr.readA(linenumber, cast(uint)cPair);
+
+                foreach ( int j, l; linenumber ) {
+                    CodeBlock cb = new CodeBlock(offset[j], l, seg);
+                    file.blocks_by_line[l] ~= cb;
+                    debug(cvparser)
+                    {
+                        bool inserted = cv.codeblocks.insert(cb);
+                        if ( !inserted )
+                            DbgIO.println("failed to insert block %s, already exists", cb);
+                    }
+                    else
+                        cv.codeblocks.insert(cb);
+                }
+			}
+
+			file.lines = file.blocks_by_line.keys.dup.sort;
+		}
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void parseLibraries(CodeView cv, ubyte[] data)
+	{
+		if ( data.length <= 0 )
+			throw new CodeViewException("parseLibraries on empty data");
+		DataReader dr = new DataReader(data);
+		while ( dr.available ) {
+			string lib;
+			dr.read(lib);
+			cv.libraries ~= lib;
+		}
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void parsePackedSymbols(CodeView cv, ubyte[] data, SymbolSet symbols)
+	{
+		if ( data.length <= 0 )
+			throw new CodeViewException("parsePackedSymbols on empty data");
+		DataReader dr = new DataReader(data);
+
+		ubyte[] buf;
+		dr.readA(buf, PackedSymbolsHeader.sizeof);
+		PackedSymbolsHeader* gsh = cast(PackedSymbolsHeader*)buf.ptr;
+
+		dr.readA(buf, gsh.cbSymbol);
+		parseSymbols(cv, buf, symbols);
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void parseGlobalTypes(CodeView cv, ubyte[] data, uint absolute_offset)
+	{
+		DataReader dr = new DataReader(data);
+		uint	flags,
+				cType;
+		uint[]	offType;
+		dr.read(flags);
+		dr.read(cType);
+		dr.readA(offType, cType);
+
+		uint	base = dr.cursor;
+		foreach ( off; offType )
+		{
+			dr.seek(base+off);
+			ushort	len;
+			dr.read(len);
+			ubyte[] buf;
+			dr.readA(buf, cast(uint)len);
+			cv.type_strings ~= parseTypeString(cv, buf);
+		}
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	Leaf[] parseTypeString(CodeView cv, ubyte[] data)
+	{
+		debug(cvdump) foreach ( b; data )
+			DbgIO.print("%02x ", b);
+		debug(cvdump) DbgIO.println("");
+		DataReader dr = new DataReader(data);
+		Leaf[] leafs;
+		bool first = true;
+		while ( dr.available )
+		{
+			ushort leaf_index;
+			dr.read(leaf_index);
+			Leaf l;
+//			debug(cvparser) DbgIO.println("parsing 0x%x", leaf_index);
+			switch ( leaf_index )
+			{
+				case LF_MODIFIER_16t:
+					LeafModifer lm = new LeafModifer;
+					l = lm;
+					dr.read(lm.attribute);
+					dr.read(lm.index);
+					break;
+				case LF_POINTER_16t:
+					LeafPointer lp = new LeafPointer;
+					l = lp;
+					dr.read(lp.attribute);
+					dr.read(lp.type);
+					switch ( lp.attribute&0x1f )
+					{
+						case 0:
+						case 10:
+							break;
+						default:
+							debug DbgIO.println("unprocessed pointer type: 0x%x", lp.attribute);
+							assert(0);
+					}
+					break;
+				case LF_ARRAY_16t:
+					LeafArray la = new LeafArray;
+					l = la;
+					dr.read(la.elemtype);
+					dr.read(la.idxtype);
+					la.length = parseNumericLeaf(dr);
+					dr.read(la.name);
+					debug(cvparser) DbgIO.println("LF_ARRAY: %d 0x%x", la.length.getUint, 0x1000+cv.type_strings.length);
+					break;
+				case LF_PROCEDURE_16t:
+					LeafProcedure lp = new LeafProcedure;
+					l = lp;
+					dr.read(lp.rvtype);
+					dr.read(lp.call);
+					dr.read(lp.reserved);
+					dr.read(lp.cParms);
+					dr.read(lp.arglist);
+					break;
+				case LF_MFUNCTION_16t:
+					LeafMFunction lmf = new LeafMFunction;
+					l = lmf;
+					dr.read(lmf.rvtype);
+					dr.read(lmf._class);
+					dr.read(lmf._this);
+					dr.read(lmf.call);
+					dr.read(lmf.reserved);
+					dr.read(lmf.cParms);
+					dr.read(lmf.arglist);
+					dr.read(lmf.thisadjust);
+					break;
+				case LF_VTSHAPE:
+					LeafVTShape lvts = new LeafVTShape;
+					l = lvts;
+					ushort count;
+					dr.read(count);
+					dr.readA(lvts.descriptor, cast(uint)(count+1)>>1);
+					// skip rest of typestring
+					dr.seek(dr.data.length);
+					break;
+				case LF_CLASS_16t:
+				case LF_STRUCTURE_16t:
+					LeafClassStruc lcs = new LeafClassStruc;
+					l = lcs;
+					dr.read(lcs.count);
+					dr.read(lcs.field);
+					dr.read(lcs.property);
+					dr.read(lcs.dList);
+					dr.read(lcs.vshape);
+					lcs.length = parseNumericLeaf(dr);
+					dr.read(lcs.name);
+					lcs.type = cast(ushort)(0x1000+cv.type_strings.length);
+					debug(cvparser) DbgIO.println(
+						"%s 0x%x '%s' fl: 0x%x prop: 0x%x, length=0x%x", leaf_index==LF_CLASS_16t?"class":"struct",
+						lcs.type, lcs.name, lcs.field, lcs.property, lcs.length.getUint
+					);
+
+					cv.UDTsByName[lcs.name] = lcs;
+					break;
+				case LF_ENUM_16t:
+					LeafEnum le = new LeafEnum;
+					l = le;
+					dr.read(le.count);
+					dr.read(le.type);
+					dr.read(le.field);
+					dr.read(le.property);
+					dr.read(le.name);
+					debug(cvparser) DbgIO.println(
+						"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
+					);
+					cv.UDTsByName[le.name] = le;
+					break;
+				case LF_UNION_16t:
+					LeafUnion lu = new LeafUnion;
+					l = lu;
+					dr.read(lu.count);
+					dr.read(lu.field);
+					dr.read(lu.property);
+					lu.length = parseNumericLeaf(dr);
+					dr.read(lu.name);
+					// skip rest of typestring
+					dr.seek(dr.data.length);
+					debug(cvparser) DbgIO.println("Union '%s' count %d fields 0x%x length 0x%x", lu.name, lu.count, lu.field, lu.length.getUint);
+					cv.UDTsByName[lu.name] = lu;
+					break;
+                case LF_OEM_16t:
+                    ushort oem;
+                    dr.read(oem);
+                    assert(oem == OEM_DIGITALMARS);
+                    dr.read(oem);
+                    ushort count;
+                    dr.read(count);
+                    assert(count == 2);
+                    switch ( oem )
+                    {
+                        case D_DYN_ARRAY:
+                            LeafDynArray lda = new LeafDynArray;
+                            l = lda;
+                            dr.read(lda.index_type);
+                            dr.read(lda.elem_type);
+                            debug(cvparser) DbgIO.println("Dynamic array index_type 0x%x elem_type 0x%x", lda.index_type, lda.elem_type);
+                            break;
+                        case D_ASSOC_ARRAY:
+                            LeafAssocArray laa = new LeafAssocArray;
+                            l = laa;
+                            dr.read(laa.key_type);
+                            dr.read(laa.elem_type);
+                            debug(cvparser) DbgIO.println("Associativ array key_type 0x%x elem_type 0x%x", laa.key_type, laa.elem_type);
+                            break;
+                        default:
+                            LeafDelegate ld = new LeafDelegate;
+                            l = ld;
+                            dr.read(ld.this_type);
+                            dr.read(ld.func_type);
+                            debug(cvparser) DbgIO.println("Delegate this_type 0x%x func_type 0x%x", ld.this_type, ld.func_type);
+                            break;
+                    }
+                    break;
+
+				case LF_ARGLIST_16t:
+					LeafArgList lal = new LeafArgList;
+					l = lal;
+					dr.read(lal.argcount);
+					dr.readA(lal.indeces, cast(uint)lal.argcount);
+					break;
+				case LF_FIELDLIST_16t:
+					debug(cvparser) DbgIO.println("fieldlist 0x%x", 0x1000+cv.type_strings.length);
+					LeafFieldList lfl = new LeafFieldList;
+					l = lfl;
+					while ( dr.available )
+						lfl.fields ~= parseSubfield(dr);
+					// skip rest of typestring
+					dr.seek(dr.data.length);
+					break;
+				case LF_DERIVED_16t:
+					LeafDerived ld = new LeafDerived;
+					l = ld;
+					ushort count;
+					dr.read(count);
+					dr.readA(ld.types, cast(uint)count);
+					break;
+				case LF_METHODLIST_16t:
+					LeafMethodList lml = new LeafMethodList;
+					l = lml;
+					// skip rest of typestring
+					dr.seek(dr.data.length);
+					break;
+				default:
+					debug DbgIO.println("unprocessed leaf index 0x%x at 0x%x", leaf_index, dr.cursor-2);
+					l = new Leaf;
+			}
+			assert ( l !is null );
+			l.leaf_index = leaf_index;
+			leafs ~= l;
+		}
+		return leafs;
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	Leaf parseSubfield(DataReader dr)
+	{
+		ushort leaf_index;
+		dr.read(leaf_index);
+		Leaf l;
+		switch ( leaf_index )
+		{
+			case LF_BCLASS_16t:
+				LeafBaseClass lbc = new LeafBaseClass;
+				l = lbc;
+				dr.read(lbc.type);
+				dr.read(lbc.attribute);
+				lbc.offset = parseNumericLeaf(dr);
+				debug(cvparser) DbgIO.println("SFbclass");
+				break;
+			case LF_MEMBER_16t:
+				LeafMember lm = new LeafMember;
+				l = lm;
+				dr.read(lm.type);
+				dr.read(lm.attribute);
+				lm.offset = parseNumericLeaf(dr);
+				dr.read(lm.name);
+				debug(cvparser) DbgIO.println("SFmember: %s", lm.name);
+				break;
+			case LF_METHOD_16t:
+				LeafMethod lm = new LeafMethod;
+				l = lm;
+				dr.read(lm.count);
+				dr.read(lm.mList);
+				dr.read(lm.name);
+				debug(cvparser) DbgIO.println("SFmethod: %d 0x%x %s", lm.count, lm.mList, lm.name);
+				break;
+			case LF_ENUMERATE:
+				LeafEnumNameValue le = new LeafEnumNameValue;
+				l = le;
+				dr.read(le.attribute);
+				le.value = parseNumericLeaf(dr);
+				dr.read(le.name);
+				debug(cvparser) DbgIO.println("SFenumerate: %s %d", le.name, le.value.getUint);
+				break;
+			case LF_NESTTYPE_16t:
+				LeafNestedType ln = new LeafNestedType;
+				l = ln;
+				dr.read(ln.index);
+				dr.read(ln.name);
+				debug(cvparser) DbgIO.println("SFnesttype: %s", ln.name);
+				break;
+			case LF_STMEMBER_16t:
+				LeafStaticDataMember ls = new LeafStaticDataMember;
+				l = ls;
+				dr.read(ls.type);
+				dr.read(ls.attribute);
+				dr.read(ls.name);
+				debug(cvparser) DbgIO.println("SFstmember: %s", ls.name);
+				break;
+			case LF_SKIP_16t:
+				dr.seek(dr.data.length);
+				debug(cvparser) DbgIO.println("SFskip");
+				break;
+			default:
+				debug DbgIO.println("unprocessed subfield index 0x%x", leaf_index);
+				l = new Leaf;
+		}
+		if ( dr.available )
+		{
+			ubyte pad;
+			dr.peek(pad);
+			if ( pad > 0xf0 )
+				dr.relseek(pad&0xf);
+		}
+		assert ( l !is null );
+		l.leaf_index = leaf_index;
+		return l;
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	LeafNumeric parseNumericLeaf(DataReader dr)
+	{
+		LeafNumeric nl = new LeafNumeric;
+		dr.read(nl.leaf_index);
+		if ( nl.leaf_index < 0x8000 ) {
+			nl.us = cast(ushort)nl.leaf_index;
+			nl.leaf_index = LF_USHORT;
+		}
+		else switch ( nl.leaf_index )
+		{
+			case LF_VARSTRING:	dr.read(nl.str);	break;
+			case LF_CHAR:		dr.read(nl.c);	break;
+			case LF_SHORT:		dr.read(nl.s);	break;
+			case LF_USHORT:		dr.read(nl.us);	break;
+			case LF_LONG:		dr.read(nl.i);	break;
+			case LF_ULONG:		dr.read(nl.ui);	break;
+			case LF_REAL32:		dr.read(nl.f);	break;
+			case LF_REAL64:		dr.read(nl.d);	break;
+			case LF_REAL80:		dr.read(nl.r);	break;
+			case LF_QUADWORD:	dr.read(nl.l);	break;
+			case LF_UQUADWORD:	dr.read(nl.ul);	break;
+			case LF_COMPLEX32:	dr.read(nl.cf);	break;
+			case LF_COMPLEX64:
+			case LF_COMPLEX80:
+			case LF_REAL48:
+			case LF_COMPLEX128:
+			case LF_REAL128:
+			default:
+				debug DbgIO.println("unknown leaftype %x", nl.leaf_index);
+		}
+		return nl;
+	}
+
+    /**********************************************************************************************
+        Updates symbol size fields and mangled_names. Since both can only
+        be determined fully after sstGlobalTypes have been read.
+    **********************************************************************************************/
+	void updateSymbols(CodeView cv, NamedSymbol[] syms)
+	{
+		foreach ( s; syms )
+		{
+			if ( s.mangled_name is null || s.mangled_name.length <= 0 )
+				s.mangled_name = cv.mangle(s);
+
+			ScopeSymbol scs = cast(ScopeSymbol)s;
+			if ( scs !is null )
+				updateSymbols(cv, scs.symbols.named_symbols);
+			ProcedureSymbol ps = cast(ProcedureSymbol)s;
+			if ( ps !is null )
+				updateSymbols(cv, ps.arguments.named_symbols);
+
+			string type = cv.mangleType(s);
+			if ( type is null )
+				continue;
+
+			DataSymbol ds = cast(DataSymbol)s;
+			if ( ds !is null )
+				ds.size = cv.sizeofCV(ds.cvdata.type);
+			else
+			{
+				StackSymbol ss = cast(StackSymbol)s;
+				if ( ss !is null )
+					ss.size = cv.sizeofCV(ss.cvdata.type);
+			}
+		}
+	}
+}