/// <summary> /// </summary> /// <param name="function"> /// </param> private void ConvertVariables(PdbFunction function) { foreach (var scope in function.scopes) { this.ConvertScope(scope); } }
/// <summary> /// </summary> /// <param name="function"> /// </param> /// <param name="generateFileOnly"> /// </param> private void ConvertFunction(PdbFunction function, bool generateFileOnly = false) { if (function.lines == null) { return; } var method = new SourceMethod { Token = (int)function.token, Name = function.name, LinkageName = function.name, DisplayName = function.name, LineNumber = function.lines.First().lines.First().lineBegin }; var file = this.GetSourceFile(this.symbolWriter, function); if (generateFileOnly) { return; } var builder = this.symbolWriter.OpenMethod(file.CompilationUnitEntry, method); this.ConvertSequencePoints(function, file, builder); this.ConvertVariables(function); this.symbolWriter.CloseMethod(); }
public void ConvertFunction(int token) { PdbFunction func = null; if (this.funcs.TryGetValue((uint)token, out func)) { this.ConvertFunction(func); return; } if (token == -1) { this.ConvertFunction(this.funcs.Values.First(f => f.lines != null), true); } }
/// <summary> /// </summary> /// <param name="function"> /// </param> /// <param name="file"> /// </param> /// <param name="builder"> /// </param> private void ConvertSequencePoints(PdbFunction function, SourceFile file, ISourceMethodBuilder builder) { var lastLine = 0; foreach (var line in function.lines.SelectMany(lines => lines.lines)) { // 0xfeefee is an MS convention, we can't pass it into ISymbolWriter, so we use the last non-hidden line var isHidden = line.lineBegin == 0xfeefee; builder.MarkSequencePoint( (int)line.offset, file, isHidden ? lastLine : (int)line.lineBegin, (int)line.colBegin, isHidden); if (!isHidden) { lastLine = (int)line.lineBegin; } } }
/// <summary> /// </summary> /// <param name="symbolWriter"> /// </param> /// <param name="function"> /// </param> /// <returns> /// </returns> private SourceFile GetSourceFile(ISymbolWriter symbolWriter, PdbFunction function) { var name = (from l in function.lines where l.file != null select l.file.name).First(); SourceFile file; if (this.files.TryGetValue(name, out file)) { return(file); } var entry = symbolWriter.DefineDocument(name); var unit = symbolWriter.DefineCompilationUnit(entry); file = new SourceFile(unit, entry); this.files.Add(name, file); return(file); }
/// <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="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="funcs"> /// </param> /// <param name="sec"> /// </param> /// <param name="off"> /// </param> /// <returns> /// </returns> private static PdbFunction FindFunction(PdbFunction[] funcs, ushort sec, uint off) { match.segment = sec; match.address = off; var item = Array.BinarySearch(funcs, match, PdbFunction.byAddress); if (item >= 0) { return funcs[item]; } return null; }
/// <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="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="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="symbolWriter"> /// </param> /// <param name="function"> /// </param> /// <returns> /// </returns> private SourceFile GetSourceFile(ISymbolWriter symbolWriter, PdbFunction function) { var name = (from l in function.lines where l.file != null select l.file.name).First(); SourceFile file; if (this.files.TryGetValue(name, out file)) { return file; } var entry = symbolWriter.DefineDocument(name); var unit = symbolWriter.DefineCompilationUnit(entry); file = new SourceFile(unit, entry); this.files.Add(name, file); return file; }