public FrameInfo(FrameInfoFlags flags, int startOffset, int endOffset, byte[] blobData) { Flags = flags; StartOffset = startOffset; EndOffset = endOffset; BlobData = blobData; }
public List <FrameInfoPair> GetFramesWithInfo( FrameInfoFlags fields, uint startIndex, uint maxCount) { var framesWithInfo = new List <FrameInfoPair>(); /// This is a workaround to avoid calling <see cref="sbThread.GetNumFrames"/>. /// It is a very expensive call for cases when stack is significantly larger /// than <see cref="startIndex+maxCount"/>, because it traverses the whole stack. for (uint i = startIndex; i < startIndex + maxCount; ++i) { SbFrame ithFrame = sbThread.GetFrameAtIndex(i); if (ithFrame == null) { // We have reached the end of stack, no need to load next frames. break; } var frame = remoteFrameFactory.Create(ithFrame); framesWithInfo.Add( new FrameInfoPair { Frame = frame, Info = frame.GetInfo(fields) }); } return(framesWithInfo); }
public FrameInfo <SbModule>?GetInfo(FrameInfoFlags fields) { var request = new GetInfoRequest() { Frame = grpcSbFrame, Fields = (uint)fields }; GetInfoResponse response = null; if (connection.InvokeRpc(() => { response = client.GetInfo(request); })) { if (response.Info != null) { return(FrameInfoUtils.CreateFrameInfo(response.Info, moduleFactory, connection)); } } return(null); }
public async Task <List <FrameInfoPair> > GetFramesWithInfoAsync( FrameInfoFlags fields, uint startIndex, uint maxCount) { var request = new GetFramesWithInfoRequest() { Thread = grpcSbThread, Fields = (uint)fields, StartIndex = startIndex, MaxCount = maxCount }; GetFramesWithInfoResponse response = null; if (await connection.InvokeRpcAsync(async delegate { response = await client.GetFramesWithInfoAsync(request); })) { return(ToFrameInfoPairList(response)); } return(null); }
public List <FrameInfoPair> GetFramesWithInfo( FrameInfoFlags fields, uint startIndex, uint maxCount) { var request = new GetFramesWithInfoRequest() { Thread = grpcSbThread, Fields = (uint)fields, StartIndex = startIndex, MaxCount = maxCount }; GetFramesWithInfoResponse response = null; if (connection.InvokeRpc(() => { response = client.GetFramesWithInfo(request); })) { return(ToFrameInfoPairList(response)); } return(null); }
public void BuildCFIMap(NodeFactory factory, ObjectNode node) { _offsetToCfis.Clear(); _offsetToCfiStart.Clear(); _offsetToCfiEnd.Clear(); _offsetToCfiLsdaBlobName.Clear(); _frameOpened = false; INodeWithCodeInfo nodeWithCodeInfo = node as INodeWithCodeInfo; if (nodeWithCodeInfo == null) { return; } FrameInfo[] frameInfos = nodeWithCodeInfo.FrameInfos; if (frameInfos == null) { return; } byte[] gcInfo = nodeWithCodeInfo.GCInfo; ObjectData ehInfo = nodeWithCodeInfo.EHInfo; for (int i = 0; i < frameInfos.Length; i++) { FrameInfo frameInfo = frameInfos[i]; int start = frameInfo.StartOffset; int end = frameInfo.EndOffset; int len = frameInfo.BlobData.Length; byte[] blob = frameInfo.BlobData; ObjectNodeSection lsdaSection = LsdaSection; if (ShouldShareSymbol(node)) { lsdaSection = lsdaSection.GetSharedSection(((ISymbolNode)node).GetMangledName(_nodeFactory.NameMangler)); } SwitchSection(_nativeObjectWriter, lsdaSection.Name, GetCustomSectionAttributes(lsdaSection), lsdaSection.ComdatName); _sb.Clear().Append("_lsda").Append(i.ToStringInvariant()).Append(_currentNodeZeroTerminatedName); byte[] blobSymbolName = _sb.ToUtf8String().UnderlyingArray; EmitSymbolDef(blobSymbolName); FrameInfoFlags flags = frameInfo.Flags; if (ehInfo != null) { flags |= FrameInfoFlags.HasEHInfo; } EmitIntValue((byte)flags, 1); if (i != 0) { EmitSymbolRef(_sb.Clear().Append("_lsda0").Append(_currentNodeZeroTerminatedName), RelocType.IMAGE_REL_BASED_REL32, 4); // emit relative offset from the main function EmitIntValue((ulong)(start - frameInfos[0].StartOffset), 4); } if (ehInfo != null) { EmitSymbolRef(_sb.Clear().Append("_ehInfo").Append(_currentNodeZeroTerminatedName), RelocType.IMAGE_REL_BASED_REL32, 4); } if (gcInfo != null) { EmitBlob(gcInfo); gcInfo = null; } if (ehInfo != null) { // TODO: Place EHInfo into different section for better locality Debug.Assert(ehInfo.Alignment == 1); Debug.Assert(ehInfo.DefinedSymbols.Length == 0); EmitSymbolDef(_sb /* ehInfo */); EmitBlobWithRelocs(ehInfo.Data, ehInfo.Relocs); ehInfo = null; } // For Unix, we build CFI blob map for each offset. Debug.Assert(len % CfiCodeSize == 0); // Record start/end of frames which shouldn't be overlapped. _offsetToCfiStart.Add(start); _offsetToCfiEnd.Add(end); _offsetToCfiLsdaBlobName.Add(start, blobSymbolName); for (int j = 0; j < len; j += CfiCodeSize) { // The first byte of CFI_CODE is offset from the range the frame covers. // Compute code offset from the root method. int codeOffset = blob[j] + start; List <byte[]> cfis; if (!_offsetToCfis.TryGetValue(codeOffset, out cfis)) { cfis = new List <byte[]>(); _offsetToCfis.Add(codeOffset, cfis); } byte[] cfi = new byte[CfiCodeSize]; Array.Copy(blob, j, cfi, 0, CfiCodeSize); cfis.Add(cfi); } } EnsureCurrentSection(); }
public void PublishUnwindInfo(ObjectNode node) { INodeWithCodeInfo nodeWithCodeInfo = node as INodeWithCodeInfo; if (nodeWithCodeInfo == null) { return; } FrameInfo[] frameInfos = nodeWithCodeInfo.FrameInfos; if (frameInfos == null) { return; } byte[] gcInfo = nodeWithCodeInfo.GCInfo; ObjectData ehInfo = nodeWithCodeInfo.EHInfo; for (int i = 0; i < frameInfos.Length; i++) { FrameInfo frameInfo = frameInfos[i]; int start = frameInfo.StartOffset; int end = frameInfo.EndOffset; int len = frameInfo.BlobData.Length; byte[] blob = frameInfo.BlobData; _sb.Clear().Append(_nodeFactory.NameMangler.CompilationUnitPrefix).Append("_unwind").Append(i.ToStringInvariant()); ObjectNodeSection section = ObjectNodeSection.XDataSection; SwitchSection(_nativeObjectWriter, section.Name); byte[] blobSymbolName = _sb.Append(_currentNodeZeroTerminatedName).ToUtf8String().UnderlyingArray; EmitAlignment(4); EmitSymbolDef(blobSymbolName); FrameInfoFlags flags = frameInfo.Flags; if (ehInfo != null) { flags |= FrameInfoFlags.HasEHInfo; } EmitBlob(blob); EmitIntValue((byte)flags, 1); if (ehInfo != null) { EmitSymbolRef(_sb.Clear().Append(_nodeFactory.NameMangler.CompilationUnitPrefix).Append("_ehInfo").Append(_currentNodeZeroTerminatedName), RelocType.IMAGE_REL_BASED_ABSOLUTE); } if (gcInfo != null) { EmitBlob(gcInfo); gcInfo = null; } if (ehInfo != null) { // TODO: Place EHInfo into different section for better locality Debug.Assert(ehInfo.Alignment == 1); Debug.Assert(ehInfo.DefinedSymbols.Length == 0); EmitSymbolDef(_sb /* ehInfo */); EmitBlobWithRelocs(ehInfo.Data, ehInfo.Relocs); ehInfo = null; } // For window, just emit the frame blob (UNWIND_INFO) as a whole. EmitWinFrameInfo(start, end, len, blobSymbolName); EnsureCurrentSection(); } }
public FrameInfo <SbModule> GetInfo(FrameInfoFlags fields) { var info = new FrameInfo <SbModule>(); var module = _sbFrame.GetModule(); // We can safely ignore FIF_RETURNTYPE, FIF_ARGS, all FIF_ARGS_*, FIF_ANNOTATEDFRAME, // FIF_FILTER_NON_USER_CODE, and FIF_DESIGN_TIME_EXPR_EVAL. // For FuncName, we can ignore FIF_FUNCNAME_FORMAT, FIF_FUNCNAME_RETURNTYPE, // FIF_FUNCNAME_LANGUAGE, and FIF_FUNCNAME_OFFSET. if ((fields & FrameInfoFlags.FIF_FUNCNAME) != 0) { info.FuncName = ""; if ((fields & FrameInfoFlags.FIF_FUNCNAME_MODULE) != 0) { var platformFileSpec = module?.GetPlatformFileSpec(); if (platformFileSpec != null) { info.FuncName = platformFileSpec.GetFilename() + "!"; } } info.FuncName += GetFunctionName(); if ((fields & FrameInfoFlags.FIF_FUNCNAME_ARGS) != 0) { info.FuncName += "("; info.FuncName += GetArguments(fields); info.FuncName += ")"; } if ((fields & FrameInfoFlags.FIF_FUNCNAME_LINES) != 0) { var lineEntry = _sbFrame.GetLineEntry(); if (lineEntry != null) { uint line = lineEntry.GetLine(); if (line != 0) { info.FuncName += " Line " + line; } } } info.ValidFields |= FrameInfoFlags.FIF_FUNCNAME; } if ((FrameInfoFlags.FIF_LANGUAGE & fields) != 0) { var function = _sbFrame.GetFunction(); LanguageType languageType = LanguageType.UNKNOWN; if (function != null) { languageType = function.GetLanguage(); } info.Language = SbLanguageRuntime.GetNameFromLanguageType(languageType); if (!string.IsNullOrEmpty(info.Language)) { info.ValidFields |= FrameInfoFlags.FIF_LANGUAGE; } } if ((FrameInfoFlags.FIF_MODULE & fields) != 0) { string moduleName = _sbFrame.GetModule()?.GetPlatformFileSpec()?.GetFilename(); if (moduleName != null) { info.ValidFields |= FrameInfoFlags.FIF_MODULE; info.ModuleName = moduleName; } } if ((FrameInfoFlags.FIF_STACKRANGE & fields) != 0) { var stackRange = GetPhysicalStackRange(); if (stackRange != null) { info.AddrMin = stackRange.addressMin; info.AddrMax = stackRange.addressMax; info.ValidFields |= FrameInfoFlags.FIF_STACKRANGE; } } if ((FrameInfoFlags.FIF_FRAME & fields) != 0) { info.ValidFields |= FrameInfoFlags.FIF_FRAME; } if ((FrameInfoFlags.FIF_DEBUGINFO & fields) != 0) { info.HasDebugInfo = Convert.ToInt32(module != null && module.HasCompileUnits()); info.ValidFields |= FrameInfoFlags.FIF_DEBUGINFO; } if ((FrameInfoFlags.FIF_STALECODE & fields) != 0) { info.StaleCode = 0; info.ValidFields |= FrameInfoFlags.FIF_STALECODE; } if ((FrameInfoFlags.FIF_DEBUG_MODULEP & fields) != 0) { if (module != null) { info.Module = module; info.ValidFields |= FrameInfoFlags.FIF_DEBUG_MODULEP; } } return(info); }
string GetArguments(FrameInfoFlags fields) { SbFunction frameFunction = _sbFrame.GetFunction(); SbTypeList typeList = frameFunction?.GetType()?.GetFunctionArgumentTypes(); if (typeList == null || typeList.GetSize() == 0) { return(""); } List <SbValue> valueList = null; if ((fields & FrameInfoFlags.FIF_FUNCNAME_ARGS_VALUES) != 0) { valueList = _sbFrame.GetVariables(true, false, false, false); } // We should skip the "this" argument. Ideally we would query if // a function is a method, but there is no such query. Instead, // we literally skip the "this" argument. uint argBase = frameFunction.GetArgumentName(0) == "this" ? 1u : 0u; var result = new StringBuilder(); uint argumentCount = typeList.GetSize(); for (uint i = 0; i < argumentCount; i++) { if (i > 0) { result.Append(", "); } if ((fields & FrameInfoFlags.FIF_FUNCNAME_ARGS_TYPES) != 0) { result.Append(typeList.GetTypeAtIndex(i).GetName()); } if ((fields & FrameInfoFlags.FIF_FUNCNAME_ARGS_NAMES) != 0) { // If we are showing types and names, add a space between them. if ((fields & FrameInfoFlags.FIF_FUNCNAME_ARGS_TYPES) != 0) { result.Append(" "); } result.Append(frameFunction.GetArgumentName(argBase + i)); } if ((fields & FrameInfoFlags.FIF_FUNCNAME_ARGS_VALUES) != 0) { // In some cases the values are missing (e.g., with incomplete debug info // when doing Debug.ListCallStack in VS's Command Window on crash dump). // Let us handle that case gracefully. int index = (int)(argBase + i); if (index < valueList.Count) { // If we are showing types or names and values, show an equals sign // between them. if ((fields & FrameInfoFlags.FIF_FUNCNAME_ARGS_TYPES) != 0 || (fields & FrameInfoFlags.FIF_FUNCNAME_ARGS_NAMES) != 0) { result.Append(" = "); } result.Append(valueList[index].GetValue()); } } } return(result.ToString()); }
public void BuildCFIMap(NodeFactory factory, ObjectNode node) { _offsetToCfis.Clear(); _offsetToCfiStart.Clear(); _offsetToCfiEnd.Clear(); _offsetToCfiLsdaBlobName.Clear(); _frameOpened = false; INodeWithCodeInfo nodeWithCodeInfo = node as INodeWithCodeInfo; if (nodeWithCodeInfo == null) { return; } FrameInfo[] frameInfos = nodeWithCodeInfo.FrameInfos; if (frameInfos == null) { return; } byte[] gcInfo = nodeWithCodeInfo.GCInfo; ObjectNode.ObjectData ehInfo = nodeWithCodeInfo.EHInfo; string mainEhInfoSymbolName = null; for (int i = 0; i < frameInfos.Length; i++) { FrameInfo frameInfo = frameInfos[i]; int start = frameInfo.StartOffset; int end = frameInfo.EndOffset; int len = frameInfo.BlobData.Length; byte[] blob = frameInfo.BlobData; if (_targetPlatform.OperatingSystem == TargetOS.Windows) { string blobSymbolName = "_unwind" + i.ToStringInvariant() + _currentNodeName; ObjectNodeSection section = ObjectNodeSection.XDataSection; if (node.ShouldShareNodeAcrossModules(factory) && factory.Target.OperatingSystem == TargetOS.Windows) { section = section.GetSharedSection(blobSymbolName); CreateCustomSection(section); } SwitchSection(_nativeObjectWriter, section.Name); EmitAlignment(4); EmitSymbolDef(blobSymbolName); FrameInfoFlags flags = frameInfo.Flags; if (ehInfo != null) { flags |= FrameInfoFlags.HasEHInfo; } EmitBlob(blob); EmitIntValue((byte)flags, 1); if (ehInfo != null) { mainEhInfoSymbolName = "_ehInfo" + _currentNodeName; EmitSymbolRef(mainEhInfoSymbolName, RelocType.IMAGE_REL_BASED_ABSOLUTE); } if (gcInfo != null) { EmitBlob(gcInfo); gcInfo = null; } if (ehInfo != null) { // TODO: Place EHInfo into different section for better locality Debug.Assert(ehInfo.Alignment == 1); Debug.Assert(ehInfo.DefinedSymbols.Length == 0); EmitSymbolDef(mainEhInfoSymbolName); EmitBlobWithRelocs(ehInfo.Data, ehInfo.Relocs); ehInfo = null; } // TODO: Currently we get linker errors if we emit frame info for shared types. // This needs follow-up investigation. if (!node.ShouldShareNodeAcrossModules(factory)) { // For window, just emit the frame blob (UNWIND_INFO) as a whole. EmitWinFrameInfo(start, end, len, blobSymbolName); } } else { string blobSymbolName = "_lsda" + i.ToStringInvariant() + _currentNodeName; SwitchSection(_nativeObjectWriter, LsdaSection.Name); EmitSymbolDef(blobSymbolName); FrameInfoFlags flags = frameInfo.Flags; if (ehInfo != null) { flags |= FrameInfoFlags.HasEHInfo; } EmitIntValue((byte)flags, 1); if (i != 0) { EmitSymbolRef("_lsda0" + _currentNodeName, RelocType.IMAGE_REL_BASED_REL32, 4); // emit relative offset from the main function EmitIntValue((ulong)(start - frameInfos[0].StartOffset), 4); } if (ehInfo != null) { mainEhInfoSymbolName = "_ehInfo" + _currentNodeName; EmitSymbolRef(mainEhInfoSymbolName, RelocType.IMAGE_REL_BASED_REL32, 4); } if (gcInfo != null) { EmitBlob(gcInfo); gcInfo = null; } if (ehInfo != null) { // TODO: Place EHInfo into different section for better locality Debug.Assert(ehInfo.Alignment == 1); Debug.Assert(ehInfo.DefinedSymbols.Length == 0); EmitSymbolDef(mainEhInfoSymbolName); EmitBlobWithRelocs(ehInfo.Data, ehInfo.Relocs); ehInfo = null; } // For Unix, we build CFI blob map for each offset. Debug.Assert(len % CfiCodeSize == 0); // Record start/end of frames which shouldn't be overlapped. _offsetToCfiStart.Add(start); _offsetToCfiEnd.Add(end); _offsetToCfiLsdaBlobName.Add(start, blobSymbolName); for (int j = 0; j < len; j += CfiCodeSize) { // The first byte of CFI_CODE is offset from the range the frame covers. // Compute code offset from the root method. int codeOffset = blob[j] + start; List <byte[]> cfis; if (!_offsetToCfis.TryGetValue(codeOffset, out cfis)) { cfis = new List <byte[]>(); _offsetToCfis.Add(codeOffset, cfis); } byte[] cfi = new byte[CfiCodeSize]; Array.Copy(blob, j, cfi, 0, CfiCodeSize); cfis.Add(cfi); } } EnsureCurrentSection(); } }