Пример #1
0
        public void Walk(ILiveWatchEngine engine,
                         Dictionary <ulong, ThreadListType> result,
                         HashSet <ulong> processedNodes,
                         int maxThreadsToLoad,
                         LinkedListNodeCache nodeCache,
                         LiveVariableQueryMode queryMode)
        {
            int   threadsFound = 0;
            ulong pxNext       = 0;

            for (var pListNode = xListEnd_pxNext.GetValue(queryMode).ToUlong(); pListNode != 0 && !processedNodes.Contains(pListNode); pListNode = pxNext, threadsFound++)
            {
                if (threadsFound >= maxThreadsToLoad)
                {
                    break;
                }

                processedNodes.Add(pListNode);

                try
                {
                    var pTCB = pListNode - _ListItemOffsetInTCB;

                    var cachedListNode = nodeCache.ProvideNode(pListNode);

                    cachedListNode.ReadValues(queryMode, out ulong pvOwner, out pxNext);

                    if (pvOwner != pTCB)
                    {
                        if ((uint)pvOwner == uint.MaxValue)
                        {
                            //This is the end-of-list node. Continue checking past it.
                            continue;
                        }
                        else
                        {
                            //The list node doesn't point to the object itself anymore. Most likely, it has been freed and reused.
                            cachedListNode.RemoveFromCache();
                            break;
                        }
                    }

                    result[pTCB] = Type;
                }
                catch (Exception ex)
                {
                    engine.LogException(ex, $"failed to process TCB node at {pListNode}");
                    break;
                }
            }
        }
Пример #2
0
            public void ReadValues(LiveVariableQueryMode queryMode, out ulong pvOwner, out ulong pxNext)
            {
                var value = _Variable.GetValue(queryMode);

                if (!value.IsValid)
                {
                    pvOwner = pxNext = 0;
                }
                else
                {
                    pvOwner = BitConverter.ToUInt32(value.Value, _Cache.pvOwner_RelativeOffset);
                    pxNext  = BitConverter.ToUInt32(value.Value, _Cache.pxNext_RelativeOffset);
                }
            }
Пример #3
0
            public override LiveWatchNodeState UpdateState(LiveWatchUpdateContext context)
            {
                var freeBytesValue = _Variable.GetValue();
                var freeBytes      = (int)freeBytesValue.ToUlong();

                int usedBytes = _HeapSize - freeBytes;

                RawValue = new LiveVariableValue(freeBytesValue.Timestamp, freeBytesValue.Generation, BitConverter.GetBytes(usedBytes));

                return(new LiveWatchNodeState
                {
                    Value = $"{usedBytes}/{_HeapSize} bytes"
                });
            }
