public ThreadNode[] RefreshThreadList() { var foundThreads = new ThreadLookup(this, _AllThreadLists, true, StateThreadListCache).DiscoverAllThreads(); int generation = Interlocked.Increment(ref _ThreadListGeneration); foreach (var thr in foundThreads) { if (!_HeapQueried) { _HeapQueried = true; _ucHeap = Engine.Symbols.LookupVariable("ucHeap"); } if (!_CachedThreadNodes.TryGetValue(thr.Key, out var threadObject)) { string threadName = ReadThreadName(thr.Key, out var pTCB); _CachedThreadNodes[thr.Key] = threadObject = new ThreadNode(Engine, pTCB, threadName, _ucHeap); } threadObject.UpdateLastSeenState(thr.Value, generation); } foreach (var kv in _CachedThreadNodes.ToArray()) { kv.Value.MarkMissingIfNeeded(generation); if (kv.Value.IsMissingForLongerThan(1000)) { _CachedThreadNodes.Remove(kv.Key); //VisualGDB will dispose the node once it realizes it's no longer reported as a child. } } return(_CachedThreadNodes.Values.OrderBy(t => t.Name, StringComparer.InvariantCultureIgnoreCase).ToArray()); }
public QueueNode(ILiveWatchEngine engine, NodeSource root, QueueTypeDescriptor queue, IPinnedVariable variable, IPinnedVariableType queueType, string userFriendlyName) : base("$rtos.queue." + variable.UserFriendlyName) { _Engine = engine; _Descriptor = queue; _QueueType = queueType; _Root = root; if (_Descriptor.IsIndirect) { _PointerVariable = engine.CreateLiveVariable(variable); } else if (_Descriptor.TypeOverride != null) { _QueueVariable = engine.Symbols.CreateTypedVariable(variable.Address, engine.Symbols.LookupType(_Descriptor.TypeOverride, true)); } else { _QueueVariable = variable; } Name = userFriendlyName; RawType = _Descriptor.Type.ToString(); Capabilities = LiveWatchCapabilities.CanHaveChildren | LiveWatchCapabilities.CanPlotValue | LiveWatchCapabilities.CanSetBreakpoint; SelectedFormatter = engine.GetDefaultFormatter(ScalarVariableType.SInt32); Location = new LiveWatchPhysicalLocation(null, variable.SourceLocation.File, variable.SourceLocation.Line); }
public static void Locate(List <ThreadList> result, ILiveWatchEngine engine, IPinnedVariable baseVariable, ThreadListType type, uint listItemOffsetInTCB, bool queryCountVariable = false) { var list = Locate(engine, baseVariable, type, listItemOffsetInTCB, queryCountVariable); if (list != null) { result.Add(list); } }
public ThreadNode(ILiveWatchEngine engine, IPinnedVariable pTCB, string threadName, IPinnedVariable ucHeap) : base("$rtos.thread." + threadName) { _Engine = engine; _TCB = pTCB; _ucHeap = ucHeap; Name = threadName; _Variables.pxTopOfStack = pTCB.LookupSpecificChild(nameof(_Variables.pxTopOfStack)); _Variables.pxTopOfStackLive = engine.CreateLiveVariable(_Variables.pxTopOfStack, LiveVariableFlags.CreateSuspended); _Variables.uxBasePriority = pTCB.LookupSpecificChild(nameof(_Variables.uxBasePriority)); _Variables.uxMutexesHeld = pTCB.LookupSpecificChild(nameof(_Variables.uxMutexesHeld)); _Variables.pxStack = pTCB.LookupSpecificChild(nameof(_Variables.pxStack)); Capabilities = LiveWatchCapabilities.CanHaveChildren; }
public static ThreadList Locate(ILiveWatchEngine engine, IPinnedVariable baseVariable, ThreadListType type, uint listItemOffsetInTCB, bool queryCountVariable = false) { if (baseVariable == null) { return(null); } var xListEnd = baseVariable?.LookupSpecificChild("xListEnd"); if (xListEnd == null) { return(null); } var xListEnd_pNext = xListEnd.LookupSpecificChild("pxNext"); if (xListEnd_pNext == null) { return(null); } ILiveVariable xListEnd_pNextLive = engine.CreateLiveVariable(xListEnd_pNext); if (xListEnd_pNextLive == null) { return(null); } ILiveVariable uxNumberOfItemsLive = null; if (queryCountVariable) { var uxNumberOfItems = baseVariable.LookupSpecificChild("uxNumberOfItems"); if (uxNumberOfItems != null) { uxNumberOfItemsLive = engine.CreateLiveVariable(uxNumberOfItems); } } return(new ThreadList(type, xListEnd.Address, xListEnd_pNextLive, baseVariable.UserFriendlyName, uxNumberOfItemsLive, listItemOffsetInTCB)); }
string ReadThreadName(ulong TCBAddress, out IPinnedVariable pTCB) { pTCB = Engine.Symbols.CreateTypedVariable(TCBAddress, _TCBType); var pcTaskName = pTCB.LookupSpecificChild("pcTaskName"); string threadName = null; if (pcTaskName != null) { try { var rawName = Engine.ReadMemory(pcTaskName); threadName = rawName.ToNullTerminatedString(); } catch { } } return(threadName ?? $"0x{TCBAddress:x8}"); }
public QueueNode[] GetAllQueues() { List <QueueNode> discoveredQueues = new List <QueueNode>(); foreach (var globalVar in Engine.Symbols.TopLevelVariables) { var qt = QueueListNode.ParseQueueType(globalVar.RawType.ToString()); if (!qt.IsValid) { continue; } IPinnedVariable replacementVariable = null; if (qt.ContentsMemberName != null) { var child = globalVar.LookupSpecificChild(qt.ContentsMemberName); if (child == null) { continue; } replacementVariable = Engine.Symbols.CreateTypedVariable(child.Address, _QueueType); } string name = globalVar.UserFriendlyName; if (name != null && qt.DiscardedNamePrefix != null && name.StartsWith(qt.DiscardedNamePrefix)) { name = name.Substring(qt.DiscardedNamePrefix.Length); } discoveredQueues.Add(new QueueNode(Engine, this, qt, replacementVariable ?? globalVar, _QueueType, name)); } return(discoveredQueues.ToArray()); }
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); }