public MethodDebugInfo(MethodBody body, ISymbolMethod pdb) { Body = body; // todo. support multiple locals sharing the same local slot // (but having different Start::End offsets, of course) // so far we just silently ignore them taking into account only the first one var locals = pdb.RootScope.Flatten(ss => ss.GetChildren()).SelectMany(ss => ss.GetLocals()); LocalNames = locals.Select(lv => new { Index = lv.AddressField1, Name = lv.Name }) .Distinct().ToDictionary(lv => lv.Index, lv => lv.Name).ToReadOnly(); var count = pdb.SequencePointCount; var offsets = new int[count]; var documents = new ISymbolDocument[count]; var lines = new int[count]; var columns = new int[count]; var endLines = new int[count]; var endColumns = new int[count]; pdb.GetSequencePoints(offsets, documents, lines, columns, endLines, endColumns); SequencePoints = 0.UpTo(count - 1).Select(i => new SequencePoint(offsets[i], documents[i], lines[i], columns[i], endLines[i], endColumns[i]) ).ToReadOnly(); }
void AddSequencePoints(CilBody body, ISymbolMethod method) { int numSeqs = method.SequencePointCount; var offsets = new int[numSeqs]; var documents = new ISymbolDocument[numSeqs]; var lines = new int[numSeqs]; var columns = new int[numSeqs]; var endLines = new int[numSeqs]; var endColumns = new int[numSeqs]; method.GetSequencePoints(offsets, documents, lines, columns, endLines, endColumns); int instrIndex = 0; for (int i = 0; i < numSeqs; i++) { var instr = GetInstruction(body.Instructions, offsets[i], ref instrIndex); if (instr == null) { continue; } var seqPoint = new SequencePoint() { Document = Add_NoLock(new PdbDocument(documents[i])), StartLine = lines[i], StartColumn = columns[i], EndLine = endLines[i], EndColumn = endColumns[i], }; instr.SequencePoint = seqPoint; } }
public SequencePoint[] Generate(ISymbolMethod method) { var sequencePoints = new List<SequencePoint>(); var sp_count = method.SequencePointCount; var spOffsets = new int[sp_count]; // Array.CreateInstance(int, sp_count) var spDocs = new ISymbolDocument[sp_count]; // Array.CreateInstance(ISymbolDocument, sp_count) var spStartLines = new int[sp_count]; // Array.CreateInstance(int, sp_count) var spEndLines = new int[sp_count]; // Array.CreateInstance(int, sp_count) var spStartCol = new int[sp_count]; // Array.CreateInstance(int, sp_count) var spEndCol = new int[sp_count]; // Array.CreateInstance(int, sp_count) method.GetSequencePoints(spOffsets, spDocs, spStartLines, spStartCol, spEndLines, spEndCol); for (int i = 0; i < sp_count; i++) // (var i in range(sp_count)) { if (spStartLines[i] != 0xfeefee) // if spStartLines[i] != 0xfeefee: { sequencePoints.Add(new SequencePoint(spOffsets[i], spDocs[i], spStartLines[i], spStartCol[i], spEndLines[i], spEndCol[i])); } } return sequencePoints.ToArray(); }
// Write the sequence points for the given method // Sequence points are the map between IL offsets and source lines. // A single method could span multiple files (use C#'s #line directive to see for yourself). private SequencePoint[] ReadSequencePoints(ISymbolMethod method) { int count = method.SequencePointCount; // Get the sequence points from the symbol store. // We could cache these arrays and reuse them. int[] offsets = new int[count]; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] startColumn = new int[count]; int[] endColumn = new int[count]; int[] startRow = new int[count]; int[] endRow = new int[count]; method.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); // Store them into the list var sequencePoints = new List <SequencePoint>(count); for (int i = 0; i < count; i++) { var sp = new SequencePoint(offsets[i], docs[i].URL, startRow[i], endRow[i], startColumn[i], endColumn[i]); sequencePoints.Add(sp); } return(sequencePoints.OrderBy(sp => sp.SourcePath).ThenBy(sp => sp.StartLine).ToArray()); }
static void Main(string[] args) { Assembly ass = Assembly.GetExecutingAssembly(); ISymbolReader symreader = SymUtil.GetSymbolReaderForFile(ass.Location, null); MethodInfo m = ass.GetType("PdbTest.TestClass").GetMethod("GetStringRepresentation"); ISymbolMethod met = symreader.GetMethod(new SymbolToken(m.MetadataToken)); int count = met.SequencePointCount; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] offsets = new int[count]; int[] lines = new int[count]; int[] columns = new int[count]; int[] endlines = new int[count]; int[] endcolumns = new int[count]; met.GetSequencePoints(offsets, docs, lines, columns, endlines, endcolumns); StreamReader reader = new StreamReader(docs[0].URL); string[] linesOfCode = reader.ReadToEnd().Split('n'); reader.Close(); Console.WriteLine("The content of method PdbTest.TestClass.GetStringRepresentation"); for (int i = lines[0]; i < endlines[count - 1] - 1; i++) { Console.WriteLine(linesOfCode[i]); } }
//�Public�Methods�(1)� /// <summary> /// Gets the method source from PDB. /// </summary> /// <param name="methodInfo">The method info.</param> /// <returns></returns> public PDBMethodSourceData GetMethodSourceFromPDB(MethodInfo methodInfo) { ISymbolMethod met = _symbolReader.GetMethod(new SymbolToken(methodInfo.MetadataToken)); int count = met.SequencePointCount; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] offsets = new int[count]; int[] lines = new int[count]; int[] columns = new int[count]; int[] endlines = new int[count]; int[] endcolumns = new int[count]; met.GetSequencePoints(offsets, docs, lines, columns, endlines, endcolumns); return(new PDBMethodSourceData() { symbolDocs = docs, sourceCodeLines = lines, ilOpcodeOffsets = offsets, souceCodeColumns = columns, sourceCodeEndColumns = endcolumns, sourceCodeEndLines = endlines }); }
/// <summary> /// Returns the name of the file for the given method using the given symbol reader /// </summary> /// <param name="reader">The reader to use</param> /// <param name="methodBase">The method to lookup</param> /// <returns>The file containing the method or null.</returns> private static string GetFileForMethod(ISymbolReader reader, MethodBase methodBase) { int token = methodBase.MetadataToken; ISymbolMethod methodSymbol = reader == null ? null : reader.GetMethod(new SymbolToken(token)); if (methodSymbol != null) { int count = methodSymbol.SequencePointCount; // Get the sequence points from the symbol store. // We could cache these arrays and reuse them. int[] offsets = new int[count]; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] startColumn = new int[count]; int[] endColumn = new int[count]; int[] startRow = new int[count]; int[] endRow = new int[count]; methodSymbol.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); foreach (ISymbolDocument doc in docs) { string file = doc.URL.ToString(); return(file); } } return(null); }
public static IEnumerable <SequencePoint> GetSequencePoints(this ISymbolMethod met) { int sc = met.SequencePointCount; int[] offsets = new int[sc]; int[] lines = new int[sc]; int[] endLines = new int[sc]; int[] columns = new int[sc]; int[] endColumns = new int[sc]; ISymbolDocument[] docs = new ISymbolDocument[sc]; met.GetSequencePoints(offsets, docs, lines, columns, endLines, endColumns); for (int n = 0; n < sc; n++) { if (columns[n] == 0) { continue; } SequencePoint sp = new SequencePoint(); sp.Document = docs[n]; sp.Line = lines[n]; sp.Offset = offsets[n]; yield return(sp); } }
// note: sadly it's not possible to cache all the [count] allocations and reuse them. // a NRE is throw if the size of the arrays does not match SequencePointCount :( void ReadSequencePoints(ISymbolMethod method, IDictionary instructions) { int count = method.SequencePointCount; int [] offsets = new int [count]; ISymbolDocument [] docs = new ISymbolDocument [count]; int [] startColumn = new int [count]; int [] endColumn = new int [count]; int [] startRow = new int [count]; int [] endRow = new int [count]; method.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); for (int i = 0; i < offsets.Length; i++) { Cil.Instruction instr = (Cil.Instruction)instructions [offsets [i]]; Cil.SequencePoint sp = new Cil.SequencePoint(GetDocument(docs [i])); sp.StartLine = startRow [i]; sp.StartColumn = startColumn [i]; sp.EndLine = endRow [i]; sp.EndColumn = endColumn [i]; instr.SequencePoint = sp; } }
// Initializes all private symbol variables private void SetupSymbolInformation() { if (p_symbolsInitialized) { return; } p_symbolsInitialized = true; CorModule module = GetModule(); ISymbolReader symreader = module.GetSymbolReader(); p_hasSymbols = symreader != null; if (p_hasSymbols) { ISymbolMethod sm = null; sm = symreader.GetMethod(new SymbolToken((Int32)GetToken())); // FIXME add version if (sm == null) { p_hasSymbols = false; return; } p_symMethod = sm; p_SPcount = p_symMethod.SequencePointCount; p_SPoffsets = new Int32[p_SPcount]; p_SPdocuments = new ISymbolDocument[p_SPcount]; p_SPstartLines = new Int32[p_SPcount]; p_SPendLines = new Int32[p_SPcount]; p_SPstartColumns = new Int32[p_SPcount]; p_SPendColumns = new Int32[p_SPcount]; p_symMethod.GetSequencePoints(p_SPoffsets, p_SPdocuments, p_SPstartLines, p_SPstartColumns, p_SPendLines, p_SPendColumns); } }
/// <summary> /// Gets information about the source if it is available. /// </summary> private bool GetSourceReference() { try { ISymbolReader sr = SymUtil.GetSymbolReaderForFile(_method.Module.Assembly.Location, null); ISymbolMethod sm = sr.GetMethod(new SymbolToken(_method.MetadataToken)); _count = sm.SequencePointCount; _offsets = new int[_count]; _documents = new ISymbolDocument[_count]; _startColumns = new int[_count]; _endColumns = new int[_count]; _startRows = new int[_count]; _endRows = new int[_count]; sm.GetSequencePoints(_offsets, _documents, _startRows, _startColumns, _endRows, _endColumns); return(true); } catch { _count = 0; _offsets = null; _documents = null; _startColumns = null; _endColumns = null; _startRows = null; _endRows = null; return(false); } }
//private string[] GetCombinedSource(IEnumerable<SequencePoint> points) { // var lines = new List<string>(); // foreach (var point in points) { // var contentLines = documentCache.Get(point.Document, () => File.ReadAllLines(point.Document.URL)); // var start = point.Start.Row - 1; // var end = point.End.Row - 1; // if (start >= contentLines.Length || end >= contentLines.Length) // continue; // for (var i = start; i <= end; i++) { // var line = contentLines[i]; // if (i == start) // line = line.Substring(point.Start.Column - 1); // else if (i == end) // line = line.Substring(0, point.End.Column - 1); // lines.Add(line); // } // } // return lines.ToArray(); //} private IEnumerable <SequencePoint> GetSequencePoints(ISymbolMethod method) { var count = method.SequencePointCount; var offsets = new int[count]; var docs = new ISymbolDocument[count]; var startColumns = new int[count]; var endColumns = new int[count]; var startRows = new int[count]; var endRows = new int[count]; method.GetSequencePoints(offsets, docs, startRows, startColumns, endRows, endColumns); for (int i = 0; i < count; i++) { if (startRows[i] == SequencePointHiddenLine || endRows[i] == SequencePointHiddenLine) { continue; } yield return(new SequencePoint { Document = this.GetOrLoadContent(docs[i]), Start = new SourcePosition(startRows[i], startColumns[i]), End = new SourcePosition(endRows[i], endColumns[i]) }); } }
protected override BreakEventInfo OnInsertBreakEvent(BreakEvent be) { BreakEventInfo binfo = new BreakEventInfo(); lock (documents) { Breakpoint bp = be as Breakpoint; if (bp != null) { DocInfo doc; if (!documents.TryGetValue(System.IO.Path.GetFullPath(bp.FileName), out doc)) { binfo.SetStatus(BreakEventStatus.NotBound, null); return(binfo); } int line; try { line = doc.Document.FindClosestLine(bp.Line); } catch { // Invalid line binfo.SetStatus(BreakEventStatus.Invalid, null); return(binfo); } ISymbolMethod met = doc.Reader.GetMethodFromDocumentPosition(doc.Document, line, 0); if (met == null) { binfo.SetStatus(BreakEventStatus.Invalid, null); return(binfo); } int offset = -1; foreach (SequencePoint sp in met.GetSequencePoints()) { if (sp.Line == line && sp.Document.URL == doc.Document.URL) { offset = sp.Offset; break; } } if (offset == -1) { binfo.SetStatus(BreakEventStatus.Invalid, null); return(binfo); } CorFunction func = doc.Module.GetFunctionFromToken(met.Token.GetToken()); CorFunctionBreakpoint corBp = func.ILCode.CreateBreakpoint(offset); corBp.Activate(bp.Enabled); breakpoints[corBp] = binfo; binfo.Handle = corBp; binfo.SetStatus(BreakEventStatus.Bound, null); return(binfo); } } return(null); }
public static void GetLocalVariables(Assembly asm, MethodInfo m) { // Assembly asm = Assembly.GetExecutingAssembly(); ISymbolReader symreader = SymUtil.GetSymbolReaderForFile(asm.Location, null); if (symreader == null) { Console.WriteLine(" ERROR: no symreader was created. Aborting GetLocalVariables..."); return; } ISymbolMethod symMethod = symreader.GetMethod(new SymbolToken(m.MetadataToken)); int sequencePointCount = symMethod.SequencePointCount; ISymbolDocument[] docs = new ISymbolDocument[sequencePointCount]; int[] offsets = new int[sequencePointCount]; int[] lines = new int[sequencePointCount]; int[] columns = new int[sequencePointCount]; int[] endlines = new int[sequencePointCount]; int[] endcolumns = new int[sequencePointCount]; symMethod.GetSequencePoints(offsets, docs, lines, columns, endlines, endcolumns); Console.WriteLine(); Console.WriteLine("The source code for method: " + m.Name + "; found in " + docs[0].URL); Console.WriteLine(new String('*', 60)); // although there's an array of docs, they seem to all have the same value (?) so we'll only use the first one StreamReader reader = new StreamReader(docs[0].URL); // URL is typically a fully path-qualified filename string[] linesOfCode = reader.ReadToEnd().Split('\r'); string PrintableLineNumber = "0000"; Console.WriteLine(linesOfCode[lines[0] - 2].Replace('\n', ' ')); // the preceding line (assumes declaration is only one line long, and found on immediately precediting line! // foreach (int LineNumber in lines) // print the source code (comments omitted) for (int LineNumber = lines[0]; LineNumber < lines[sequencePointCount - 1] + 1; LineNumber++) // print the source code (including comments) { PrintableLineNumber = new String(' ', 4 - LineNumber.ToString().Length) // padding + LineNumber.ToString(); Console.WriteLine(PrintableLineNumber + ": " + linesOfCode[LineNumber - 1].Replace('\n', ' ')); } // Console.WriteLine(linesOfCode[lines[sequencePointCount -1] + 1].Replace('\n', ' ')); // the trailing line //Console.WriteLine(linesOfCode); reader.Close(); Console.WriteLine(new String('*', 60)); Console.WriteLine(); linesOfCode = null; }
protected override object OnInsertBreakEvent(BreakEvent be, bool activate) { lock (documents) { Breakpoint bp = be as Breakpoint; if (bp != null) { DocInfo doc; if (!documents.TryGetValue(System.IO.Path.GetFullPath(bp.FileName), out doc)) { return(null); } int line; try { line = doc.Document.FindClosestLine(bp.Line); } catch { // Invalid line return(null); } ISymbolMethod met = doc.Reader.GetMethodFromDocumentPosition(doc.Document, line, 0); if (met == null) { return(null); } int offset = -1; foreach (SequencePoint sp in met.GetSequencePoints()) { if (sp.Line == line && sp.Document.URL == doc.Document.URL) { offset = sp.Offset; break; } } if (offset == -1) { return(null); } CorFunction func = doc.Module.GetFunctionFromToken(met.Token.GetToken()); CorFunctionBreakpoint corBp = func.ILCode.CreateBreakpoint(offset); corBp.Activate(activate); return(corBp); } } return(null); }
ISymbolDocument[] GetDocumentList(ISymbolMethod method) { int count = method.SequencePointCount; // Get the sequence points from the symbol store. // We could cache these arrays and reuse them. int[] offsets = new int[count]; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] startColumn = new int[count]; int[] endColumn = new int[count]; int[] startRow = new int[count]; int[] endRow = new int[count]; method.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); return docs; }
// Write the sequence points for the given method // Sequence points are the map between IL offsets and source lines. // A single method could span multiple files (use C#'s #line directive to see for yourself). private void WriteSequencePoints(ISymbolMethod method) { m_writer.WriteStartElement("sequencepoints"); int count = method.SequencePointCount; m_writer.WriteAttributeString("total", Util.CultureInvariantToString(count)); // Get the sequence points from the symbol store. // We could cache these arrays and reuse them. var offsets = new int[count]; var docs = new ISymbolDocument[count]; var startColumn = new int[count]; var endColumn = new int[count]; var startRow = new int[count]; var endRow = new int[count]; method.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); // Write out sequence points for (int i = 0; i < count; i++) { m_writer.WriteStartElement("entry"); m_writer.WriteAttributeString("il_offset", Util.AsIlOffset(offsets[i])); // If it's a special 0xFeeFee sequence point (eg, "hidden"), // place an attribute on it to make it very easy for tools to recognize. // See http://blogs.msdn.com/jmstall/archive/2005/06/19/FeeFee_SequencePoints.aspx if (startRow[i] == 0xFeeFee) { m_writer.WriteAttributeString("hidden", XmlConvert.ToString(true)); } //else { m_writer.WriteAttributeString("start_row", Util.CultureInvariantToString(startRow[i])); m_writer.WriteAttributeString("start_column", Util.CultureInvariantToString(startColumn[i])); m_writer.WriteAttributeString("end_row", Util.CultureInvariantToString(endRow[i])); m_writer.WriteAttributeString("end_column", Util.CultureInvariantToString(endColumn[i])); m_writer.WriteAttributeString("file_ref", Util.CultureInvariantToString(m_fileMapping[docs[i].URL])); } m_writer.WriteEndElement(); } m_writer.WriteEndElement(); // sequencepoints }
// Write the sequence points for the given method // Sequence points are the map between IL offsets and source lines. // A single method could span multiple files (use C#'s #line directive to see for yourself). private void WriteSequencePoints(ISymbolMethod method) { int count = method.SequencePointCount; // Get the sequence points from the symbol store. // We could cache these arrays and reuse them. int[] offsets = new int[count]; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] startColumn = new int[count]; int[] endColumn = new int[count]; int[] startRow = new int[count]; int[] endRow = new int[count]; method.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); xmlWriter.WriteStartElement("sequencePoints"); for (int i = 0; i < count; i++) { xmlWriter.WriteStartElement("entry"); // IL offsets are usually written in hexadecimal... xmlWriter.WriteAttributeString("ilOffset", "0x" + offsets[i].ToString("x4")); // ... but .NET XPath 1.0 cannot compare strings so we need a decimal number as well :-( xmlWriter.WriteAttributeString("ilOffsetDec", offsets[i].ToString()); xmlWriter.WriteAttributeString("fileRef", fileMapping[docs[i].URL].ToString()); // If it's a special 0xfeefee sequence point (e.g., "hidden"), // place an attribute on it to make it very easy for tools to recognize. // See http://blogs.msdn.com/b/jmstall/archive/2005/06/19/feefee-sequencepoints.aspx if (startRow[i] == 0xfeefee) { xmlWriter.WriteAttributeString("hidden", "true"); } else { xmlWriter.WriteAttributeString("startLine", startRow[i].ToString()); xmlWriter.WriteAttributeString("startColumn", startColumn[i].ToString()); xmlWriter.WriteAttributeString("endLine", endRow[i].ToString()); xmlWriter.WriteAttributeString("endColumn", endColumn[i].ToString()); } xmlWriter.WriteEndElement(); // </entry> } xmlWriter.WriteEndElement(); // </sequencePoints> }
// Write the sequence points for the given method // Sequence points are the map between IL offsets and source lines. // A single method could span multiple files (use C#'s #line directive to see for yourself). private List <SequencePoint> ReadSequencePoints(ISymbolMethod method) { int count = method.SequencePointCount; // Get the sequence points from the symbol store. // We could cache these arrays and reuse them. int[] offsets = new int[count]; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] startColumn = new int[count]; int[] endColumn = new int[count]; int[] startRow = new int[count]; int[] endRow = new int[count]; method.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); // Store them into the list List <SequencePoint> sequencePoints = new List <SequencePoint>(count); for (int i = 0; i < count; i++) { SequencePoint sp = new SequencePoint(); sp.ilOffset = offsets[i]; // If it's a special 0xFeeFee sequence point (eg, "hidden"), // place an attribute on it to make it very easy for tools to recognize. // See http://blogs.msdn.com/jmstall/archive/2005/06/19/FeeFee_SequencePoints.aspx if (startRow[i] == 0xFeeFee) { sp.hidden = true; } sp.sourceId = this.fileMapping[docs[i].URL]; sp.startRow = startRow[i]; sp.startColumn = startColumn[i]; sp.endRow = endRow[i]; sp.endColumn = endColumn[i]; sequencePoints.Add(sp); } return(sequencePoints); }
////////////////////////////////////////////////////////////////////////////////// // // Initialization & locals // ////////////////////////////////////////////////////////////////////////////////// private void EnsureIsUpToDate() { Debug.Assert(m_module != null); Debug.Assert(m_module.EditsCounter >= CorFunction.Version - 1); // version cannot be greater then # of edits; versions are 1 based if (m_isInitialized) { return; // no need to do any refresh } // perform refresh m_isInitialized = true; m_haveSymbols = m_module.SymReader != null; if (m_haveSymbols) { ISymbolMethod sm = null; sm = m_module.SymReader.GetMethod(new SymbolToken(m_function.Token), CorFunction.Version); if (sm == null) { m_haveSymbols = false; return; } m_symMethod = sm; m_SPcount = m_symMethod.SequencePointCount; m_SPoffsets = new int[m_SPcount]; m_SPdocuments = new ISymbolDocument[m_SPcount]; m_SPstartLines = new int[m_SPcount]; m_SPendLines = new int[m_SPcount]; m_SPstartColumns = new int[m_SPcount]; m_SPendColumns = new int[m_SPcount]; m_symMethod.GetSequencePoints(m_SPoffsets, m_SPdocuments, m_SPstartLines, m_SPstartColumns, m_SPendLines, m_SPendColumns); } }
public MethodDebugInfo(MethodBody body, ISymbolMethod pdb) { Body = body; // todo. support multiple locals sharing the same local slot // (but having different Start::End offsets, of course) // so far we just silently ignore them taking into account only the first one var locals = pdb.RootScope.Flatten(ss => ss.GetChildren()).SelectMany(ss => ss.GetLocals()); LocalNames = locals.Select(lv => new {Index = lv.AddressField1, Name = lv.Name}) .Distinct().ToDictionary(lv => lv.Index, lv => lv.Name).ToReadOnly(); var count = pdb.SequencePointCount; var offsets = new int[count]; var documents = new ISymbolDocument[count]; var lines = new int[count]; var columns = new int[count]; var endLines = new int[count]; var endColumns = new int[count]; pdb.GetSequencePoints(offsets, documents, lines, columns, endLines, endColumns); SequencePoints = 0.UpTo(count - 1).Select(i => new SequencePoint(offsets[i], documents[i], lines[i], columns[i], endLines[i], endColumns[i]) ).ToReadOnly(); }
private void Populate(ISymbolMethod method) { method.GetSequencePoints(Offsets, Documents, Lines, Columns, EndLines, EndColumns); for (int i = 0; i < Count; i++) { this.indexByOffsets.Add(Offsets[i], i); } }
internal static GotoInfo[] LookupLocationsFromPdb(GotoInfo info, IVsSmartOpenScope vsSmartOpenScope) { Debug.Assert(info != null && info.MemberInfo != null, "LookupLocationsFromPdb lacks required parameter"); var sources = new Dictionary <string, Location>(); if (string.IsNullOrEmpty(info.FilePath) || !File.Exists(info.FilePath)) { return(new GotoInfo[0]); } object unkMetaDataImport; IntPtr ptrMetaDataImport = IntPtr.Zero; ISymbolBinder1 binder; ISymbolReader reader; ISymbolDocument[] documents; int[] lines; int[] columns; int[] endLines; int[] endColumns; int[] offsets; var methods = new List <MethodBase>(); Type ty = null; try { int hr = vsSmartOpenScope.OpenScope(info.FilePath, 0, ref IID_MetaDataImport, out unkMetaDataImport); if (hr == VSConstants.S_OK) { ptrMetaDataImport = Marshal.GetIUnknownForObject(unkMetaDataImport); binder = new SymBinder(); reader = binder.GetReader(ptrMetaDataImport, info.FilePath, null); documents = new ISymbolDocument[1]; lines = new int[1]; columns = new int[1]; endLines = new int[1]; endColumns = new int[1]; offsets = new int[1]; } else { Debug.WriteLineIf(TS.TraceWarning, string.Format("Failed to obtain MetaDataImport from VS, hr 0x{0:X8}", hr), TS.DisplayName); return(new GotoInfo[0]); } switch (info.MemberInfo.MemberType) { case MemberTypes.Constructor: case MemberTypes.Method: MethodBase mb = (MethodBase)info.MemberInfo; // Abstract methods does not contain any code. // if (mb.IsAbstract) { methods.AddRange(mb.DeclaringType.GetMethods(DeclaredMembers)); } else { methods.Add(mb); } break; case MemberTypes.Property: PropertyInfo pi = (PropertyInfo)info.MemberInfo; methods.AddRange(pi.GetAccessors(true)); break; case MemberTypes.Field: methods.AddRange(info.MemberInfo.DeclaringType.GetMethods(DeclaredMembers)); break; case MemberTypes.Event: EventInfo ei = (EventInfo)info.MemberInfo; methods.Add(ei.GetAddMethod(true)); methods.Add(ei.GetRemoveMethod(true)); methods.Add(ei.GetRaiseMethod(true)); methods.AddRange(ei.GetOtherMethods(true)); break; case MemberTypes.TypeInfo: case MemberTypes.NestedType: ty = (Type)info.MemberInfo; methods.AddRange(ty.GetMethods(DeclaredMembers)); methods.AddRange(ty.GetConstructors(DeclaredMembers)); break; default: Trace.Fail("Unexpected MemberType " + info.MemberInfo.MemberType); break; } foreach (MethodBase mb in methods) { if (mb == null || Attribute.GetCustomAttribute(mb, typeof(CompilerGeneratedAttribute)) != null) { continue; } try { SymbolToken token = new SymbolToken(mb.MetadataToken); ISymbolMethod method = reader.GetMethod(token); if (method.SequencePointCount > 0) { method.GetSequencePoints(offsets, documents, lines, columns, endLines, endColumns); var path = documents[0].URL; // We are interested in unique files only. if (File.Exists(path) && (ty == null || mb.DeclaringType.Equals(ty))) { Location value; if (sources.TryGetValue(path, out value)) { if ((value.Column == 0 || value.Line == 0) && lines[0] != 0 && columns[0] != 0) { sources[path] = new Location(path, lines[0], columns[0], endLines[0], endColumns[0]); } } else { sources.Add(path, new Location(path, lines[0], columns[0], endLines[0], endColumns[0])); } } } } catch (COMException ex) { // Abstract method or not a method at all. // Sequence points are available only for methods. // Trace.WriteLineIf(TS.TraceError, string.Format("({0}) {1}, code 0x{2:X8}", mb.Name, ex.Message, ex.ErrorCode), TS.DisplayName); } } } catch (COMException ex) { // The file was not found or source locations were stripped from the pdb. // Trace.WriteLineIf(TS.TraceError, string.Format("{0}, code 0x{1:8X}", ex.Message, ex.ErrorCode), TS.DisplayName); } finally { if (ptrMetaDataImport != IntPtr.Zero) { Marshal.Release(ptrMetaDataImport); } } return(sources.Select(x => new GotoInfo(x.Key, x.Value)).ToArray()); }
void AddSequencePoints(CilBody body, ISymbolMethod method) { int numSeqs = method.SequencePointCount; var offsets = new int[numSeqs]; var documents = new ISymbolDocument[numSeqs]; var lines = new int[numSeqs]; var columns = new int[numSeqs]; var endLines = new int[numSeqs]; var endColumns = new int[numSeqs]; method.GetSequencePoints(offsets, documents, lines, columns, endLines, endColumns); int instrIndex = 0; for (int i = 0; i < numSeqs; i++) { var instr = GetInstruction(body.Instructions, offsets[i], ref instrIndex); if (instr == null) continue; var seqPoint = new SequencePoint() { Document = Add_NoLock(new PdbDocument(documents[i])), StartLine = lines[i], StartColumn = columns[i], EndLine = endLines[i], EndColumn = endColumns[i], }; instr.SequencePoint = seqPoint; } }
public static SequencePoint GetSequencePoint(CorDebuggerSession session, CorFrame frame) { ISymbolReader reader = session.GetReaderForModule(frame.Function.Module); if (reader == null) { return(null); } ISymbolMethod met = reader.GetMethod(new SymbolToken(frame.Function.Token)); if (met == null) { return(null); } int SequenceCount = met.SequencePointCount; if (SequenceCount <= 0) { return(null); } CorDebugMappingResult mappingResult; uint ip; frame.GetIP(out ip, out mappingResult); if (mappingResult == CorDebugMappingResult.MAPPING_NO_INFO || mappingResult == CorDebugMappingResult.MAPPING_UNMAPPED_ADDRESS) { return(null); } int[] offsets = new int[SequenceCount]; int[] lines = new int[SequenceCount]; int[] endLines = new int[SequenceCount]; int[] columns = new int[SequenceCount]; int[] endColumns = new int[SequenceCount]; ISymbolDocument[] docs = new ISymbolDocument[SequenceCount]; met.GetSequencePoints(offsets, docs, lines, columns, endLines, endColumns); if ((SequenceCount > 0) && (offsets [0] <= ip)) { int i; for (i = 0; i < SequenceCount; ++i) { if (offsets [i] >= ip) { break; } } if ((i == SequenceCount) || (offsets [i] != ip)) { --i; } if (lines [i] == SpecialSequencePoint) { int j = i; // let's try to find a sequence point that is not special somewhere earlier in the code // stream. while (j > 0) { --j; if (lines [j] != SpecialSequencePoint) { return(new SequencePoint() { IsSpecial = true, Offset = offsets [j], StartLine = lines [j], EndLine = endLines [j], StartColumn = columns [j], EndColumn = endColumns [j], Document = docs [j] }); } } // we didn't find any non-special seqeunce point before current one, let's try to search // after. j = i; while (++j < SequenceCount) { if (lines [j] != SpecialSequencePoint) { return(new SequencePoint() { IsSpecial = true, Offset = offsets [j], StartLine = lines [j], EndLine = endLines [j], StartColumn = columns [j], EndColumn = endColumns [j], Document = docs [j] }); } } // Even if sp is null at this point, it's a valid scenario to have only special sequence // point in a function. For example, we can have a compiler-generated default ctor which // doesn't have any source. return(null); } else { return(new SequencePoint() { IsSpecial = false, Offset = offsets [i], StartLine = lines [i], EndLine = endLines [i], StartColumn = columns [i], EndColumn = endColumns [i], Document = docs [i] }); } } return(null); }
// Write the sequence points for the given method // Sequence points are the map between IL offsets and source lines. // A single method could span multiple files (use C#'s #line directive to see for yourself). private List<SequencePoint> ReadSequencePoints(ISymbolMethod method) { int count = method.SequencePointCount; // Get the sequence points from the symbol store. // We could cache these arrays and reuse them. int[] offsets = new int[count]; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] startColumn = new int[count]; int[] endColumn = new int[count]; int[] startRow = new int[count]; int[] endRow = new int[count]; method.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); // Store them into the list List<SequencePoint> sequencePoints = new List<SequencePoint>(count); for (int i = 0; i < count; i++) { SequencePoint sp = new SequencePoint(); sp.ilOffset = offsets[i]; // If it's a special 0xFeeFee sequence point (eg, "hidden"), // place an attribute on it to make it very easy for tools to recognize. // See http://blogs.msdn.com/jmstall/archive/2005/06/19/FeeFee_SequencePoints.aspx if (startRow[i] == 0xFeeFee) { sp.hidden = true; } sp.sourceId = this.m_fileMapping[docs[i].URL]; sp.startRow = startRow[i]; sp.startColumn = startColumn[i]; sp.endRow = endRow[i]; sp.endColumn = endColumn[i]; sequencePoints.Add(sp); } return sequencePoints; }
private void InitSymbolInformation() { if (p_symbolsInitialized) return; p_symbolsInitialized = true; ISymbolReader symreader = Module.GetSymReader(); p_hasSymbols = symreader != null; if (p_hasSymbols) { ISymbolMethod sm = null; sm = symreader.GetMethod(new SymbolToken((Int32)Token)); if (sm == null) { p_hasSymbols = false; return; } p_symMethod = sm; p_SPcount = p_symMethod.SequencePointCount; p_SPoffsets = new Int32[p_SPcount]; p_SPdocuments = new ISymbolDocument[p_SPcount]; p_SPstartLines = new Int32[p_SPcount]; p_SPendLines = new Int32[p_SPcount]; p_SPstartColumns = new Int32[p_SPcount]; p_SPendColumns = new Int32[p_SPcount]; p_symMethod.GetSequencePoints(p_SPoffsets, p_SPdocuments, p_SPstartLines, p_SPstartColumns, p_SPendLines, p_SPendColumns); } }
void Step(bool into) { if (stepper != null) { stepper.IsActive(); CorFrame frame = activeThread.ActiveFrame; ISymbolReader reader = GetReaderForModule(frame.Function.Module.Name); if (reader == null) { RawContinue(into); return; } ISymbolMethod met = reader.GetMethod(new SymbolToken(frame.Function.Token)); if (met == null) { RawContinue(into); return; } uint offset; CorDebugMappingResult mappingResult; frame.GetIP(out offset, out mappingResult); // Find the current line SequencePoint currentSeq = null; foreach (SequencePoint sp in met.GetSequencePoints()) { if (sp.Offset > offset) { break; } currentSeq = sp; } if (currentSeq == null) { RawContinue(into); return; } // Exclude all ranges belonging to the current line List <COR_DEBUG_STEP_RANGE> ranges = new List <COR_DEBUG_STEP_RANGE> (); SequencePoint lastSeq = null; foreach (SequencePoint sp in met.GetSequencePoints()) { if (lastSeq != null && lastSeq.Line == currentSeq.Line) { COR_DEBUG_STEP_RANGE r = new COR_DEBUG_STEP_RANGE(); r.startOffset = (uint)lastSeq.Offset; r.endOffset = (uint)sp.Offset; ranges.Add(r); } lastSeq = sp; } stepper.StepRange(into, ranges.ToArray()); ClearEvalStatus(); process.SetAllThreadsDebugState(CorDebugThreadState.THREAD_RUN, null); process.Continue(false); } }
// Write the sequence points for the given method // Sequence points are the map between IL offsets and source lines. // A single method could span multiple files (use C#'s #line directive to see for yourself). private void WriteSequencePoints(ISymbolMethod method) { writer.WriteStartElement("sequencepoints"); int count = method.SequencePointCount; writer.WriteAttributeString("total", CultureInvariantToString(count)); // Get the sequence points from the symbol store. // We could cache these arrays and reuse them. int[] offsets = new int[count]; ISymbolDocument[] docs = new ISymbolDocument[count]; int[] startColumn = new int[count]; int[] endColumn = new int[count]; int[] startRow = new int[count]; int[] endRow = new int[count]; method.GetSequencePoints(offsets, docs, startRow, startColumn, endRow, endColumn); // Write out sequence points for (int i = 0; i < count; i++) { writer.WriteStartElement("entry"); writer.WriteAttributeString("il_offset", AsILOffset(offsets[i])); // If it's a special 0xFeeFee sequence point (eg, "hidden"), // place an attribute on it to make it very easy for tools to recognize. // See http://blogs.msdn.com/jmstall/archive/2005/06/19/FeeFee_SequencePoints.aspx if (startRow[i] == 0xFeeFee) { writer.WriteAttributeString("hidden", XmlConvert.ToString(true)); } writer.WriteAttributeString("start_row", CultureInvariantToString(startRow[i])); writer.WriteAttributeString("start_column", CultureInvariantToString(startColumn[i])); writer.WriteAttributeString("end_row", CultureInvariantToString(endRow[i])); writer.WriteAttributeString("end_column", CultureInvariantToString(endColumn[i])); //EDMAURER allow there to be PDBs generated for sources that don't have a name (document). int fileRefVal = -1; this.m_fileMapping.TryGetValue(docs[i].URL, out fileRefVal); writer.WriteAttributeString("file_ref", CultureInvariantToString(fileRefVal)); writer.WriteEndElement(); } writer.WriteEndElement(); // sequencepoints }
internal VirtualSourceViewerForm(MainForm parent, MDbgFunction function) { m_function = function; Debug.Assert(function != null); // Now actually right in text. do this first so that we can get the current font. BeginInit(parent); // Get fonts FontCache cache; { Font fontCurrent = richText.Font; var emphasis = new Font( fontCurrent.FontFamily, fontCurrent.Size, FontStyle.Bold ); cache = new FontCache(emphasis); } // Underlying writer to the window. var rawWriter = new RawWriter(cache); // Il2Native mapping can be used to find out what IL offsets we can actually stop on. Il2NativeIterator il2nativeIterator = null; // Actual IL disassembly in string form. ILDasmIterator ilDasm = null; // Iterator through sequence points and source files. SequencePointIterator seqIterator = null; string fullName = "?"; int token = 0; ulong nativeStartAddress = 0; CorDebugJITCompilerFlags codeFlags = CorDebugJITCompilerFlags.CORDEBUG_JIT_DEFAULT; // Make cross-thread call to worker thread to collect raw information. // This needs to access MDbg and so can't be done on our UI thread. parent.ExecuteOnWorkerThreadIfStoppedAndBlock(delegate(MDbgProcess proc) { Debug.Assert(proc != null); Debug.Assert(!proc.IsRunning); Debug.Assert(function.Module.Process == proc); // Get some properties about this function to display. token = function.CorFunction.Token; nativeStartAddress = function.CorFunction.NativeCode.Address; codeFlags = function.CorFunction.NativeCode.CompilerFlags; CorCode ilCode = function.CorFunction.ILCode; Debug.Assert(ilCode.IsIL); byte[] code = ilCode.GetCode(); fullName = function.FullName; // This does the real disassembly work. string[] lines = null; // strings of IL. ILDisassembler.Disassemble(code, function.Module.Importer, out lines, out m_il2RowMapping); ilDasm = new ILDasmIterator(rawWriter, m_il2RowMapping, lines); IL2NativeMap[] il2nativeMapping = function.CorFunction.NativeCode. GetILToNativeMapping(); il2nativeIterator = new Il2NativeIterator(rawWriter, il2nativeMapping, code); // Get sequence points ISymbolMethod symMethod = function.SymMethod; // Sequence point information int[] seqIlOffsets = null; string[] seqPaths = null; int[] seqStartLines = null, seqEndLines = null, seqStartColumns = null, seqEndColumns = null; int seqCount = 0; if (symMethod != null) { seqCount = symMethod.SequencePointCount; seqIlOffsets = new int[seqCount]; var seqDocuments = new ISymbolDocument[seqCount]; seqPaths = new string[seqCount]; seqStartLines = new int[seqCount]; seqEndLines = new int[seqCount]; seqStartColumns = new int[seqCount]; seqEndColumns = new int[seqCount]; symMethod.GetSequencePoints(seqIlOffsets, seqDocuments, seqStartLines, seqStartColumns, seqEndLines, seqEndColumns); for (int i = 0; i < seqCount; i++) { seqPaths[i] = seqDocuments[i].URL; } } seqIterator = new SequencePointIterator(rawWriter, parent, seqIlOffsets, seqPaths, seqStartLines, seqStartColumns, seqEndLines, seqEndColumns); } ); // end worker call // We assume sequence points are sorted by IL offset. We assert that in the iterators below. // Now we need to go through and stitch the IL + Source together. // This also works even if we have no source (since that's just the degenerate case of 0 sequence points) // Print out header information Debug.Assert(token != 0); rawWriter.WriteLine(String.Format(CultureInfo.InvariantCulture, "> Function name:{0} (token={1:x})", fullName, token)); rawWriter.WriteLine(String.Format(CultureInfo.InvariantCulture, "> Native Code Address =0x{0:x}, flags={1}", nativeStartAddress, codeFlags)); // Walk through the IL in order and write out interleaved IL and Sequence Points. while (!seqIterator.IsDone) { // Add IL snippets that occur before this sequence point. WriteIlAndNative(ilDasm, il2nativeIterator, seqIterator.IlOffset); seqIterator.WriteSource(); seqIterator.Next(); } // Write the IL that's after the last sequence point WriteIlAndNative(ilDasm, il2nativeIterator, ilDasm.IlLength); // Set the text. InitLines(null, rawWriter.Lines, rawWriter.FormatList); EndInit(fullName); }
////////////////////////////////////////////////////////////////////////////////// // // Initialization & locals // ////////////////////////////////////////////////////////////////////////////////// private void EnsureIsUpToDate() { Debug.Assert(m_module != null); Debug.Assert(m_module.EditsCounter >= CorFunction.Version - 1); // version cannot be greater then # of edits; versions are 1 based if (m_isInitialized) return; // no need to do any refresh // perform refresh m_isInitialized = true; m_haveSymbols = m_module.SymReader != null; if (m_haveSymbols) { ISymbolMethod sm = null; sm = m_module.SymReader.GetMethod(new SymbolToken((int)m_function.Token), CorFunction.Version); if (sm == null) { m_haveSymbols = false; return; } m_symMethod = sm; m_SPcount = m_symMethod.SequencePointCount; m_SPoffsets = new int[m_SPcount]; m_SPdocuments = new ISymbolDocument[m_SPcount]; m_SPstartLines = new int[m_SPcount]; m_SPendLines = new int[m_SPcount]; m_SPstartColumns = new int[m_SPcount]; m_SPendColumns = new int[m_SPcount]; m_symMethod.GetSequencePoints(m_SPoffsets, m_SPdocuments, m_SPstartLines, m_SPstartColumns, m_SPendLines, m_SPendColumns); } }
/// <summary> /// Read the pdb file for this module and frame /// Retrieve infomation about the function /// </summary> /// <remarks> /// When an unmanaged app like reflector loads CLR, "Function.Module.Name" /// doesn't return a valid value and so this function returns null. /// </remarks> /// <returns>SourcePosition of the function</returns> private SourcePosition GetMetaDataInfo(CorMetadataImport importer) { SourcePosition functionPos = null; //position in this function where we are try { moduleFullName = thisFrame.Function.Module.Name; moduleShortName = System.IO.Path.GetFileName(moduleFullName); } catch (ArgumentException) { moduleFullName = ""; moduleShortName = ""; return(null); } //TODO: Implement a better method to determine the symbol path than just assuming it's in the same // directory string sympath = "."; //dealing with readinf the source in the module ISymbolReader metaReader = null; ISymbolBinder1 symbolBinder = new SymbolBinder(); try { if (moduleFullName.Length > 0) { metaReader = (symbolBinder as SymbolBinder). GetReaderForFile(importer.RawCOMObject, moduleFullName, sympath); } } catch (COMException) { //Debug.WriteLine(ed.ToString(CultureInfo.CurrentCulture.NumberFormat)); //will get here for any function which we cant read the .pdb file for //its not a big deal we just wont have source and line info } if (metaReader != null) { ISymbolMethod symMethod = null; try { symMethod = metaReader.GetMethod(new SymbolToken((int)thisFrame.Function.Token), thisFrame.Function.Version); int sequenceCount = symMethod.SequencePointCount; symDocs = new ISymbolDocument[sequenceCount]; offsets = new int[sequenceCount]; startLines = new int[sequenceCount]; startColumns = new int[sequenceCount]; endLines = new int[sequenceCount]; endColumns = new int[sequenceCount]; //Get the sequence points and store them in the apporpriate arrays. Seqeunce points //represent the different points in the files which correlate to il instruction and lines symMethod.GetSequencePoints(offsets, symDocs, startLines, startColumns, endLines, endColumns); functionPos = GetSourcePositionFromFrame(); } catch (COMException) { functionPos = null; } finally { symDocs = null; symMethod = null; } } CorType ctype = GetClassType(); if (ctype != null) { StringBuilder sb = new StringBuilder(); GetFunctionClassPath(sb, ctype); functionFullName = sb.ToString(); } else { functionFullName = ""; } MethodInfo methIn = importer.GetMethodInfo(thisFrame.Function.Token); functionFullName += "." + methIn.Name; functionShortName = methIn.Name; return(functionPos); }
//private string[] GetCombinedSource(IEnumerable<SequencePoint> points) { // var lines = new List<string>(); // foreach (var point in points) { // var contentLines = documentCache.Get(point.Document, () => File.ReadAllLines(point.Document.URL)); // var start = point.Start.Row - 1; // var end = point.End.Row - 1; // if (start >= contentLines.Length || end >= contentLines.Length) // continue; // for (var i = start; i <= end; i++) { // var line = contentLines[i]; // if (i == start) // line = line.Substring(point.Start.Column - 1); // else if (i == end) // line = line.Substring(0, point.End.Column - 1); // lines.Add(line); // } // } // return lines.ToArray(); //} private IEnumerable<SequencePoint> GetSequencePoints(ISymbolMethod method) { var count = method.SequencePointCount; var offsets = new int[count]; var docs = new ISymbolDocument[count]; var startColumns = new int[count]; var endColumns = new int[count]; var startRows = new int[count]; var endRows = new int[count]; method.GetSequencePoints(offsets, docs, startRows, startColumns, endRows, endColumns); for (int i = 0; i < count; i++) { if (startRows[i] == SequencePointHiddenLine || endRows[i] == SequencePointHiddenLine) continue; yield return new SequencePoint { Document = this.GetOrLoadContent(docs[i]), Start = new SourcePosition(startRows[i], startColumns[i]), End = new SourcePosition(endRows[i], endColumns[i]) }; } }
void ReadSequencePoints(ISymbolMethod method, Hashtable instructions) { int count = method.SequencePointCount; int [] offsets = new int [count]; ISymbolDocument [] docs = new ISymbolDocument [count]; int [] startColumn = new int [count]; int [] endColumn = new int [count]; int [] startRow = new int [count]; int [] endRow = new int [count]; method.GetSequencePoints (offsets, docs, startRow, startColumn, endRow, endColumn); for (int i = 0; i < offsets.Length; i++) { Cil.Instruction instr = (Cil.Instruction) instructions [offsets [i]]; Cil.SequencePoint sp = new Cil.SequencePoint (GetDocument (docs [i])); sp.StartLine = startRow [i]; sp.StartColumn = startColumn [i]; sp.EndLine = endRow [i]; sp.EndColumn = endColumn [i]; instr.SequencePoint = sp; } }
internal static StackFrame CreateFrame(CorDebuggerSession session, CorFrame frame) { uint address = 0; string file = ""; int line = 0; string method = ""; string lang = ""; string module = ""; if (frame.FrameType == CorFrameType.ILFrame) { if (frame.Function != null) { module = frame.Function.Module.Name; CorMetadataImport importer = new CorMetadataImport(frame.Function.Module); MethodInfo mi = importer.GetMethodInfo(frame.Function.Token); method = mi.DeclaringType.FullName + "." + mi.Name; ISymbolReader reader = session.GetReaderForModule(frame.Function.Module.Name); if (reader != null) { ISymbolMethod met = reader.GetMethod(new SymbolToken(frame.Function.Token)); if (met != null) { uint offset; CorDebugMappingResult mappingResult; frame.GetIP(out offset, out mappingResult); SequencePoint prevSp = null; foreach (SequencePoint sp in met.GetSequencePoints()) { if (sp.Offset > offset) { break; } prevSp = sp; } if (prevSp != null) { line = prevSp.Line; file = prevSp.Document.URL; } } } } lang = "Managed"; } else if (frame.FrameType == CorFrameType.NativeFrame) { frame.GetNativeIP(out address); method = "<Unknown>"; lang = "Native"; } else if (frame.FrameType == CorFrameType.InternalFrame) { switch (frame.InternalFrameType) { case CorDebugInternalFrameType.STUBFRAME_M2U: method = "[Managed to Native Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_U2M: method = "[Native to Managed Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_LIGHTWEIGHT_FUNCTION: method = "[Lightweight Method Call]"; break; case CorDebugInternalFrameType.STUBFRAME_APPDOMAIN_TRANSITION: method = "[Application Domain Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_FUNC_EVAL: method = "[Function Evaluation]"; break; } } if (method == null) { method = "<Unknown>"; } return(new StackFrame((long)address, module, method, file, line, lang)); }
internal static StackFrame CreateFrame(CorDebuggerSession session, CorFrame frame) { // TODO: Fix remaining. uint address = 0; //string typeFQN; //string typeFullName; string addressSpace = ""; string file = ""; int line = 0; int column = 0; string method = ""; string lang = ""; string module = ""; string type = ""; bool hasDebugInfo = false; bool hidden = false; bool external = true; if (frame.FrameType == CorFrameType.ILFrame) { if (frame.Function != null) { module = frame.Function.Module.Name; CorMetadataImport importer = new CorMetadataImport(frame.Function.Module); MethodInfo mi = importer.GetMethodInfo(frame.Function.Token); method = mi.DeclaringType.FullName + "." + mi.Name; type = mi.DeclaringType.FullName; addressSpace = mi.Name; ISymbolReader reader = session.GetReaderForModule(frame.Function.Module.Name); if (reader != null) { ISymbolMethod met = reader.GetMethod(new SymbolToken(frame.Function.Token)); if (met != null) { CorDebugMappingResult mappingResult; frame.GetIP(out address, out mappingResult); SequencePoint prevSp = null; foreach (SequencePoint sp in met.GetSequencePoints()) { if (sp.Offset > address) { break; } prevSp = sp; } if (prevSp != null) { line = prevSp.Line; column = prevSp.Offset; file = prevSp.Document.URL; address = (uint)prevSp.Offset; } } } // FIXME: Still steps into. //hidden = mi.GetCustomAttributes (true).Any (v => v is System.Diagnostics.DebuggerHiddenAttribute); } lang = "Managed"; hasDebugInfo = true; } else if (frame.FrameType == CorFrameType.NativeFrame) { frame.GetNativeIP(out address); method = "<Unknown>"; lang = "Native"; } else if (frame.FrameType == CorFrameType.InternalFrame) { switch (frame.InternalFrameType) { case CorDebugInternalFrameType.STUBFRAME_M2U: method = "[Managed to Native Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_U2M: method = "[Native to Managed Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_LIGHTWEIGHT_FUNCTION: method = "[Lightweight Method Call]"; break; case CorDebugInternalFrameType.STUBFRAME_APPDOMAIN_TRANSITION: method = "[Application Domain Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_FUNC_EVAL: method = "[Function Evaluation]"; break; } } if (method == null) { method = "<Unknown>"; } var loc = new SourceLocation(method, file, line, column); return(new StackFrame((long)address, addressSpace, loc, lang, external, hasDebugInfo, hidden, null, null)); }