Пример #4
0
        public override LiveWatchNodeState UpdateState(LiveWatchUpdateContext context)
        {
            var result = new LiveWatchNodeState {
                Icon = LiveWatchNodeIcon.Graph
            };

            if (_xSchedulerRunning != null)
            {
                if (_xSchedulerRunning.GetValue().ToUlong() != 0)
                {
                    result.Value = "active";
                }
                else
                {
                    result.Value = "inactive";
                }
            }

            return(result);
        }
        public override LiveWatchNodeState UpdateState(LiveWatchUpdateContext context)
        {
            int estimatedStackSize = (int)(_StackEnd - _StackStart);

            if (_OverflowDetected)
            {
                return(ReportStackOverflow(estimatedStackSize));
            }

            if (_Error != null)
            {
                return new LiveWatchNodeState {
                           Icon = LiveWatchNodeIcon.Error, Value = _Error
                }
            }
            ;

            var rawValue = _BorderVariable?.GetValue() ?? default;

            if (!rawValue.IsValid || CountUnusedStackMarkers(rawValue.Value) != rawValue.Value.Length)
            {
                ulong lastKnownEndOfStack;

                if (_BorderVariable != null)
                {
                    lastKnownEndOfStack = _BorderVariable.Address + (uint)_BorderVariable.Size;
                }
                else
                {
                    lastKnownEndOfStack = _StackEnd;
                }

                _BorderVariable?.Dispose();
                _BorderVariable = null;

                ulong startOfCheckedArea;
                if (!_StackOpposesGrowingHeap)
                {
                    //Maximum size is fixed. No guessing needed.
                    startOfCheckedArea = _StackStart;
                }
                else if (_HeapEndVariable != null)
                {
                    //Stack immediately follows the dynamically growing heap
                    startOfCheckedArea = _HeapEndVariable.GetValue().ToUlong();
                    if (startOfCheckedArea == 0)
                    {
                        startOfCheckedArea = _StackStart;   //The heap has never been used yet
                    }
                    estimatedStackSize = (int)(_StackEnd - _StackStart);
                }
                else
                {
                    //No heap. Stack directly follows the 'end' symbol.
                    startOfCheckedArea = _StackStart;
                }

                int position = MeasureUnusedStackArea(startOfCheckedArea, lastKnownEndOfStack);
                if (position == 0)
                {
                    _OverflowDetected = true;
                }
                else
                {
                    _PatternEverFound = true;
                }

                if (_OverflowDetected)
                {
                    return(ReportStackOverflow(estimatedStackSize));
                }
                else
                {
                    int watchSize = Math.Min(_MaxBorderVariableSize, position);
                    _BorderVariable = _Engine.Memory.CreateLiveVariable(startOfCheckedArea + (uint)position - (uint)watchSize, watchSize);
                }
            }

            ulong firstUsedStackSlot = _BorderVariable.Address + (uint)_BorderVariable.Size;

            Location = new LiveWatchPhysicalLocation(firstUsedStackSlot, null, 0);
            int stackUsage = (int)(_StackEnd - firstUsedStackSlot);

            RawValue = new LiveVariableValue(rawValue.Timestamp, rawValue.Generation, BitConverter.GetBytes(stackUsage));

            if (_HeapEndVariable != null)
            {
                var   rawHeapEnd = _HeapEndVariable.GetValue();
                ulong heapEnd    = rawHeapEnd.ToUlong();
                if (heapEnd == 0)
                {
                    heapEnd = _StackStart;
                }

                estimatedStackSize = (int)(_StackEnd - heapEnd);

                _DistanceToHeapEnd = new LiveVariableValue(rawHeapEnd.Timestamp, rawHeapEnd.Generation, BitConverter.GetBytes((int)(firstUsedStackSlot - heapEnd)));
            }

            string text;

            if (estimatedStackSize > 0)
            {
                text = $"{stackUsage}/{estimatedStackSize} bytes";
            }
            else
            {
                text = $"{stackUsage} bytes";
            }

            if (context.PreloadChildren && _Children == null && _HeapEndVariable != null)
            {
                _Children = new ILiveWatchNode[] { new DistanceToHeapNode(this) };
            }

            return(new LiveWatchNodeState
            {
                Value = text,
                Icon = LiveWatchNodeIcon.Stack,
                NewChildren = _Children,
            });
        }
