VOID BtrUninitializeStack( VOID ) { PLIST_ENTRY ListEntry; PLIST_ENTRY ListHead; PBTR_STACK_PAGE Page; // // Close stack file // BtrCloseStackFile(); // // N.B. BtrFlushStackRecord() can not be called after this routine // ListHead = &BtrStackPageRetireList; __try { while (IsListEmpty(ListHead) != TRUE) { ListEntry = RemoveHeadList(ListHead); Page = CONTAINING_RECORD(ListEntry, BTR_STACK_PAGE, ListEntry); VirtualFree(Page, 0, MEM_RELEASE); } if (BtrStackPageFree != NULL) { VirtualFree(BtrStackPageFree, 0, MEM_RELEASE); } } __except(EXCEPTION_EXECUTE_HANDLER) { } __try { BtrDeleteLock(&BtrStackPageLock); } __except(EXCEPTION_EXECUTE_HANDLER) { } }
ULONG BtrUnloadRuntime( VOID ) { PBTR_THREAD Thread; LIST_ENTRY ListHead; PLIST_ENTRY ListEntry; LIST_ENTRY RangeListHead; LIST_ENTRY PendingListHead; LIST_ENTRY CompleteListHead; PBTR_ADDRESS_RANGE Range; // // Scan pending thread list, note that we only need scan once, // because all probes are unregistered, new thread don't get // a chance to enter runtime. // BtrAcquireLock(&BtrThreadLock); BtrScanPendingThreads(&PendingListHead, &CompleteListHead); BtrReleaseLock(&BtrThreadLock); // // Repeatly query until all pending frames are completed, in some // special cases, this will run forever, e.g. a thread is probing // a top level routine, which is always pending before the thread exit, // we have no chance to immediately unload runtime in this case, // technically we have method to walk the stack frame and hijack // its return address, but it's very complicated to do so, it's after // all a rare case. // while (IsListEmpty(&PendingListHead) != TRUE) { ListEntry = RemoveHeadList(&PendingListHead); Thread = CONTAINING_RECORD(ListEntry, BTR_THREAD, ListEntry); if (BtrIsPendingFrameExist(Thread)) { InsertTailList(&PendingListHead, &Thread->ListEntry); Sleep(1000); } else { InsertTailList(&CompleteListHead, &Thread->ListEntry); } } // // Close left threads' file and mapping objects. // while (IsListEmpty(&CompleteListHead) != TRUE) { ListEntry = RemoveHeadList(&CompleteListHead); Thread = CONTAINING_RECORD(ListEntry, BTR_THREAD, ListEntry); BtrCloseMappingPerThread(Thread); if (Thread->RundownHandle != NULL) { if (BtrIsThreadTerminated(Thread)) { // // do nothing, don't worry dirty stack since its deallocated. // } else { BtrClearThreadStack(Thread); } CloseHandle(Thread->RundownHandle); } else { // // Without rundown handle, we in fact don't know thread state, // we have to clear its stack cookie, this is a rare rare case, // I never see it till now. // BtrClearThreadStack(Thread); } } // // Ensure all threads are not executing trap code, not executing // runtime code // InitializeListHead(&RangeListHead); ListEntry = BtrTrapPageList.Flink; while (ListEntry != &BtrTrapPageList) { PBTR_TRAP_PAGE Page; Page = CONTAINING_RECORD(ListEntry, BTR_TRAP_PAGE, ListEntry); Range = BtrMalloc(sizeof(BTR_ADDRESS_RANGE)); Range->Address = (ULONG_PTR)Page->StartVa; Range->Size = (ULONG_PTR)Page->EndVa - (ULONG_PTR)Page->StartVa; InsertTailList(&RangeListHead, &Range->ListEntry); ListEntry = ListEntry->Flink; } // // Append runtime address range, note that we don't need check filter // address, because there's no pending frame, so the thread pc can not // be possible in address range of filters. // Range = BtrMalloc(sizeof(BTR_ADDRESS_RANGE)); Range->Address = BtrDllBase; Range->Size = BtrDllSize; InsertHeadList(&RangeListHead, &Range->ListEntry); InitializeListHead(&ListHead); while (BtrSuspendProcess(&ListHead) != S_OK) { SwitchToThread(); } while (BtrIsExecutingAddress(&ListHead, &RangeListHead)) { BtrResumeProcess(&ListHead); Sleep(5000); BtrSuspendProcess(&ListHead); } BtrResumeProcess(&ListHead); BtrDeleteLock(&BtrThreadLock); // // Unload all registered filters // BtrUnregisterFilters(); // // Free trap page list, note that this must be done before // heap destroy because trap page's bitmap object is allocated // from normal heap. // BtrUninitializeTrap(); BtrUninitializeProbe(); BtrUninitializeCounter(); BtrUninitializeStackTrace(); BtrUninitializeCache(); BtrUninitializeHal(); BtrUninitializeMm(); if (FlagOn(BtrFeatures, FeatureRemote)) { BtrExecuteUnloadRoutine(); ExitThread(0); // // never reach here // } // // local mode, return here // return S_OK; }
ULONG BtrWriteMarkStream( __in PPF_REPORT_HEAD Head, __in HANDLE FileHandle, __in LARGE_INTEGER Start, __out PLARGE_INTEGER End ) { ULONG Count; ULONG Size; ULONG Complete; ULONG Status; PBTR_MARK Mark; PBTR_MARK Entry; PLIST_ENTRY ListEntry; ASSERT(BtrMarkCount != 0); ASSERT(!IsListEmpty(&BtrMarkList)); Count = 0; Size = sizeof(BTR_MARK) * BtrMarkCount; Mark = (PBTR_MARK)BtrMalloc(Size); BtrAcquireLock(&BtrMarkLock); // // Serialize all marks into stream in memory // while (!IsListEmpty(&BtrMarkList)) { ListEntry = RemoveHeadList(&BtrMarkList); Entry = CONTAINING_RECORD(ListEntry, BTR_MARK, ListEntry); Mark[Count] = *Entry; BtrFree(Entry); Count += 1; } // // Verify mark count match // ASSERT(Count == BtrMarkCount); BtrMarkCount = 0; BtrReleaseLock(&BtrMarkLock); // // Write mark stream to file // Status = WriteFile(FileHandle, Mark, Size, &Complete, NULL); if (Status != TRUE) { Status = GetLastError(); } else { End->QuadPart = Start.QuadPart + Size; Status = S_OK; } BtrFree(Mark); // // Destroy mark lock // BtrDeleteLock(&BtrMarkLock); return Status; }