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); }
private void ReadLivePoint(tblElement element, LivePoint_DTO livepoint) { if (element.tblConnector.Gateway_Type == DataGatewayType.Obix.ToString()) { try { if (_connection_id != element.tblConnector.ID) { _connection_id = element.tblConnector.ID; _liveVariable = new Obix( StringEncryDecry.Decrypt(element.tblConnector.Server_Name, element.tblConnector.SessionID), StringEncryDecry.Decrypt(element.tblConnector.User_Name, element.tblConnector.SessionID), StringEncryDecry.Decrypt(element.tblConnector.Password, element.tblConnector.SessionID)); } LivePoint_ResponseDTO response_dto = new LivePoint_ResponseDTO(); if (_liveVariable.Is_Connected) { response_dto = _liveVariable.ReadLiveVariable(element.Source_Element_Name_Live); livepoint.Current_Value = response_dto; } else { livepoint.Error_Info = Error_Internal.SetError("Connection Error"); } } catch (Exception ex) { } } else { throw new Exception("Invalid GatewayType"); } }
public NodeSource(ILiveWatchEngine engine) { Engine = engine; _TCBType = (IPinnedVariableStructType)engine.Symbols.LookupType("TCB_t", true); _QueueType = (IPinnedVariableStructType)engine.Symbols.LookupType("Queue_t"); var xStateListItem_Offset = _TCBType.LookupMember("xStateListItem", true).Offset; xEventListItem_Offset = _TCBType.LookupMember("xEventListItem", true).Offset; var listItemType = (IPinnedVariableStructType)engine.Symbols.LookupType("ListItem_t", true); var pvOwner_Offset = (int)listItemType.LookupMember("pvOwner", true).Offset; var pxNext_Offset = (int)listItemType.LookupMember("pxNext", true).Offset; StateThreadListCache = new LinkedListNodeCache(engine, pvOwner_Offset, pxNext_Offset); EventThreadListCache = new LinkedListNodeCache(engine, pvOwner_Offset, pxNext_Offset); _pxCurrentTCB = engine.CreateLiveVariable("pxCurrentTCB", true); _uxCurrentNumberOfTasks = engine.CreateLiveVariable("uxCurrentNumberOfTasks", true); foreach (var pxReadyTaskList in engine.Symbols.LookupVariable("pxReadyTasksLists")?.LookupChildren(0) ?? new IPinnedVariable[0]) { ThreadList.Locate(_AllThreadLists, engine, pxReadyTaskList, ThreadListType.Ready, xStateListItem_Offset); } ThreadList.Locate(_AllThreadLists, engine, engine.Symbols.LookupVariable("xDelayedTaskList1"), ThreadListType.Delayed, xStateListItem_Offset); ThreadList.Locate(_AllThreadLists, engine, engine.Symbols.LookupVariable("xDelayedTaskList2"), ThreadListType.Delayed, xStateListItem_Offset); ThreadList.Locate(_AllThreadLists, engine, engine.Symbols.LookupVariable("xSuspendedTaskList"), ThreadListType.Suspended, xStateListItem_Offset); _Children = new ILiveWatchNode[] { new KernelNode(this, engine), new ThreadListNode(this), new QueueListNode(this), new HeapStructureNode(this) }; }
public Node(LinkedListNodeCache linkedListNodeCache, ulong address) { _Cache = linkedListNodeCache; _Address = address; _Variable = _Cache._Engine.Memory.CreateLiveVariable(address + (uint)_Cache._Start, _Cache._Length) ?? throw new Exception($"Failed to create live variable at 0x{address:x8}"); }
public CurrentTaskNode(NodeSource root, ILiveVariable pxCurrentTCB) : base("$rtos.kernel.current_task") { _pxCurrentTCB = pxCurrentTCB; _Root = root; Name = "Current Task"; }
ThreadList(ThreadListType type, ulong endNodeAddress, ILiveVariable xListEnd_pxNext, string name, ILiveVariable uxNumberOfItems, uint listItemOffsetInTCB) { Type = type; EndNodeAddress = endNodeAddress; this.xListEnd_pxNext = xListEnd_pxNext; this.uxNumberOfItems = uxNumberOfItems; _ListItemOffsetInTCB = listItemOffsetInTCB; _Name = name; }
public KernelNode(NodeSource root, ILiveWatchEngine engine) : base("$rtos.kernel") { _Root = root; _Engine = engine; _xSchedulerRunning = engine.CreateLiveVariable("xSchedulerRunning", false); Name = "Kernel"; Capabilities = LiveWatchCapabilities.CanHaveChildren; }
public void Reset() { uxMessagesWaiting?.Dispose(); uxMessagesWaiting = null; uxLength?.Dispose(); uxLength = null; u_xSemaphore_xMutexHolder?.Dispose(); u_xSemaphore_xMutexHolder = null; u_xSemaphore_uxRecursiveCallCount?.Dispose(); u_xSemaphore_uxRecursiveCallCount = null; }
public HeapUsageNode(ILiveWatchEngine engine, ILiveVariable variable, HeapNodeType type, int heapSize) : base("$rtos.kernel.heap_current") { _Variable = variable; _HeapSize = heapSize; SelectedFormatter = engine.GetDefaultFormatter(ScalarVariableType.SInt32); if (type == HeapNodeType.Current) { Name = "Heap Usage"; } else { Name = "Max. Heap Usage"; } }
public StackInfoNode(ILiveWatchEngine engine) : base("$stack") { _Engine = engine; SelectedFormatter = engine.GetDefaultFormatter(ScalarVariableType.SInt32); _UnusedStackFillPatern = engine.Settings.UnusedStackFillPattern; _MaxBorderVariableSize = engine.Settings.StackBorderWatchSize; Name = "Highest Stack Usage"; Capabilities |= LiveWatchCapabilities.CanHaveChildren; try { var endOfStackVariable = engine.Symbols.TryLookupRawSymbolInfo("_estack") ?? engine.Symbols.TryLookupRawSymbolInfo("__StackLimit") ?? throw new Exception("No '_estack' or '__StackLimit' symbol found."); _StackEnd = endOfStackVariable.Address; var reservedForStackVariable = engine.Symbols.LookupVariable("ReservedForStack"); if (reservedForStackVariable != null && reservedForStackVariable.Size != 0) { //Stack size is fixed. No need to monitor outside it. _StackStart = _StackEnd - (uint)reservedForStackVariable.Size; } else { //Stack size is variable. Initially, it starts right after the 'end' symbol, but can be moved further as the heap grows. var endVariable = engine.Symbols.TryLookupRawSymbolInfo("end") ?? engine.Symbols.TryLookupRawSymbolInfo("_ebss") ?? engine.Symbols.TryLookupRawSymbolInfo("_edata") ?? throw new Exception("Could not find 'end', '_ebss' or '_edata'"); var heapEndVariableAddress = engine.Symbols.FindSymbolsContainingString("heap_end").SingleOrDefault().Address; if (heapEndVariableAddress != 0) { _HeapEndVariable = engine.Memory.CreateLiveVariable(heapEndVariableAddress, 4); } _StackStart = endVariable.Address; _StackOpposesGrowingHeap = true; } } catch (Exception ex) { _Error = ex.Message; } }
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)); }
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, }); }
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())); }
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 }); }