Пример #6
0
        public override LiveWatchNodeState UpdateState(LiveWatchUpdateContext context)
        {
            if (_PointerVariable != null)
            {
                var address = _PointerVariable.GetValue().ToUlong() & ~1UL;
                if (address != _QueueVariable?.Address)
                {
                    _QueueVariable = _Engine.Symbols.CreateTypedVariable(address, _QueueType);
                }
            }

            if (_QueueVariable != null && _QueueVariable.Address != _Variables.LastKnownAddress)
            {
                _Variables.LastKnownAddress = _QueueVariable.Address;

                //The previous instance will get auto-disposed by VisualGDB.
                _QueueObjectNode = null;
                _Variables.Reset();

                if (_QueueVariable.Address != 0)
                {
                    _Variables.uxMessagesWaiting = _Engine.CreateLiveVariable(_QueueVariable.LookupSpecificChild(nameof(_Variables.uxMessagesWaiting)));
                    _Variables.uxLength          = _Engine.CreateLiveVariable(_QueueVariable.LookupSpecificChild(nameof(_Variables.uxLength)));

                    _Variables.u_xSemaphore_xMutexHolder         = _Engine.CreateLiveVariable(_QueueVariable.LookupChildRecursively("u.xSemaphore.xMutexHolder"));
                    _Variables.u_xSemaphore_uxRecursiveCallCount = _Engine.CreateLiveVariable(_QueueVariable.LookupChildRecursively("u.xSemaphore.uxRecursiveCallCount"));
                }
            }

            if (context.PreloadChildren && _QueueVariable != null && _QueueObjectNode == null && _QueueVariable.Address != 0)
            {
                _QueueObjectNode = _Engine.CreateNodeForPinnedVariable(_QueueVariable, new LiveWatchNodeOverrides {
                    Name = "[Object]"
                });
            }

            var result = new LiveWatchNodeState();

            if ((_QueueVariable?.Address ?? 0) == 0)
            {
                result.Value = "[NULL]";
            }
            else if (_Variables.uxLength == null || _Variables.uxMessagesWaiting == null)
            {
                result.Value = "???";
            }
            else
            {
                if (_Descriptor.TypeOverride != null && !_StaticType.HasValue)
                {
                    var typeVar = _QueueVariable.LookupSpecificChild("ucQueueType");
                    if (typeVar != null)
                    {
                        _StaticType = (QueueType)_Engine.ReadMemory(typeVar).ToUlong();
                        RawType     = _StaticType.Value.ToString();
                    }
                }

                var detectedType = _StaticType ?? _Descriptor.Type;

                var   rawValue = _Variables.uxMessagesWaiting.GetValue();
                int   value = (int)rawValue.ToUlong();
                int   maxValue = (int)_Variables.uxLength.GetValue().ToUlong();
                ulong owner = 0, level = 0;

                if (detectedType != QueueType.BaseQueue && _Variables.u_xSemaphore_xMutexHolder != null && _Variables.u_xSemaphore_uxRecursiveCallCount != null)
                {
                    owner = _Variables.u_xSemaphore_xMutexHolder.GetValue().ToUlong();
                    level = _Variables.u_xSemaphore_uxRecursiveCallCount.GetValue().ToUlong();

                    if (owner == _QueueVariable.Address)
                    {
                        detectedType = QueueType.Semaphore;
                    }
                    else
                    {
                        detectedType = QueueType.RecursiveMutex;
                    }
                }

                if (detectedType == QueueType.RecursiveMutex || detectedType == QueueType.NonRecursiveMutex)
                {
                    if (value != 0)
                    {
                        result.Value = "free";
                        RawValue     = new LiveVariableValue(rawValue.Timestamp, rawValue.Generation, BitConverter.GetBytes(0));
                    }
                    else if (_Variables.u_xSemaphore_xMutexHolder != null && _Variables.u_xSemaphore_uxRecursiveCallCount != null)
                    {
                        string threadName = _Root.GetThreadName(owner);
                        result.Value = $"taken by {threadName}";
                        if (level >= 1)
                        {
                            result.Value += $" (recursion = {level})";
                        }

                        RawValue = new LiveVariableValue(rawValue.Timestamp, rawValue.Generation, BitConverter.GetBytes((int)level + 1));
                    }
                    else
                    {
                        result.Value = "taken";
                    }
                }
                else
                {
                    RawValue     = rawValue;
                    result.Value = $"{value}/{maxValue}";
                }

                result.NewType = detectedType.ToString();

                switch (detectedType)
                {
                case QueueType.BinarySemaphore:
                case QueueType.Semaphore:
                case QueueType.RecursiveMutex:
                case QueueType.NonRecursiveMutex:
                    result.Icon = LiveWatchNodeIcon.Flag;
                    break;

                case QueueType.BaseQueue:
                    result.Icon = LiveWatchNodeIcon.Queue;
                    break;
                }


                if (context.PreloadChildren)
                {
                    ProvideWaitingThreadsNodes(detectedType);
                    result.NewChildren = new[] { _ReadThreadQueue, _WriteThreadQueue, _QueueObjectNode }.Where(n => n != null).ToArray();
                }
            }

            return(result);
        }
