Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
EventProvider.cs784 linesDownload Raw Back to Eventing
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.ComponentModel;5using System.Diagnostics.CodeAnalysis;6using System.Globalization;7using System.Runtime.InteropServices;8using System.Security;9using System.Threading;10 11namespace System.Diagnostics.Eventing12{13    public class EventProvider : IDisposable14    {15        [SecurityCritical]16        private UnsafeNativeMethods.EtwEnableCallback _etwCallback;  // Trace Callback function17 18        private long _regHandle;                       // Trace Registration Handle19        private byte _level;                            // Tracing Level20        private long _anyKeywordMask;                  // Trace Enable Flags21        private long _allKeywordMask;                  // Match all keyword22        private int _enabled;                           // Enabled flag from Trace callback23        private readonly Guid _providerId;              // Control Guid24        private int _disposed;                          // when 1, provider has unregister25 26        [ThreadStatic]27        private static WriteEventErrorCode t_returnCode; // thread slot to keep last error28 29        [ThreadStatic]30        private static Guid t_activityId;31 32        private const int s_basicTypeAllocationBufferSize = 16;33        private const int s_etwMaxNumberArguments = 32;34        private const int s_etwAPIMaxStringCount = 8;35        private const int s_maxEventDataDescriptors = 128;36        private const int s_traceEventMaximumSize = 65482;37        private const int s_traceEventMaximumStringSize = 32724;38 39        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]40        public enum WriteEventErrorCode : int41        {42            // check mapping to runtime codes43            NoError = 0,44            NoFreeBuffers = 1,45            EventTooBig = 246        }47 48        [StructLayout(LayoutKind.Explicit, Size = 16)]49        private struct EventData50        {51            [FieldOffset(0)]52            internal ulong DataPointer;53 54            [FieldOffset(8)]55            internal uint Size;56 57            [FieldOffset(12)]58            internal int Reserved;59        }60 61        private enum ActivityControl : uint62        {63            EVENT_ACTIVITY_CTRL_GET_ID = 1,64            EVENT_ACTIVITY_CTRL_SET_ID = 2,65            EVENT_ACTIVITY_CTRL_CREATE_ID = 3,66            EVENT_ACTIVITY_CTRL_GET_SET_ID = 4,67            EVENT_ACTIVITY_CTRL_CREATE_SET_ID = 568        }69 70        /// <summary>71        /// Constructor for EventProvider class.72        /// </summary>73        /// <param name="providerGuid">74        /// Unique GUID among all trace sources running on a system75        /// </param>76        [SecuritySafeCritical]77        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "guid")]78        public EventProvider(Guid providerGuid)79        {80            _providerId = providerGuid;81 82            //83            // EtwRegister the ProviderId with ETW84            //85            EtwRegister();86        }87 88        /// <summary>89        /// This method registers the controlGuid of this class with ETW.90        /// We need to be running on Vista or above. If not an91        /// PlatformNotSupported exception will be thrown.92        /// If for some reason the ETW EtwRegister call failed93        /// a NotSupported exception will be thrown.94        /// </summary>95        [System.Security.SecurityCritical]96        private unsafe void EtwRegister()97        {98            uint status;99 100            _etwCallback = new UnsafeNativeMethods.EtwEnableCallback(EtwEnableCallBack);101 102            status = UnsafeNativeMethods.EventRegister(in _providerId, _etwCallback, null, ref _regHandle);103            if (status != 0)104            {105                throw new Win32Exception((int)status);106            }107        }108 109        //110        // implement Dispose Pattern to early deregister from ETW instead of waiting for111        // the finalizer to call deregistration.112        // Once the user is done with the provider it needs to call Close() or Dispose()113        // If neither are called the finalizer will unregister the provider anyway114        //115        public void Dispose()116        {117            Dispose(true);118            GC.SuppressFinalize(this);119        }120 121        [System.Security.SecuritySafeCritical]122        protected virtual void Dispose(bool disposing)123        {124            //125            // explicit cleanup is done by calling Dispose with true from126            // Dispose() or Close(). The disposing argument is ignored because there127            // are no unmanaged resources.128            // The finalizer calls Dispose with false.129            //130 131            //132            // check if the object has been already disposed133            //134            if (_disposed == 1)135            {136                return;137            }138 139            if (Interlocked.Exchange(ref _disposed, 1) != 0)140            {141                // somebody is already disposing the provider142                return;143            }144 145            //146            // Disables Tracing in the provider, then unregister147            //148 149            _enabled = 0;150 151            Deregister();152        }153 154        /// <summary>155        /// This method deregisters the controlGuid of this class with ETW.156        /// </summary>157        public virtual void Close()158        {159            Dispose();160        }161 162        ~EventProvider()163        {164            Dispose(false);165        }166 167        /// <summary>168        /// This method un-registers from ETW.169        /// </summary>170        [System.Security.SecurityCritical]171        private unsafe void Deregister()172        {173            //174            // Unregister from ETW using the RegHandle saved from175            // the register call.176            //177 178            if (_regHandle != 0)179            {180                UnsafeNativeMethods.EventUnregister(_regHandle);181                _regHandle = 0;182            }183        }184 185        [System.Security.SecurityCritical]186        private unsafe void EtwEnableCallBack(187                        [In] ref System.Guid sourceId,188                        [In] int isEnabled,189                        [In] byte setLevel,190                        [In] long anyKeyword,191                        [In] long allKeyword,192                        [In] void* filterData,193                        [In] void* callbackContext194                        )195        {196            _enabled = isEnabled;197            _level = setLevel;198            _anyKeywordMask = anyKeyword;199            _allKeywordMask = allKeyword;200            return;201        }202 203        /// <summary>204        /// IsEnabled, method used to test if provider is enabled.205        /// </summary>206        public bool IsEnabled()207        {208            return _enabled != 0;209        }210 211        /// <summary>212        /// IsEnabled, method used to test if event is enabled.213        /// </summary>214        /// <param name="level">215        /// Level to test216        /// </param>217        /// <param name="keywords">218        /// Keyword to test219        /// </param>220        public bool IsEnabled(byte level, long keywords)221        {222            //223            // If not enabled at all, return false.224            //225 226            if (_enabled == 0)227            {228                return false;229            }230 231            // This also covers the case of Level == 0.232            if ((level <= _level) ||233                (_level == 0))234            {235                //236                // Check if Keyword is enabled237                //238 239                if ((keywords == 0) ||240                    (((keywords & _anyKeywordMask) != 0) &&241                     ((keywords & _allKeywordMask) == _allKeywordMask)))242                {243                    return true;244                }245            }246 247            return false;248        }249 250        public static WriteEventErrorCode GetLastWriteEventError()251        {252            return t_returnCode;253        }254 255        //256        // Helper function to set the last error on the thread257        //258        private static void SetLastError(int error)259        {260            switch (error)261            {262                case UnsafeNativeMethods.ERROR_ARITHMETIC_OVERFLOW:263                case UnsafeNativeMethods.ERROR_MORE_DATA:264                    t_returnCode = WriteEventErrorCode.EventTooBig;265                    break;266                case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY:267                    t_returnCode = WriteEventErrorCode.NoFreeBuffers;268                    break;269            }270        }271 272        [System.Security.SecurityCritical]273        private static unsafe string EncodeObject(ref object data, EventData* dataDescriptor, byte* dataBuffer)274        /*++275 276        Routine Description:277 278           This routine is used by WriteEvent to unbox the object type and279           to fill the passed in ETW data descriptor.280 281        Arguments:282 283           data - argument to be decoded284 285           dataDescriptor - pointer to the descriptor to be filled286 287           dataBuffer - storage buffer for storing user data, needed because cant get the address of the object288 289        Return Value:290 291           null if the object is a basic type other than string. String otherwise292 293        --*/294        {295            dataDescriptor->Reserved = 0;296 297            if (data is string sRet)298            {299                dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);300                return sRet;301            }302 303            if (data == null)304            {305                dataDescriptor->Size = 0;306                dataDescriptor->DataPointer = 0;307            }308            else if (data is IntPtr)309            {310                dataDescriptor->Size = (uint)sizeof(IntPtr);311                IntPtr* intptrPtr = (IntPtr*)dataBuffer;312                *intptrPtr = (IntPtr)data;313                dataDescriptor->DataPointer = (ulong)intptrPtr;314            }315            else if (data is int)316            {317                dataDescriptor->Size = (uint)sizeof(int);318                int* intptrPtr = (int*)dataBuffer;319                *intptrPtr = (int)data;320                dataDescriptor->DataPointer = (ulong)intptrPtr;321            }322            else if (data is long)323            {324                dataDescriptor->Size = (uint)sizeof(long);325                long* longptr = (long*)dataBuffer;326                *longptr = (long)data;327                dataDescriptor->DataPointer = (ulong)longptr;328            }329            else if (data is uint)330            {331                dataDescriptor->Size = (uint)sizeof(uint);332                uint* uintptr = (uint*)dataBuffer;333                *uintptr = (uint)data;334                dataDescriptor->DataPointer = (ulong)uintptr;335            }336            else if (data is ulong)337            {338                dataDescriptor->Size = (uint)sizeof(ulong);339                ulong* ulongptr = (ulong*)dataBuffer;340                *ulongptr = (ulong)data;341                dataDescriptor->DataPointer = (ulong)ulongptr;342            }343            else if (data is char)344            {345                dataDescriptor->Size = (uint)sizeof(char);346                char* charptr = (char*)dataBuffer;347                *charptr = (char)data;348                dataDescriptor->DataPointer = (ulong)charptr;349            }350            else if (data is byte)351            {352                dataDescriptor->Size = (uint)sizeof(byte);353                byte* byteptr = (byte*)dataBuffer;354                *byteptr = (byte)data;355                dataDescriptor->DataPointer = (ulong)byteptr;356            }357            else if (data is short)358            {359                dataDescriptor->Size = (uint)sizeof(short);360                short* shortptr = (short*)dataBuffer;361                *shortptr = (short)data;362                dataDescriptor->DataPointer = (ulong)shortptr;363            }364            else if (data is sbyte)365            {366                dataDescriptor->Size = (uint)sizeof(sbyte);367                sbyte* sbyteptr = (sbyte*)dataBuffer;368                *sbyteptr = (sbyte)data;369                dataDescriptor->DataPointer = (ulong)sbyteptr;370            }371            else if (data is ushort)372            {373                dataDescriptor->Size = (uint)sizeof(ushort);374                ushort* ushortptr = (ushort*)dataBuffer;375                *ushortptr = (ushort)data;376                dataDescriptor->DataPointer = (ulong)ushortptr;377            }378            else if (data is float)379            {380                dataDescriptor->Size = (uint)sizeof(float);381                float* floatptr = (float*)dataBuffer;382                *floatptr = (float)data;383                dataDescriptor->DataPointer = (ulong)floatptr;384            }385            else if (data is double)386            {387                dataDescriptor->Size = (uint)sizeof(double);388                double* doubleptr = (double*)dataBuffer;389                *doubleptr = (double)data;390                dataDescriptor->DataPointer = (ulong)doubleptr;391            }392            else if (data is bool)393            {394                dataDescriptor->Size = (uint)sizeof(bool);395                bool* boolptr = (bool*)dataBuffer;396                *boolptr = (bool)data;397                dataDescriptor->DataPointer = (ulong)boolptr;398            }399            else if (data is Guid)400            {401                dataDescriptor->Size = (uint)sizeof(Guid);402                Guid* guidptr = (Guid*)dataBuffer;403                *guidptr = (Guid)data;404                dataDescriptor->DataPointer = (ulong)guidptr;405            }406            else if (data is decimal)407            {408                dataDescriptor->Size = (uint)sizeof(decimal);409                decimal* decimalptr = (decimal*)dataBuffer;410                *decimalptr = (decimal)data;411                dataDescriptor->DataPointer = (ulong)decimalptr;412            }413            else414            {415                // To our eyes, everything else is a just a string416                sRet = data.ToString();417                dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);418                return sRet;419            }420 421            return null;422        }423 424        /// <summary>425        /// WriteMessageEvent, method to write a string with level and Keyword.426        /// The activity ID will be propagated only if the call stays on the same native thread as SetActivityId().427        /// </summary>428        /// <param name="eventMessage">429        /// Message to write430        /// </param>431        /// <param name="eventLevel">432        /// Level to test433        /// </param>434        /// <param name="eventKeywords">435        /// Keyword to test436        /// </param>437        [System.Security.SecurityCritical]438        public bool WriteMessageEvent(string eventMessage, byte eventLevel, long eventKeywords)439        {440            int status = 0;441 442            ArgumentNullException.ThrowIfNull(eventMessage);443 444            if (IsEnabled(eventLevel, eventKeywords))445            {446                if (eventMessage.Length > s_traceEventMaximumStringSize)447                {448                    t_returnCode = WriteEventErrorCode.EventTooBig;449                    return false;450                }451 452                unsafe453                {454                    fixed (char* pdata = eventMessage)455                    {456                        status = (int)UnsafeNativeMethods.EventWriteString(_regHandle, eventLevel, eventKeywords, pdata);457                    }458 459                    if (status != 0)460                    {461                        SetLastError(status);462                        return false;463                    }464                }465            }466 467            return true;468        }469 470        /// <summary>471        /// WriteMessageEvent, method to write a string with level=0 and Keyword=0472        /// The activity ID will be propagated only if the call stays on the same native thread as SetActivityId().473        /// </summary>474        /// <param name="eventMessage">475        /// Message to log476        /// </param>477        public bool WriteMessageEvent(string eventMessage)478        {479            return WriteMessageEvent(eventMessage, 0, 0);480        }481 482        /// <summary>483        /// WriteEvent method to write parameters with event schema properties.484        /// </summary>485        /// <param name="eventDescriptor">486        /// Event Descriptor for this event.487        /// </param>488        /// <param name="eventPayload">489        /// </param>490        public bool WriteEvent(in EventDescriptor eventDescriptor, params object[] eventPayload)491        {492            return WriteTransferEvent(in eventDescriptor, Guid.Empty, eventPayload);493        }494 495        /// <summary>496        /// WriteEvent, method to write a string with event schema properties.497        /// </summary>498        /// <param name="eventDescriptor">499        /// Event Descriptor for this event.500        /// </param>501        /// <param name="data">502        /// string to log.503        /// </param>504        [System.Security.SecurityCritical]505        [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]506        public bool WriteEvent(in EventDescriptor eventDescriptor, string data)507        {508            uint status = 0;509 510            ArgumentNullException.ThrowIfNull(data);511 512            if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))513            {514                if (data.Length > s_traceEventMaximumStringSize)515                {516                    t_returnCode = WriteEventErrorCode.EventTooBig;517                    return false;518                }519 520                EventData userData;521 522                userData.Size = (uint)((data.Length + 1) * 2);523                userData.Reserved = 0;524 525                unsafe526                {527                    fixed (char* pdata = data)528                    {529                        Guid activityId = GetActivityId();530                        userData.DataPointer = (ulong)pdata;531 532                        status = UnsafeNativeMethods.EventWriteTransfer(_regHandle,533                                                                        in eventDescriptor,534                                                                        (activityId == Guid.Empty) ? null : &activityId,535                                                                        null,536                                                                        1,537                                                                        &userData);538                    }539                }540            }541 542            if (status != 0)543            {544                SetLastError((int)status);545                return false;546            }547 548            return true;549        }550 551        /// <summary>552        /// WriteEvent, method to be used by generated code on a derived class.553        /// </summary>554        /// <param name="eventDescriptor">555        /// Event Descriptor for this event.556        /// </param>557        /// <param name="dataCount">558        /// number of event descriptors559        /// </param>560        /// <param name="data">561        /// pointer do the event data562        /// </param>563        [System.Security.SecurityCritical]564        protected bool WriteEvent(in EventDescriptor eventDescriptor, int dataCount, IntPtr data)565        {566            uint status = 0;567 568            unsafe569            {570                Guid activityId = GetActivityId();571 572                status = UnsafeNativeMethods.EventWriteTransfer(573                                    _regHandle,574                                    in eventDescriptor,575                                    (activityId == Guid.Empty) ? null : &activityId,576                                    null,577                                    (uint)dataCount,578                                    (void*)data);579            }580 581            if (status != 0)582            {583                SetLastError((int)status);584                return false;585            }586 587            return true;588        }589 590        /// <summary>591        /// WriteTransferEvent, method to write a parameters with event schema properties.592        /// </summary>593        /// <param name="eventDescriptor">594        /// Event Descriptor for this event.595        /// </param>596        /// <param name="relatedActivityId">597        /// </param>598        /// <param name="eventPayload">599        /// </param>600        [System.Security.SecurityCritical]601        public bool WriteTransferEvent(in EventDescriptor eventDescriptor, Guid relatedActivityId, params object[] eventPayload)602        {603            uint status = 0;604 605            if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))606            {607                Guid activityId = GetActivityId();608 609                unsafe610                {611                    int argCount = 0;612                    EventData* userDataPtr = null;613 614                    if ((eventPayload != null) && (eventPayload.Length != 0))615                    {616                        argCount = eventPayload.Length;617                        if (argCount > s_etwMaxNumberArguments)618                        {619                            //620                            // too many arguments to log621                            //622                            throw new ArgumentOutOfRangeException(nameof(eventPayload),623                                string.Format(CultureInfo.CurrentCulture, DotNetEventingStrings.ArgumentOutOfRange_MaxArgExceeded, s_etwMaxNumberArguments));624                        }625 626                        uint totalEventSize = 0;627                        int index;628                        int stringIndex = 0;629                        int[] stringPosition = new int[s_etwAPIMaxStringCount]; // used to keep the position of strings in the eventPayload parameter630                        string[] dataString = new string[s_etwAPIMaxStringCount]; // string arrays from the eventPayload parameter631                        EventData* userData = stackalloc EventData[argCount];             // allocation for the data descriptors632                        userDataPtr = (EventData*)userData;633                        byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize * argCount]; // 16 byte for unboxing non-string argument634                        byte* currentBuffer = dataBuffer;635 636                        //637                        // The loop below goes through all the arguments and fills in the data638                        // descriptors. For strings save the location in the dataString array.639                        // Calculates the total size of the event by adding the data descriptor640                        // size value set in EncodeObjec method.641                        //642                        for (index = 0; index < eventPayload.Length; index++)643                        {644                            string isString;645                            isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer);646                            currentBuffer += s_basicTypeAllocationBufferSize;647                            totalEventSize += userDataPtr->Size;648                            userDataPtr++;649                            if (isString != null)650                            {651                                if (stringIndex < s_etwAPIMaxStringCount)652                                {653                                    dataString[stringIndex] = isString;654                                    stringPosition[stringIndex] = index;655                                    stringIndex++;656                                }657                                else658                                {659                                    throw new ArgumentOutOfRangeException(nameof(eventPayload),660                                        string.Format(CultureInfo.CurrentCulture, DotNetEventingStrings.ArgumentOutOfRange_MaxStringsExceeded, s_etwAPIMaxStringCount));661                                }662                            }663                        }664 665                        if (totalEventSize > s_traceEventMaximumSize)666                        {667                            t_returnCode = WriteEventErrorCode.EventTooBig;668                            return false;669                        }670 671                        fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3],672                                v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7])673                        {674                            userDataPtr = (EventData*)userData;675                            if (dataString[0] != null)676                            {677                                userDataPtr[stringPosition[0]].DataPointer = (ulong)v0;678                            }679 680                            if (dataString[1] != null)681                            {682                                userDataPtr[stringPosition[1]].DataPointer = (ulong)v1;683                            }684 685                            if (dataString[2] != null)686                            {687                                userDataPtr[stringPosition[2]].DataPointer = (ulong)v2;688                            }689 690                            if (dataString[3] != null)691                            {692                                userDataPtr[stringPosition[3]].DataPointer = (ulong)v3;693                            }694 695                            if (dataString[4] != null)696                            {697                                userDataPtr[stringPosition[4]].DataPointer = (ulong)v4;698                            }699 700                            if (dataString[5] != null)701                            {702                                userDataPtr[stringPosition[5]].DataPointer = (ulong)v5;703                            }704 705                            if (dataString[6] != null)706                            {707                                userDataPtr[stringPosition[6]].DataPointer = (ulong)v6;708                            }709 710                            if (dataString[7] != null)711                            {712                                userDataPtr[stringPosition[7]].DataPointer = (ulong)v7;713                            }714                        }715                    }716 717                    status = UnsafeNativeMethods.EventWriteTransfer(_regHandle,718                                                                    in eventDescriptor,719                                                                    (activityId == Guid.Empty) ? null : &activityId,720                                                                    (relatedActivityId == Guid.Empty) ? null : &relatedActivityId,721                                                                    (uint)argCount,722                                                                    userDataPtr);723                }724            }725 726            if (status != 0)727            {728                SetLastError((int)status);729                return false;730            }731 732            return true;733        }734 735        [System.Security.SecurityCritical]736        protected bool WriteTransferEvent(in EventDescriptor eventDescriptor, Guid relatedActivityId, int dataCount, IntPtr data)737        {738            uint status = 0;739 740            Guid activityId = GetActivityId();741 742            unsafe743            {744                status = UnsafeNativeMethods.EventWriteTransfer(745                                                _regHandle,746                                                in eventDescriptor,747                                                (activityId == Guid.Empty) ? null : &activityId,748                                                &relatedActivityId,749                                                (uint)dataCount,750                                                (void*)data);751            }752 753            if (status != 0)754            {755                SetLastError((int)status);756                return false;757            }758 759            return true;760        }761 762        [System.Security.SecurityCritical]763        private static Guid GetActivityId()764        {765            return t_activityId;766        }767 768        [System.Security.SecurityCritical]769        public static void SetActivityId(ref Guid id)770        {771            t_activityId = id;772            UnsafeNativeMethods.EventActivityIdControl((int)ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref id);773        }774 775        [System.Security.SecurityCritical]776        public static Guid CreateActivityId()777        {778            Guid newId = new();779            UnsafeNativeMethods.EventActivityIdControl((int)ActivityControl.EVENT_ACTIVITY_CTRL_CREATE_ID, ref newId);780            return newId;781        }782    }783}784