public void PrintManagedCallStacks() { //Threads test, get info of all managed threads found in dump context.WriteInfo("--- Managed callstacks ---"); if (context.Runtime != null) { foreach (ClrThread thread in context.Runtime.Threads) { if (!thread.IsAlive) { continue; } context.WriteInfo("Thread {0}, managed id: {1}:", thread.OSThreadId, thread.ManagedThreadId); context.WriteInfo("GC mode: {0} ", thread.GcMode); context.WriteInfo("Thread type: {0}", thread); context.WriteInfo("Callstack: {0:X} - {1:X}", thread.StackBase, thread.StackLimit); // get last thrown exception of thread ClrException lastException = thread.CurrentException; if (lastException != null) { this.PrintException(lastException); } // walk each stack frame foreach (ClrStackFrame frame in thread.StackTrace) { SDFileAndLineNumber info = frame.GetSourceLocation(); context.WriteLine("{0,12:X} {1,12:X} {2} - {3}:{4}", frame.StackPointer, frame.InstructionPointer, frame.DisplayString, info.File, info.Line); } context.WriteLine(null); } context.WriteInfo("Total amount of all (managed) threads: " + context.Runtime.Threads.Count); } }
private async Task <Tuple <SDFileAndLineNumber, string> > Address2MethodSourceAsync(ulong instrPtr, SDCDModule module) { ulong relativeIp = instrPtr; var systemContext = (SDCDSystemContext)analysisResult.SystemContext; // Calculate the relative IP to the base module. // For this we must subtract the start address of the whole module from the IP // The module start address from the parameter is only the start address of the segment. // We get the real module start address by subtracting the page offset multiplied by the page size from the segment start. ulong moduleStartAddress = module.StartAddress - (module.Offset * (uint)systemContext.PageSize); relativeIp -= moduleStartAddress + 1; string output = await processHandler.ExecuteProcessAndGetOutputAsync("addr2line", $"-f -C -e {module.LocalPath} 0x{relativeIp.ToString("X")}"); string[] lines = output.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); if (lines.Length < 2) { Console.WriteLine($"Output of addr2line is invalid ({lines.Length} lines)! First line: {lines?[0]}"); return(Tuple.Create <SDFileAndLineNumber, string>(new SDFileAndLineNumber(), null)); } string methodName = lines[0]; string fileLine = lines[1]; SDFileAndLineNumber sourceInfo = RetrieveSourceInfo(fileLine); return(Tuple.Create(sourceInfo, methodName)); }
private async Task <Tuple <SDFileAndLineNumber, string> > Address2MethodSourceAsync(ulong instrPtr, SDCDModule module) { ulong relativeIp = instrPtr; string mainExecutable = ((SDCDSystemContext)analysisResult.SystemContext).FileName; mainExecutable = Path.GetFileName(mainExecutable); if (mainExecutable != module.FileName) { // Subtract modules start address unless it's the main executable relativeIp -= module.StartAddress + 1; } string output = await processHandler.ExecuteProcessAndGetOutputAsync("addr2line", $"-f -C -e {module.LocalPath} 0x{relativeIp.ToString("X")}"); string[] lines = output.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); if (lines.Length < 2) { Console.WriteLine($"Output of addr2line is invalid ({lines.Length} lines)! First line: {lines?[0]}"); return(Tuple.Create <SDFileAndLineNumber, string>(new SDFileAndLineNumber(), null)); } string methodName = lines[0]; string fileLine = lines[1]; SDFileAndLineNumber sourceInfo = RetrieveSourceInfo(fileLine); return(Tuple.Create(sourceInfo, methodName)); }
// source location support, not implemented yet! //public string SourceFileName { get; set; } //public uint SourceLineNumber { get; set; } //public uint SourceLineNumberEnd { get; set; } //public uint SourceColumnNumber { get; set; } //public uint SourceColumnNumberEnd { get; set; } /// <summary> /// Constructor for native frame /// </summary> /// <param name="frame"></param> /// <param name="debugSymbols"></param> public CombinedStackFrame(DEBUG_STACK_FRAME frame, IDebugSymbols3 debugSymbols) { Type = StackFrameType.Native; //native frame InstructionPointer = frame.InstructionOffset; StackPointer = frame.StackOffset; ReturnOffset = frame.ReturnOffset; uint moduleIndex; ulong dummy; //if no module is associated with this frame, the method is unknown, can happen with CLR-JIT code if (debugSymbols.GetModuleByOffset(InstructionPointer, 0, out moduleIndex, out dummy) != 0) { ModuleName = "UNKNOWN"; MethodName = "UNKNOWN"; return; //no more action needed } var name = new StringBuilder(1024); //create buffer for storing method name ulong displacement; uint nameSize; Utility.CheckHRESULT(debugSymbols.GetNameByOffset(InstructionPointer, name, name.Capacity, out nameSize, out displacement)); OffsetInMethod = displacement; //offset of InstructionPointer and base location of symbol, could be null //get module name and method name, example for name : string[] parts = name.ToString().Split('!'); ModuleName = parts[0]; //module is the first part before '!' if (parts.Length > 1) { MethodName = parts[1]; //second part, after the '!' } if (string.IsNullOrEmpty(ModuleName)) { ModuleName = "UNKNOWN"; } // check if method name was found or not if (string.IsNullOrEmpty(MethodName)) { MethodName = "UNKNOWN"; } // get source information uint line; var fileBuffer = new StringBuilder(4 * 1024); uint fileSize; debugSymbols.GetLineByOffset(InstructionPointer, out line, fileBuffer, fileBuffer.Capacity, out fileSize, out displacement); if (fileSize > 0) { this.SourceInfo = new SDFileAndLineNumber { File = fileBuffer.ToString(), Line = (int)line }; } }
public SDCombinedStackFrame(StackFrameType type, string moduleName, string methodName, ulong offsetInMethod, ulong ip, ulong sp, ulong returnOffset, ulong spOffset, SDFileAndLineNumber sourceInfo) { this.Type = type; this.ModuleName = moduleName; this.MethodName = methodName; this.OffsetInMethod = offsetInMethod; this.InstructionPointer = ip; this.StackPointer = sp; this.ReturnOffset = returnOffset; this.LinkedStackFrame = null; this.StackPointerOffset = spOffset; this.SourceInfo = sourceInfo; }
private SDFileAndLineNumber RetrieveSourceInfo(string output) { Match match = addr2lineRegex.Match(output); if (match.Success) { SDFileAndLineNumber sourceInfo = new SDFileAndLineNumber() { File = match.Groups[1].Value, Line = int.Parse(match.Groups[2].Value) }; return(sourceInfo); } return(new SDFileAndLineNumber()); }
private async Task AddSourceInfoAsync(SDCombinedStackFrame stackFrame, SDCDModule module) { Tuple <SDFileAndLineNumber, string> methodSource = await Address2MethodSourceAsync(stackFrame.InstructionPointer, module); SDFileAndLineNumber sourceInfo = methodSource.Item1; string methodName = methodSource.Item2; if (methodName != "??") { stackFrame.MethodName = methodName; if (sourceInfo.File != null && sourceInfo.File != "??") { stackFrame.SourceInfo = sourceInfo; } } }
private static SDFileAndLineNumber FindNearestLine(PdbFunction function, int ilOffset) { int distance = int.MaxValue; var nearest = new SDFileAndLineNumber(); foreach (PdbSequencePointCollection sequenceCollection in function.SequencePoints) { foreach (PdbSequencePoint point in sequenceCollection.Lines) { int dist = (int)Math.Abs(point.Offset - ilOffset); if (dist < distance) { nearest.File = sequenceCollection.File.Name; nearest.Line = (int)point.LineBegin; } } } return(nearest); }
private async Task <Tuple <SDFileAndLineNumber, string> > Address2MethodSourceAsync(ulong instrPtr, SDCDModule module) { ulong relativeIp = instrPtr; if (module.DebugSymbolPath != null && module.DebugSymbolPath != "") { // If there is a debug file, link it (required for addr2line to find the dbg file) LinkDebugFile(module.LocalPath, module.DebugSymbolPath); } string output = await processHandler.ExecuteProcessAndGetOutputAsync("addr2line", $"-f -C -e {module.LocalPath} 0x{relativeIp.ToString("X")}"); string[] lines = output.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); if (lines.Length < 2) { Console.WriteLine($"Output of addr2line is invalid ({lines.Length} lines)! First line: {lines?[0]}"); return(Tuple.Create <SDFileAndLineNumber, string>(new SDFileAndLineNumber(), null)); } string methodName = lines[0]; string fileLine = lines[1]; SDFileAndLineNumber sourceInfo = RetrieveSourceInfo(fileLine); return(Tuple.Create(sourceInfo, methodName)); }
public CombinedStackFrame(ClrStackFrame frame) { if (frame.Kind == ClrStackFrameType.ManagedMethod) { Type = StackFrameType.Managed; } if (frame.Kind == ClrStackFrameType.Runtime) { Type = StackFrameType.Special; } InstructionPointer = frame.InstructionPointer; StackPointer = frame.StackPointer; if (frame.Method == null) { MethodName = frame.DisplayString; //for example GCFrame return; } MethodName = frame.Method.GetFullSignature(); if (frame.Method.Type != null) { ModuleName = Path.GetFileNameWithoutExtension(frame.Method.Type.Module.Name); if (string.IsNullOrEmpty(ModuleName)) { ModuleName = "UNKNOWN"; } } // calculate IL offset with instruction pointer of frame and instruction pointer // in the target dump file of the start of the method's assembly OffsetInMethod = InstructionPointer - frame.Method.NativeCode; this.SourceInfo = frame.GetSourceLocation(); }