예제 #1
0
 public FrameInfo(FrameInfoFlags flags, int startOffset, int endOffset, byte[] blobData)
 {
     Flags       = flags;
     StartOffset = startOffset;
     EndOffset   = endOffset;
     BlobData    = blobData;
 }
예제 #2
0
        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);
        }
예제 #3
0
 public FrameInfo(FrameInfoFlags flags, int startOffset, int endOffset, byte[] blobData)
 {
     Flags = flags;
     StartOffset = startOffset;
     EndOffset = endOffset;
     BlobData = blobData;
 }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
        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();
        }
예제 #8
0
        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();
            }
        }
예제 #9
0
        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);
        }
예제 #10
0
        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());
        }
예제 #11
0
        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();
            }
        }