public UnifiedStackFrame ConvertToUnified(ClrStackFrame frame, SourceLocation sourceLocation, ThreadInfo info)
        {
            var result = new UnifiedStackFrame(frame, sourceLocation);
            result.ThreadContext = info.ContextStruct;

            return result;
        }
        /* WaitForSingleObject
        *
        * 1st: RCX (handle)
        * 000007fe`fd24102b 488bf9          mov     rdi,rcx
        * 2nd - RDX (Timeout)
        * 000007fe`fd241029 8bf2            mov     esi,edx
        */
        /* EnterCriticalSection
        *
        * 1st: RCX (CRITICAL_SECTION ptr)
        * 00007ffd`b57310cb 488bf9          mov     rdi,rcx
        */
        internal override Params GetWaitForMultipleObjectsParams(UnifiedStackFrame frame)
        {
            Params result = new Params();
            //RCX, RDX, R8, and R9

            //RCX
            //00007ffd`b57312e5 8bd9            mov     ebx,ecx
            var handlesCount = frame.ThreadContext.Context_amd64.Rbx;

            if (handlesCount > Kernel32.Const.MAXIMUM_WAIT_OBJECTS)
            {
                throw new ArgumentOutOfRangeException($"Cannot await for more then : {Kernel32.Const.MAXIMUM_WAIT_OBJECTS}, given value :{handlesCount}");
            }

            result.First = handlesCount;

            //RDX
            //00007ffd`b57312e2 4c8bea          mov     r13,rdx
            var hArrayPtr = frame.ThreadContext.Context_amd64.R13;
            result.Second = hArrayPtr;

            //3rd - R8: WaitAll (BOOLEAN)
            //00007ffd`b57312ca 4489442418      mov dword ptr[rsp + 18h],r8d
            var rspPtr = frame.StackPointer + 24;
            result.Third = base.ReadBoolean(rspPtr);

            //R9
            ////00007ffd`b57312df 458bf1          mov     r14d,r9d
            var waitTime = frame.ThreadContext.Context_amd64.R14;
            result.Fourth = waitTime;

            return result;
        }
        /* WaitForSingleObject
        *
        * 1st: RCX (handle)
        * 000007fe`fd24102b 488bf9          mov     rdi,rcx
        * 2nd - RDX (Timeout)
        * 000007fe`fd241029 8bf2            mov     esi,edx
        */
        /* EnterCriticalSection
        *
        * 1st: RCX (CRITICAL_SECTION ptr)
        * 00007ffd`b57310cb 488bf9          mov     rdi,rcx
        */
        internal override Params GetWaitForMultipleObjectsParams(UnifiedStackFrame frame)
        {
            Params result = new Params();
            //1st: RCX (Wait Objects count)
            //00007ffd`b57312e5 8bd9            mov     ebx,ecx
            result.First = frame.ThreadContext.Context_amd64.Rbx;

            if (result.First > Kernel32.Const.MAXIMUM_WAIT_OBJECTS)
            {
                throw new ArgumentOutOfRangeException($"Cannot await for more then : {Kernel32.Const.MAXIMUM_WAIT_OBJECTS}, given value { result.First}");
            }

            //2nd - RDX (Array ptr)
            //00007ffd`b57312e2 4c8bea          mov     r13,rdx
            result.Second = frame.ThreadContext.Context_amd64.R13;

            //3rd - R8: WaitAll (BOOLEAN)
            //00007ffa`d7653a90 4489442444      mov     dword ptr [rsp+44h],r8d
            var rspPtr = frame.StackPointer + 68;
            result.Third = base.ReadBoolean(rspPtr);

            //4th - R9: Timeout (DWORD)
            //00007ffa`d7653a8d 458be1          mov     r12d,r9d
            var waitTime = frame.ThreadContext.Context_amd64.R12;
            result.Fourth = waitTime;

            return result;
        }
        internal bool CheckForWinApiCalls(UnifiedStackFrame frame, string key)
        {
            bool result = frame != null
                && !String.IsNullOrEmpty(frame.Method)
                && frame.Method != null && frame.Method.Contains(key);

            return result;
        }
        internal virtual Params GetWaitForSingleObjectParams(UnifiedStackFrame frame)
        {
            Params result = new Params();

            result.First = frame.ThreadContext.Context_amd64.Rdi;
            result.Second = frame.ThreadContext.Context_amd64.Rsi;

            return result;
        }
        internal bool GetCriticalSectionBlockingObject(UnifiedStackFrame frame, ClrRuntime runtime, out UnifiedBlockingObject blockingObject)
        {
            bool result = false;

            if (frame.Handles != null && frame.Method.Contains(ENTER_CRITICAL_SECTION_FUNCTION_NAME))
            {
                blockingObject = GetCriticalSectionBlockingObject(frame, runtime);
                result = blockingObject != null;
            }
            else
            {
                blockingObject = null;
            }

            return result;
        }
        /* WaitForSingleObject
        *
        * 1st: RCX (handle)
        * 000007fe`fd24102b 488bf9          mov     rdi,rcx
        * 2nd - RDX (Timeout)
        * 000007fe`fd241029 8bf2            mov     esi,edx
        */
        /* EnterCriticalSection
        *
        * 1st: RCX (CRITICAL_SECTION ptr)
        * 00007ffd`b57310cb 488bf9          mov     rdi,rcx
        */
        internal override Params GetWaitForMultipleObjectsParams(UnifiedStackFrame frame)
        {
            throw new NotImplementedException();

            Params result = new Params();

            //1st: RCX (Wait Objects count)
            //000007fe`fd24155a 48894c2408      mov     qword ptr [rsp+8],rcx
            var rspPtr = frame.StackPointer + 8;
            result.Third = base.ReadULong(rspPtr);

            //2nd - RDX (Array ptr)

            //3rd - R8: WaitAll (BOOLEAN)

            //4th - R9: Timeout (DWORD)

            return result;
        }
        internal List<UnifiedStackFrame> ConvertToUnified(IEnumerable<DEBUG_STACK_FRAME> stackFrames,
            ClrRuntime runtime, IDebugClient debugClient, ThreadInfo info, uint pid = Constants.INVALID_PID)
        {
            bool waitFound = false;
            var reversed = stackFrames.Reverse();
            List<UnifiedStackFrame> stackTrace = new List<UnifiedStackFrame>();

            foreach (var frame in reversed)
            {
                var unified_frame = new UnifiedStackFrame(frame, (IDebugSymbols2)debugClient);
                unified_frame.ThreadContext = info.ContextStruct;

                if (!waitFound)
                {
                    waitFound = Inpsect(unified_frame, runtime, pid);
                }

                stackTrace.Add(unified_frame);
            }

            return stackTrace;
        }
 /// <summary>
 ///  Original Function call example: 
 ///    DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD  dwMilliseconds);
 /// </summary>
 protected override void DealWithSingle(UnifiedStackFrame frame, ClrRuntime runtime, uint pid)
 {
     var paramz = Strategy.GetWaitForSingleObjectParams(frame);
     EnrichUnifiedStackFrame(frame, paramz.First, pid);
 }
 /// <summary>
 /// Original Function call example: 
 ///     DWORD WaitForMultipleObjects(DWORD  nCount,HANDLE* lpHandles,BOOL bWaitAll,DWORD dwMilliseconds);
 /// </summary>
 protected override void DealWithMultiple(UnifiedStackFrame frame, ClrRuntime runtime, uint pid)
 {
     var paramz = Strategy.GetWaitForMultipleObjectsParams(frame);
     EnrichUnifiedStackFrame(frame, runtime, pid, paramz.First, paramz.Second);
 }
 /// <summary>
 /// Original Function call example: 
 ///     void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
 /// </summary>
 protected override void DealWithCriticalSection(UnifiedStackFrame frame, ClrRuntime runtime, uint pid)
 {
     var paramz = Strategy.GetEnterCriticalSectionParam(frame);
     EnrichUnifiedStackFrame(frame, paramz.First, pid);
 }
 protected void EnrichUnifiedStackFrame(UnifiedStackFrame frame, ulong handle, uint pid)
 {
     UnifiedHandle unifiedHandle = GenerateUnifiedHandle(handle, pid);
     if (unifiedHandle != null)
     {
         frame.Handles = new List<UnifiedHandle>();
         frame.Handles.Add(unifiedHandle);
     }
 }
 internal virtual Params GetEnterCriticalSectionParam(UnifiedStackFrame frame)
 {
     Params result = new Params();
     result.First = frame.ThreadContext.Context_amd64.Rdi;
     return result;
 }
        protected bool Inpsect(UnifiedStackFrame frame, ClrRuntime runtime, uint pid)
        {
            bool waitCallFound = false;

            if (CheckForWinApiCalls(frame, WAIT_FOR_SINGLE_OBJECTS_FUNCTION_NAME))
            {
                DealWithSingle(frame, runtime, pid);
            }
            else if (waitCallFound = CheckForWinApiCalls(frame, WAIT_FOR_MULTIPLE_OBJECTS_FUNCTION_NAME))
            {
                DealWithMultiple(frame, runtime, pid);
            }
            else if(CheckForWinApiCalls(frame, ENTER_CRITICAL_SECTION_FUNCTION_NAME))
            {
               DealWithCriticalSection(frame, runtime, pid);
            }

            return waitCallFound;
        }
 protected abstract UnifiedBlockingObject GetCriticalSectionBlockingObject(UnifiedStackFrame frame, ClrRuntime runtime);
        protected void EnrichUnifiedStackFrame(UnifiedStackFrame frame, ClrRuntime runtime, uint pid, ulong waitCount, ulong hPtr)
        {
            if (waitCount > Kernel32.Const.MAXIMUM_WAIT_OBJECTS)
            {
                throw new InvalidOperationException($"waitCount exceeded MAXIMUM_WAIT_OBJECTS :{ waitCount }");
            }

            var handles = ReadFromMemmory(hPtr, (uint)waitCount, runtime);

            frame.Handles = new List<UnifiedHandle>();
            foreach (var handle in handles)
            {
                ulong handleUint = Convert(handle);

                UnifiedHandle unifiedHandle = GenerateUnifiedHandle(handleUint, pid);

                if (unifiedHandle != null)
                {
                    frame.Handles.Add(unifiedHandle);
                }
            }
        }
        /// <summary>
        /// Original Function call example: 
        ///     void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
        /// </summary>
        protected override UnifiedBlockingObject GetCriticalSectionBlockingObject(UnifiedStackFrame frame, ClrRuntime runtime)
        {
            UnifiedBlockingObject result = null;

            var paramz = Strategy.GetEnterCriticalSectionParam(frame);
            result = new UnifiedBlockingObject(paramz.First, UnifiedBlockingType.CriticalSectionObject);

            return result;
        }
 protected abstract void DealWithSingle(UnifiedStackFrame frame, ClrRuntime runtime, uint pid);
 protected abstract void DealWithCriticalSection(UnifiedStackFrame frame, ClrRuntime runtime, uint pid);
 internal abstract Params GetWaitForMultipleObjectsParams(UnifiedStackFrame frame);