/// <summary> /// </summary> /// <param name="contentSize"> /// </param> /// <param name="bits"> /// </param> /// <param name="count"> /// </param> internal DataStream(int contentSize, BitAccess bits, int count) { this.contentSize = contentSize; if (count > 0) { this.pages = new int[count]; bits.ReadInt32(this.pages); } }
/// <summary> /// </summary> /// <param name="read"> /// </param> /// <param name="bits"> /// </param> /// <param name="readAllStrings"> /// </param> /// <returns> /// </returns> /// <exception cref="PdbException"> /// </exception> internal static PdbFunction[] LoadFunctions(Stream read, BitAccess bits, bool readAllStrings) { var head = new PdbFileHeader(read, bits); var reader = new PdbReader(read, head.pageSize); var dir = new MsfDirectory(reader, head, bits); DbiModuleInfo[] modules = null; DbiDbgHdr header; dir.streams[1].Read(reader, bits); var nameIndex = LoadNameIndex(bits); int nameStream; if (!nameIndex.TryGetValue("/names", out nameStream)) { throw new PdbException("No `name' stream"); } dir.streams[nameStream].Read(reader, bits); var names = LoadNameStream(bits); dir.streams[3].Read(reader, bits); LoadDbiStream(bits, out modules, out header, readAllStrings); var funcList = new ArrayList(); if (modules != null) { for (var m = 0; m < modules.Length; m++) { if (modules[m].stream > 0) { dir.streams[modules[m].stream].Read(reader, bits); LoadFuncsFromDbiModule(bits, modules[m], names, funcList, readAllStrings, dir, nameIndex, reader); } } } var funcs = (PdbFunction[])funcList.ToArray(typeof(PdbFunction)); // After reading the functions, apply the token remapping table if it exists. if (header.snTokenRidMap != 0 && header.snTokenRidMap != 0xffff) { dir.streams[header.snTokenRidMap].Read(reader, bits); var ridMap = new uint[dir.streams[header.snTokenRidMap].Length / 4]; bits.ReadUInt32(ridMap); foreach (var func in funcs) { func.token = 0x06000000 | ridMap[func.token & 0xffffff]; } } //Array.Sort(funcs, PdbFunction.byAddress); Array.Sort(funcs, PdbFunction.byToken); return funcs; }
/// <summary> /// </summary> /// <param name="reader"> /// </param> /// <param name="bits"> /// </param> internal PdbFileHeader(Stream reader, BitAccess bits) { bits.MinCapacity(56); reader.Seek(0, SeekOrigin.Begin); bits.FillBuffer(reader, 56); this.magic = new byte[32]; bits.ReadBytes(this.magic); // 0..31 bits.ReadInt32(out this.pageSize); // 32..35 bits.ReadInt32(out this.freePageMap); // 36..39 bits.ReadInt32(out this.pagesUsed); // 40..43 bits.ReadInt32(out this.directorySize); // 44..47 bits.ReadInt32(out this.zero); // 48..51 bits.ReadInt32(out this.directoryRoot); // 52..55 }
/// <summary> /// </summary> /// <param name="bits"> /// </param> /// <returns> /// </returns> /// <exception cref="PdbDebugException"> /// </exception> private static IntHashTable LoadNameStream(BitAccess bits) { var ht = new IntHashTable(); uint sig; int ver; bits.ReadUInt32(out sig); // 0..3 Signature bits.ReadInt32(out ver); // 4..7 Version // Read (or skip) string buffer. int buf; bits.ReadInt32(out buf); // 8..11 Bytes of Strings if (sig != 0xeffeeffe || ver != 1) { throw new PdbDebugException("Unsupported Name Stream version. " + "(sig={0:x8}, ver={1})", sig, ver); } var beg = bits.Position; var nxt = bits.Position + buf; bits.Position = nxt; // Read hash table. int siz; bits.ReadInt32(out siz); // n+0..3 Number of hash buckets. nxt = bits.Position; for (var i = 0; i < siz; i++) { int ni; string name; bits.ReadInt32(out ni); if (ni != 0) { var saved = bits.Position; bits.Position = beg + ni; bits.ReadCString(out name); bits.Position = saved; ht.Add(ni, name); } } bits.Position = nxt; return ht; }
/// <summary> /// </summary> /// <param name="read"> /// </param> /// <param name="readAllStrings"> /// </param> /// <returns> /// </returns> internal static PdbFunction[] LoadFunctions(Stream read, bool readAllStrings) { var bits = new BitAccess(512 * 1024); return LoadFunctions(read, bits, readAllStrings); }
/// <summary> /// </summary> /// <param name="bits"> /// </param> /// <param name="doctype"> /// </param> /// <param name="language"> /// </param> /// <param name="vendor"> /// </param> private static void LoadGuidStream(BitAccess bits, out Guid doctype, out Guid language, out Guid vendor) { bits.ReadGuid(out language); bits.ReadGuid(out vendor); bits.ReadGuid(out doctype); }
/// <summary> /// </summary> /// <param name="bits"> /// </param> /// <param name="modules"> /// </param> /// <param name="header"> /// </param> /// <param name="readStrings"> /// </param> /// <exception cref="PdbException"> /// </exception> /// <exception cref="PdbDebugException"> /// </exception> private static void LoadDbiStream(BitAccess bits, out DbiModuleInfo[] modules, out DbiDbgHdr header, bool readStrings) { var dh = new DbiHeader(bits); header = new DbiDbgHdr(); if (dh.sig != -1 || dh.ver != 19990903) { throw new PdbException("Unsupported DBI Stream version, sig={0}, ver={1}", dh.sig, dh.ver); } // Read gpmod section. var modList = new ArrayList(); var end = bits.Position + dh.gpmodiSize; while (bits.Position < end) { var mod = new DbiModuleInfo(bits, readStrings); modList.Add(mod); } if (bits.Position != end) { throw new PdbDebugException("Error reading DBI stream, pos={0} != {1}", bits.Position, end); } if (modList.Count > 0) { modules = (DbiModuleInfo[])modList.ToArray(typeof(DbiModuleInfo)); } else { modules = null; } // Skip the Section Contribution substream. bits.Position += dh.secconSize; // Skip the Section Map substream. bits.Position += dh.secmapSize; // Skip the File Info substream. bits.Position += dh.filinfSize; // Skip the TSM substream. bits.Position += dh.tsmapSize; // Skip the EC substream. bits.Position += dh.ecinfoSize; // Read the optional header. end = bits.Position + dh.dbghdrSize; if (dh.dbghdrSize > 0) { header = new DbiDbgHdr(bits); } bits.Position = end; }
/// <summary> /// </summary> /// <param name="streams"> /// </param> /// <param name="directoryRoot"> /// </param> /// <param name="directorySize"> /// </param> /// <param name="bits"> /// </param> private void WriteDirectory(DataStream[] streams, out int directoryRoot, out int directorySize, BitAccess bits) { var directory = new DataStream(); var pages = 0; for (var s = 0; s < streams.Length; s++) { if (streams[s].Length > 0) { pages += streams[s].Pages; } } var use = 4 * (1 + streams.Length + pages); bits.MinCapacity(use); bits.WriteInt32(streams.Length); for (var s = 0; s < streams.Length; s++) { bits.WriteInt32(streams[s].Length); } for (var s = 0; s < streams.Length; s++) { if (streams[s].Length > 0) { bits.WriteInt32(streams[s].pages); } } directory.Write(this, bits.Buffer, use); directorySize = directory.Length; use = 4 * directory.Pages; bits.MinCapacity(use); bits.WriteInt32(directory.pages); var ddir = new DataStream(); ddir.Write(this, bits.Buffer, use); directoryRoot = ddir.pages[0]; }
/// <summary> /// </summary> /// <param name="bits"> /// </param> private void ReadUsingInfo(BitAccess bits) { ushort numberOfNamespaces; bits.ReadUInt16(out numberOfNamespaces); this.usingCounts = new ushort[numberOfNamespaces]; for (ushort i = 0; i < numberOfNamespaces; i++) { bits.ReadUInt16(out this.usingCounts[i]); } }
/// <summary> /// </summary> /// <param name="bits"> /// </param> private void ReadForwardIterator(BitAccess bits) { this.iteratorClass = bits.ReadString(); }
/// <summary> /// </summary> /// <param name="bits"> /// </param> private void ReadForwardInfo(BitAccess bits) { }
/// <summary> /// </summary> /// <param name="module"> /// </param> /// <param name="bits"> /// </param> /// <param name="limit"> /// </param> /// <param name="readStrings"> /// </param> /// <returns> /// </returns> internal static PdbFunction[] LoadManagedFunctions(string module, BitAccess bits, uint limit, bool readStrings) { var mod = StripNamespace(module); var begin = bits.Position; var count = 0; while (bits.Position < limit) { ushort siz; ushort rec; bits.ReadUInt16(out siz); var star = bits.Position; var stop = bits.Position + siz; bits.Position = star; bits.ReadUInt16(out rec); switch ((SYM)rec) { case SYM.S_GMANPROC: case SYM.S_LMANPROC: ManProcSym proc; bits.ReadUInt32(out proc.parent); bits.ReadUInt32(out proc.end); bits.Position = (int)proc.end; count++; break; case SYM.S_END: bits.Position = stop; break; default: // Console.WriteLine("{0,6}: {1:x2} {2}", // bits.Position, rec, (SYM)rec); bits.Position = stop; break; } } if (count == 0) { return(null); } bits.Position = begin; var funcs = new PdbFunction[count]; var func = 0; while (bits.Position < limit) { ushort siz; ushort rec; bits.ReadUInt16(out siz); var star = bits.Position; var stop = bits.Position + siz; bits.ReadUInt16(out rec); switch ((SYM)rec) { case SYM.S_GMANPROC: case SYM.S_LMANPROC: ManProcSym proc; var offset = bits.Position; bits.ReadUInt32(out proc.parent); bits.ReadUInt32(out proc.end); bits.ReadUInt32(out proc.next); bits.ReadUInt32(out proc.len); bits.ReadUInt32(out proc.dbgStart); bits.ReadUInt32(out proc.dbgEnd); bits.ReadUInt32(out proc.token); bits.ReadUInt32(out proc.off); bits.ReadUInt16(out proc.seg); bits.ReadUInt8(out proc.flags); bits.ReadUInt16(out proc.retReg); if (readStrings) { bits.ReadCString(out proc.name); } else { bits.SkipCString(out proc.name); } // Console.WriteLine("token={0:X8} [{1}::{2}]", proc.token, module, proc.name); bits.Position = stop; funcs[func++] = new PdbFunction(module, proc, bits); break; default: { // throw new PdbDebugException("Unknown SYMREC {0}", (SYM)rec); bits.Position = stop; break; } } } return(funcs); }
/// <summary> /// </summary> /// <param name="module"> /// </param> /// <param name="proc"> /// </param> /// <param name="bits"> /// </param> /// <exception cref="PdbDebugException"> /// </exception> internal PdbFunction(string module, ManProcSym proc, BitAccess bits) { this.token = proc.token; this.module = module; this.name = proc.name; this.flags = proc.flags; this.segment = proc.seg; this.address = proc.off; this.length = proc.len; this.slotToken = 0; if (proc.seg != 1) { throw new PdbDebugException("Segment is {0}, not 1.", proc.seg); } if (proc.parent != 0 || proc.next != 0) { throw new PdbDebugException("Warning parent={0}, next={1}", proc.parent, proc.next); } if (proc.dbgStart != 0 || proc.dbgEnd != 0) { throw new PdbDebugException("Warning DBG start={0}, end={1}", proc.dbgStart, proc.dbgEnd); } int constantCount; int scopeCount; int slotCount; int usedNamespacesCount; CountScopesAndSlots(bits, proc.end, out constantCount, out scopeCount, out slotCount, out usedNamespacesCount); this.scopes = new PdbScope[scopeCount]; var scope = 0; while (bits.Position < proc.end) { ushort siz; ushort rec; bits.ReadUInt16(out siz); var star = bits.Position; var stop = bits.Position + siz; bits.Position = star; bits.ReadUInt16(out rec); switch ((SYM)rec) { case SYM.S_OEM: { // 0x0404 OemSymbol oem; bits.ReadGuid(out oem.idOem); bits.ReadUInt32(out oem.typind); // internal byte[] rgl; // user data, force 4-byte alignment if (oem.idOem == msilMetaData) { var name = bits.ReadString(); if (name == "MD2") { byte version; bits.ReadUInt8(out version); if (version == 4) { byte count; bits.ReadUInt8(out count); bits.Align(4); while (count-- > 0) { this.ReadCustomMetadata(bits); } } } bits.Position = stop; break; } else { throw new PdbDebugException("OEM section: guid={0} ti={1}", oem.idOem, oem.typind); // bits.Position = stop; } } case SYM.S_BLOCK32: { var block = new BlockSym32(); bits.ReadUInt32(out block.parent); bits.ReadUInt32(out block.end); bits.ReadUInt32(out block.len); bits.ReadUInt32(out this.address); bits.ReadUInt16(out block.seg); bits.SkipCString(out block.name); bits.Position = stop; this.scopes[scope] = new PdbScope(block, bits, out this.slotToken); bits.Position = (int)block.end; break; } case SYM.S_UNAMESPACE: bits.Position = stop; break; case SYM.S_END: bits.Position = stop; break; default: { // throw new PdbDebugException("Unknown SYM: {0}", (SYM)rec); bits.Position = stop; break; } } } if (bits.Position != proc.end) { throw new PdbDebugException("Not at S_END"); } ushort esiz; ushort erec; bits.ReadUInt16(out esiz); bits.ReadUInt16(out erec); if (erec != (ushort)SYM.S_END) { throw new PdbDebugException("Missing S_END"); } }
/// <summary> /// </summary> /// <param name="reader"> /// </param> /// <param name="bits"> /// </param> internal void Read(PdbReader reader, BitAccess bits) { bits.MinCapacity(this.contentSize); this.Read(reader, 0, bits.Buffer, 0, this.contentSize); }
/// <summary> /// </summary> /// <param name="writer"> /// </param> /// <param name="bits"> /// </param> internal void Write(Stream writer, BitAccess bits) { bits.MinCapacity(56); bits.WriteBytes(this.magic); // 0..31 bits.WriteInt32(this.pageSize); // 32..35 bits.WriteInt32(this.freePageMap); // 36..39 bits.WriteInt32(this.pagesUsed); // 40..43 bits.WriteInt32(this.directorySize); // 44..47 bits.WriteInt32(this.zero); // 48..51 bits.WriteInt32(this.directoryRoot); // 52..55 writer.Seek(0, SeekOrigin.Begin); bits.WriteBuffer(writer, 56); }
/// <summary> /// </summary> /// <param name="bits"> /// </param> private void ReadIteratorLocals(BitAccess bits) { uint numberOfLocals; bits.ReadUInt32(out numberOfLocals); this.iteratorScopes = new List<ILocalScope>((int)numberOfLocals); while (numberOfLocals-- > 0) { uint ilStartOffset; uint ilEndOffset; bits.ReadUInt32(out ilStartOffset); bits.ReadUInt32(out ilEndOffset); this.iteratorScopes.Add(new PdbIteratorScope(ilStartOffset, ilEndOffset - ilStartOffset)); } }
/// <summary> /// </summary> /// <param name="bits"> /// </param> private void ReadForwardedToModuleInfo(BitAccess bits) { }
/// <summary> /// </summary> /// <param name="streams"> /// </param> /// <param name="bits"> /// </param> internal void WriteMeta(DataStream[] streams, BitAccess bits) { var head = new PdbFileHeader(this.pageSize); this.WriteDirectory(streams, out head.directoryRoot, out head.directorySize, bits); this.WriteFreeMap(); head.freePageMap = 2; head.pagesUsed = this.usedBytes / this.pageSize; this.writer.Seek(0, SeekOrigin.Begin); head.Write(this.writer, bits); }
/// <summary> /// </summary> /// <param name="block"> /// </param> /// <param name="bits"> /// </param> /// <param name="typind"> /// </param> /// <exception cref="PdbException"> /// </exception> /// <exception cref="Exception"> /// </exception> internal PdbScope(BlockSym32 block, BitAccess bits, out uint typind) { this.segment = block.seg; this.address = block.off; this.length = block.len; typind = 0; int constantCount; int scopeCount; int slotCount; int namespaceCount; PdbFunction.CountScopesAndSlots(bits, block.end, out constantCount, out scopeCount, out slotCount, out namespaceCount); this.constants = new PdbConstant[constantCount]; this.scopes = new PdbScope[scopeCount]; this.slots = new PdbSlot[slotCount]; this.usedNamespaces = new string[namespaceCount]; var constant = 0; var scope = 0; var slot = 0; var usedNs = 0; while (bits.Position < block.end) { ushort siz; ushort rec; bits.ReadUInt16(out siz); var star = bits.Position; var stop = bits.Position + siz; bits.Position = star; bits.ReadUInt16(out rec); switch ((SYM)rec) { case SYM.S_BLOCK32: { var sub = new BlockSym32(); bits.ReadUInt32(out sub.parent); bits.ReadUInt32(out sub.end); bits.ReadUInt32(out sub.len); bits.ReadUInt32(out sub.off); bits.ReadUInt16(out sub.seg); bits.SkipCString(out sub.name); bits.Position = stop; this.scopes[scope++] = new PdbScope(sub, bits, out typind); break; } case SYM.S_MANSLOT: this.slots[slot++] = new PdbSlot(bits, out typind); bits.Position = stop; break; case SYM.S_UNAMESPACE: bits.ReadCString(out this.usedNamespaces[usedNs++]); bits.Position = stop; break; case SYM.S_END: bits.Position = stop; break; case SYM.S_MANCONSTANT: this.constants[constant++] = new PdbConstant(bits); bits.Position = stop; break; default: throw new PdbException("Unknown SYM in scope {0}", (SYM)rec); // bits.Position = stop; } } if (bits.Position != block.end) { throw new Exception("Not at S_END"); } ushort esiz; ushort erec; bits.ReadUInt16(out esiz); bits.ReadUInt16(out erec); if (erec != (ushort)SYM.S_END) { throw new Exception("Missing S_END"); } }
/// <summary> /// </summary> /// <param name="bits"> /// </param> /// <param name="limit"> /// </param> /// <param name="constants"> /// </param> /// <param name="scopes"> /// </param> /// <param name="slots"> /// </param> /// <param name="usedNamespaces"> /// </param> internal static void CountScopesAndSlots(BitAccess bits, uint limit, out int constants, out int scopes, out int slots, out int usedNamespaces) { var pos = bits.Position; BlockSym32 block; constants = 0; slots = 0; scopes = 0; usedNamespaces = 0; while (bits.Position < limit) { ushort siz; ushort rec; bits.ReadUInt16(out siz); var star = bits.Position; var stop = bits.Position + siz; bits.Position = star; bits.ReadUInt16(out rec); switch ((SYM)rec) { case SYM.S_BLOCK32: { bits.ReadUInt32(out block.parent); bits.ReadUInt32(out block.end); scopes++; bits.Position = (int)block.end; break; } case SYM.S_MANSLOT: slots++; bits.Position = stop; break; case SYM.S_UNAMESPACE: usedNamespaces++; bits.Position = stop; break; case SYM.S_MANCONSTANT: constants++; bits.Position = stop; break; default: bits.Position = stop; break; } } bits.Position = pos; }
/// <summary> /// </summary> /// <param name="bits"> /// </param> /// <param name="info"> /// </param> /// <param name="names"> /// </param> /// <param name="funcList"> /// </param> /// <param name="readStrings"> /// </param> /// <param name="dir"> /// </param> /// <param name="nameIndex"> /// </param> /// <param name="reader"> /// </param> /// <exception cref="PdbDebugException"> /// </exception> private static void LoadFuncsFromDbiModule( BitAccess bits, DbiModuleInfo info, IntHashTable names, ArrayList funcList, bool readStrings, MsfDirectory dir, Dictionary<string, int> nameIndex, PdbReader reader) { PdbFunction[] funcs = null; bits.Position = 0; int sig; bits.ReadInt32(out sig); if (sig != 4) { throw new PdbDebugException("Invalid signature. (sig={0})", sig); } bits.Position = 4; // Console.WriteLine("{0}:", info.moduleName); funcs = PdbFunction.LoadManagedFunctions(info.moduleName, bits, (uint)info.cbSyms, readStrings); if (funcs != null) { bits.Position = info.cbSyms + info.cbOldLines; LoadManagedLines(funcs, names, bits, dir, nameIndex, reader, (uint)(info.cbSyms + info.cbOldLines + info.cbLines)); for (var i = 0; i < funcs.Length; i++) { funcList.Add(funcs[i]); } } }
/// <summary> /// </summary> /// <param name="module"> /// </param> /// <param name="bits"> /// </param> /// <param name="limit"> /// </param> /// <param name="readStrings"> /// </param> /// <returns> /// </returns> internal static PdbFunction[] LoadManagedFunctions(string module, BitAccess bits, uint limit, bool readStrings) { var mod = StripNamespace(module); var begin = bits.Position; var count = 0; while (bits.Position < limit) { ushort siz; ushort rec; bits.ReadUInt16(out siz); var star = bits.Position; var stop = bits.Position + siz; bits.Position = star; bits.ReadUInt16(out rec); switch ((SYM)rec) { case SYM.S_GMANPROC: case SYM.S_LMANPROC: ManProcSym proc; bits.ReadUInt32(out proc.parent); bits.ReadUInt32(out proc.end); bits.Position = (int)proc.end; count++; break; case SYM.S_END: bits.Position = stop; break; default: // Console.WriteLine("{0,6}: {1:x2} {2}", // bits.Position, rec, (SYM)rec); bits.Position = stop; break; } } if (count == 0) { return null; } bits.Position = begin; var funcs = new PdbFunction[count]; var func = 0; while (bits.Position < limit) { ushort siz; ushort rec; bits.ReadUInt16(out siz); var star = bits.Position; var stop = bits.Position + siz; bits.ReadUInt16(out rec); switch ((SYM)rec) { case SYM.S_GMANPROC: case SYM.S_LMANPROC: ManProcSym proc; var offset = bits.Position; bits.ReadUInt32(out proc.parent); bits.ReadUInt32(out proc.end); bits.ReadUInt32(out proc.next); bits.ReadUInt32(out proc.len); bits.ReadUInt32(out proc.dbgStart); bits.ReadUInt32(out proc.dbgEnd); bits.ReadUInt32(out proc.token); bits.ReadUInt32(out proc.off); bits.ReadUInt16(out proc.seg); bits.ReadUInt8(out proc.flags); bits.ReadUInt16(out proc.retReg); if (readStrings) { bits.ReadCString(out proc.name); } else { bits.SkipCString(out proc.name); } // Console.WriteLine("token={0:X8} [{1}::{2}]", proc.token, module, proc.name); bits.Position = stop; funcs[func++] = new PdbFunction(module, proc, bits); break; default: { // throw new PdbDebugException("Unknown SYMREC {0}", (SYM)rec); bits.Position = stop; break; } } } return funcs; }
/// <summary> /// </summary> /// <param name="funcs"> /// </param> /// <param name="names"> /// </param> /// <param name="bits"> /// </param> /// <param name="dir"> /// </param> /// <param name="nameIndex"> /// </param> /// <param name="reader"> /// </param> /// <param name="limit"> /// </param> private static void LoadManagedLines( PdbFunction[] funcs, IntHashTable names, BitAccess bits, MsfDirectory dir, Dictionary<string, int> nameIndex, PdbReader reader, uint limit) { Array.Sort(funcs, PdbFunction.byAddress); var checks = new IntHashTable(); // Read the files first var begin = bits.Position; while (bits.Position < limit) { int sig; int siz; bits.ReadInt32(out sig); bits.ReadInt32(out siz); var place = bits.Position; var endSym = bits.Position + siz; switch ((DEBUG_S_SUBSECTION)sig) { case DEBUG_S_SUBSECTION.FILECHKSMS: while (bits.Position < endSym) { CV_FileCheckSum chk; var ni = bits.Position - place; bits.ReadUInt32(out chk.name); bits.ReadUInt8(out chk.len); bits.ReadUInt8(out chk.type); var name = (string)names[(int)chk.name]; int guidStream; var doctypeGuid = SymDocumentType.Text; var languageGuid = SymLanguageType.CSharp; var vendorGuid = SymLanguageVendor.Microsoft; if (nameIndex.TryGetValue("/src/files/" + name, out guidStream)) { var guidBits = new BitAccess(0x100); dir.streams[guidStream].Read(reader, guidBits); LoadGuidStream(guidBits, out doctypeGuid, out languageGuid, out vendorGuid); } var src = new PdbSource((uint)ni, name, doctypeGuid, languageGuid, vendorGuid); checks.Add(ni, src); bits.Position += chk.len; bits.Align(4); } bits.Position = endSym; break; default: bits.Position = endSym; break; } } // Read the lines next. bits.Position = begin; while (bits.Position < limit) { int sig; int siz; bits.ReadInt32(out sig); bits.ReadInt32(out siz); var endSym = bits.Position + siz; switch ((DEBUG_S_SUBSECTION)sig) { case DEBUG_S_SUBSECTION.LINES: { CV_LineSection sec; bits.ReadUInt32(out sec.off); bits.ReadUInt16(out sec.sec); bits.ReadUInt16(out sec.flags); bits.ReadUInt32(out sec.cod); var func = FindFunction(funcs, sec.sec, sec.off); if (func == null) { break; } // Count the line blocks. var begSym = bits.Position; var blocks = 0; while (bits.Position < endSym) { CV_SourceFile file; bits.ReadUInt32(out file.index); bits.ReadUInt32(out file.count); bits.ReadUInt32(out file.linsiz); // Size of payload. var linsiz = (int)file.count * (8 + ((sec.flags & 1) != 0 ? 4 : 0)); bits.Position += linsiz; blocks++; } func.lines = new PdbLines[blocks]; var block = 0; bits.Position = begSym; while (bits.Position < endSym) { CV_SourceFile file; bits.ReadUInt32(out file.index); bits.ReadUInt32(out file.count); bits.ReadUInt32(out file.linsiz); // Size of payload. var src = (PdbSource)checks[(int)file.index]; var tmp = new PdbLines(src, file.count); func.lines[block++] = tmp; var lines = tmp.lines; var plin = bits.Position; var pcol = bits.Position + 8 * (int)file.count; for (var i = 0; i < file.count; i++) { CV_Line line; var column = new CV_Column(); bits.Position = plin + 8 * i; bits.ReadUInt32(out line.offset); bits.ReadUInt32(out line.flags); var lineBegin = line.flags & (uint)CV_Line_Flags.linenumStart; var delta = (line.flags & (uint)CV_Line_Flags.deltaLineEnd) >> 24; var statement = (line.flags & (uint)CV_Line_Flags.fStatement) == 0; if ((sec.flags & 1) != 0) { bits.Position = pcol + 4 * i; bits.ReadUInt16(out column.offColumnStart); bits.ReadUInt16(out column.offColumnEnd); } lines[i] = new PdbLine(line.offset, lineBegin, column.offColumnStart, lineBegin + delta, column.offColumnEnd); } } break; } } bits.Position = endSym; } }
/// <summary> /// </summary> /// <param name="bits"> /// </param> /// <exception cref="PdbDebugException"> /// </exception> private void ReadCustomMetadata(BitAccess bits) { var savedPosition = bits.Position; byte version; bits.ReadUInt8(out version); if (version != 4) { throw new PdbDebugException("Unknown custom metadata item version: {0}", version); } byte kind; bits.ReadUInt8(out kind); bits.Align(4); uint numberOfBytesInItem; bits.ReadUInt32(out numberOfBytesInItem); switch (kind) { case 0: this.ReadUsingInfo(bits); break; case 1: this.ReadForwardInfo(bits); break; case 2: this.ReadForwardedToModuleInfo(bits); break; case 3: this.ReadIteratorLocals(bits); break; case 4: this.ReadForwardIterator(bits); break; default: throw new PdbDebugException("Unknown custom metadata item kind: {0}", kind); } bits.Position = savedPosition + (int)numberOfBytesInItem; }
/// <summary> /// </summary> /// <param name="bits"> /// </param> /// <returns> /// </returns> /// <exception cref="PdbDebugException"> /// </exception> private static Dictionary<string, int> LoadNameIndex(BitAccess bits) { var result = new Dictionary<string, int>(); int ver; int sig; int age; Guid guid; bits.ReadInt32(out ver); // 0..3 Version bits.ReadInt32(out sig); // 4..7 Signature bits.ReadInt32(out age); // 8..11 Age bits.ReadGuid(out guid); // 12..27 GUID if (ver != 20000404) { throw new PdbDebugException("Unsupported PDB Stream version {0}", ver); } // Read string buffer. int buf; bits.ReadInt32(out buf); // 28..31 Bytes of Strings var beg = bits.Position; var nxt = bits.Position + buf; bits.Position = nxt; // Read map index. int cnt; // n+0..3 hash size. int max; // n+4..7 maximum ni. bits.ReadInt32(out cnt); bits.ReadInt32(out max); var present = new BitSet(bits); var deleted = new BitSet(bits); if (!deleted.IsEmpty) { throw new PdbDebugException("Unsupported PDB deleted bitset is not empty."); } var j = 0; for (var i = 0; i < max; i++) { if (present.IsSet(i)) { int ns; int ni; bits.ReadInt32(out ns); bits.ReadInt32(out ni); string name; var saved = bits.Position; bits.Position = beg + ns; bits.ReadCString(out name); bits.Position = saved; result.Add(name, ni); j++; } } if (j != cnt) { throw new PdbDebugException("Count mismatch. ({0} != {1})", j, cnt); } return result; }