Пример #7
0
 public string GetCurrentTaskName(ILiveVariable pxCurrentTCB)
 {
     //We use a separate live variable, so that we can suspend it independently. VisualGDB will automatically sort out the redundancies if both variables are enabled.
     return(GetThreadName(pxCurrentTCB.GetValue().ToUlong()));
 }
Пример #8
0
            public override LiveWatchNodeState UpdateState(LiveWatchUpdateContext context)
            {
                int estimatedStackSize = ProvideEstimatedStackSize(out var pxStack);

                if (_OverflowDetected)
                {
                    return(ReportStackOverflow(estimatedStackSize));
                }

                var rawValue = _BorderVariable?.GetValue() ?? default;

                if (!rawValue.IsValid || CountUnusedStackArea(rawValue.Value) != rawValue.Value.Length)
                {
                    int queriedStackSize;
                    if (_BorderVariable != null)
                    {
                        queriedStackSize = (int)(_BorderVariable.Address - pxStack);
                    }
                    else
                    {
                        queriedStackSize = (int)(_ThreadNode._Engine.ReadMemory(_ThreadNode._Variables.pxTopOfStack).ToUlong() - pxStack);
                    }

                    _BorderVariable?.Dispose();
                    _BorderVariable = null;

                    if (queriedStackSize < 0)
                    {
                        return new LiveWatchNodeState {
                                   Icon = LiveWatchNodeIcon.Error, Value = $"Unexpected stack size ({queriedStackSize})"
                        }
                    }
                    ;

                    var data = _ThreadNode._Engine.Memory.ReadMemory(pxStack, queriedStackSize);
                    if (!data.IsValid)
                    {
                        return new LiveWatchNodeState {
                                   Icon = LiveWatchNodeIcon.Error, Value = $"Failed to read stack contents (0x{pxStack:x8} - 0x{pxStack + (uint)queriedStackSize:x8})"
                        }
                    }
                    ;

                    int offset = CountUnusedStackArea(data.Value);

                    //We don't know whether it is a stack overflow, or if the empty stack is never filled with the pattern.
                    //We assume that if the stack appears overflown from the very beginning, the pattern is not being used at all.
                    _OverflowDetected = offset == 0;
                    if (offset != 0)
                    {
                        _PatternEverFound = true;
                    }

                    if (offset == 0)
                    {
                        return(ReportStackOverflow(estimatedStackSize));
                    }
                    else
                    {
                        int watchSize = Math.Min(_MaxBorderVariableSize, offset);

                        _BorderVariable = _ThreadNode._Engine.Memory.CreateLiveVariable(pxStack + (uint)(offset - watchSize), watchSize, "Stack Border");
                    }
                }

                int freeStack  = (int)(_BorderVariable.Address - pxStack) + _BorderVariable.Size; /* The border variable watches the 1st free slot, not the 1st used one */
                int stackUsage = estimatedStackSize - freeStack;

                RawValue = new LiveVariableValue(rawValue.Timestamp, rawValue.Generation, BitConverter.GetBytes(stackUsage));

                string text;

                if (estimatedStackSize > 0)
                {
                    text = $"{stackUsage}/{estimatedStackSize} bytes";
                }
                else
                {
                    text = $"{stackUsage} bytes";
                }

                return(new LiveWatchNodeState
                {
                    Value = text
                });
            }