// Can't refer to the types in sospriv.h because it drags in windows.h void StressLog::EnumerateStressMsgs(/*STRESSMSGCALLBACK*/void* smcbWrapper, /*ENDTHREADLOGCALLBACK*/void* etcbWrapper, void *token) { STRESSMSGCALLBACK smcb = (STRESSMSGCALLBACK)smcbWrapper; ENDTHREADLOGCALLBACK etcb = (ENDTHREADLOGCALLBACK) etcbWrapper; void *argsCopy[StressMsg::maxArgCnt]; for (;;) { ThreadStressLog* latestLog = this->FindLatestThreadLog(); if (latestLog == 0) { break; } StressMsg* latestMsg = latestLog->readPtr; if (latestMsg->formatOffset != 0 && !latestLog->CompletedDump()) { char format[256]; TADDR taFmt = (latestMsg->formatOffset) + (TADDR)(this->moduleOffset); HRESULT hr = DacReadAll(taFmt, format, _countof(format), false); if (hr != S_OK) strcpy_s(format, _countof(format), "Could not read address of format string"); double deltaTime = ((double) (latestMsg->timeStamp - this->startTimeStamp)) / this->tickFrequency; // Pass a copy of the args to the callback to avoid foreign code overwriting the stress log // entries (this was the case for %s arguments) memcpy_s(argsCopy, sizeof(argsCopy), latestMsg->args, (latestMsg->numberOfArgs)*sizeof(void*)); if (!smcb(latestLog->threadId, deltaTime, latestMsg->facility, format, argsCopy, token)) break; } latestLog->readPtr = latestLog->AdvanceRead(); if (latestLog->CompletedDump()) { latestLog->readPtr = NULL; if (!etcb(latestLog->threadId, token)) break; } } }
PVOID DacInstantiateClassByVTable(TADDR addr, ULONG32 minSize, bool throwEx) { #ifdef _PREFIX_ // Dac accesses are not interesting for PREfix and cause alot of PREfix noise // so we just return the unmodified pointer for our PREFIX builds return (PVOID)addr; #else // !_PREFIX_ if (!g_dacImpl) { DacError(E_UNEXPECTED); UNREACHABLE(); } // Preserve special pointer values. if (!addr || addr == (TADDR)-1) { return (PVOID)addr; } // Do not attempt to allocate more than 64megs for one object instance. While we should // never even come close to this size, in cases of heap corruption or bogus data passed // into the dac, we can allocate huge amounts of data if we are unlucky. This santiy // checks the size to ensure we don't allocate gigs of data. if (minSize > 0x4000000) { if (throwEx) { DacError(E_OUTOFMEMORY); } return NULL; } // // Check the cache for an existing VPTR instance. // If there is an instance we assume that it's // the right object. // DAC_INSTANCE* inst = g_dacImpl->m_instances.Find(addr); DAC_INSTANCE* oldInst = NULL; if (inst) { // If the existing instance is a VPTR we can // reuse it, otherwise we need to promote. if (inst->usage == DAC_VPTR) { // Sanity check that the object we're returning is big enough to fill the PTR type it's being // accessed with. For more information, see the similar check below for the case when the // object isn't already cached _ASSERTE_MSG(inst->size >= minSize, "DAC coding error: Attempt to instantiate a VPTR from an object that is too small"); return inst + 1; } else { // Existing instance is not a match and must // be superseded. // Promote the new instance into the hash // in place of the old, but keep the // old instance around in case code still // has a pointer to it. But ensure that we can // create the larger instance and add it to the // hash table before removing the old one. oldInst = inst; } } HRESULT status; TADDR vtAddr; ULONG32 size; PVOID hostVtPtr; // Read the vtable pointer to get the actual // implementation class identity. if ((status = DacReadAll(addr, &vtAddr, sizeof(vtAddr), throwEx)) != S_OK) { return NULL; } // // Instantiate the right class, using the vtable as // class identity. // #define VPTR_CLASS(name) \ if (vtAddr == g_dacImpl->m_globalBase + \ g_dacGlobals.name##__vtAddr) \ { \ size = sizeof(name); \ hostVtPtr = g_dacHostVtPtrs.name; \ } \ else #define VPTR_MULTI_CLASS(name, keyBase) \ if (vtAddr == g_dacImpl->m_globalBase + \ g_dacGlobals.name##__##keyBase##__mvtAddr) \ { \ size = sizeof(name); \ hostVtPtr = g_dacHostVtPtrs.name##__##keyBase; \ } \ else #include <vptr_list.h> #undef VPTR_CLASS #undef VPTR_MULTI_CLASS { // Can't identify the vtable pointer. if (throwEx) { _ASSERTE_MSG(false,"DAC coding error: Unrecognized vtable pointer in VPTR marshalling code"); DacError(E_INVALIDARG); } return NULL; } // Sanity check that the object we're returning is big enough to fill the PTR type it's being // accessed with. // If this is not true, it means the type being marshalled isn't a sub-type (or the same type) // as the PTR type it's being used as. For example, trying to marshal an instance of a SystemDomain // object into a PTR_AppDomain will cause this ASSERT to fire (because both SystemDomain and AppDomain // derived from BaseDomain, and SystemDomain is smaller than AppDomain). _ASSERTE_MSG(size >= minSize, "DAC coding error: Attempt to instantiate a VPTR from an object that is too small"); inst = g_dacImpl->m_instances.Alloc(addr, size, DAC_VPTR); if (!inst) { DacError(E_OUTOFMEMORY); UNREACHABLE(); } // Copy the object contents into the host instance. Note that this assumes the host and target // have the same exact layout. Specifically, it assumes the host and target vtable pointers are // the same size. if ((status = DacReadAll(addr, inst + 1, size, false)) != S_OK) { g_dacImpl->m_instances.ReturnAlloc(inst); if (throwEx) { DacError(status); } return NULL; } // We now have a proper target object with a target // vtable. We need to patch the vtable to the appropriate // host vtable so that the virtual functions can be // called in the host process. *(PVOID*)(inst + 1) = hostVtPtr; if (!g_dacImpl->m_instances.Add(inst)) { g_dacImpl->m_instances.ReturnAlloc(inst); DacError(E_OUTOFMEMORY); UNREACHABLE(); } if (oldInst) { g_dacImpl->m_instances.Supersede(oldInst); } return inst + 1; #endif // !_PREFIX_ }
PVOID DacInstantiateTypeByAddressHelper(TADDR addr, ULONG32 size, bool throwEx, bool fReport) { #ifdef _PREFIX_ // Dac accesses are not interesting for PREfix and cause alot of PREfix noise // so we just return the unmodified pointer for our PREFIX builds return (PVOID)addr; #else // !_PREFIX_ if (!g_dacImpl) { DacError(E_UNEXPECTED); UNREACHABLE(); } // Preserve special pointer values. if (!addr || addr == (TADDR)-1) { return (PVOID)addr; } // DacInstanceManager::Alloc will assert (with a non-obvious message) on 0-size instances. // Fail sooner and more obviously here. _ASSERTE_MSG( size > 0, "DAC coding error: instance size cannot be 0" ); // Do not attempt to allocate more than 64megs for one object instance. While we should // never even come close to this size, in cases of heap corruption or bogus data passed // into the dac, we can allocate huge amounts of data if we are unlucky. This santiy // checks the size to ensure we don't allocate gigs of data. if (size > 0x4000000) { if (throwEx) { DacError(E_OUTOFMEMORY); } return NULL; } // // Check the cache for an existing DPTR instance. // It's possible that a previous access may have been // smaller than the current access, so we have to // allow an existing instance to be superseded. // DAC_INSTANCE* inst = g_dacImpl->m_instances.Find(addr); DAC_INSTANCE* oldInst = NULL; if (inst) { // If the existing instance is large enough we // can reuse it, otherwise we need to promote. // We cannot promote a VPTR as the VPTR data // has been updated with a host vtable and we // don't want to lose that. This shouldn't // happen anyway. if (inst->size >= size) { return inst + 1; } else { // Existing instance is too small and must // be superseded. if (inst->usage == DAC_VPTR) { // The same address has already been marshalled as a VPTR, now we're trying to marshal as a // DPTR. This is not allowed. _ASSERTE_MSG(false, "DAC coding error: DPTR/VPTR usage conflict"); DacError(E_INVALIDARG); UNREACHABLE(); } // Promote the larger instance into the hash // in place of the smaller, but keep the // smaller instance around in case code still // has a pointer to it. But ensure that we can // create the larger instance and add it to the // hash table before removing the old one. oldInst = inst; } } inst = g_dacImpl->m_instances.Alloc(addr, size, DAC_DPTR); if (!inst) { DacError(E_OUTOFMEMORY); UNREACHABLE(); } if (fReport == false) { // mark the bit if necessary inst->noReport = 1; } else { // clear the bit inst->noReport = 0; } HRESULT status = DacReadAll(addr, inst + 1, size, false); if (status != S_OK) { g_dacImpl->m_instances.ReturnAlloc(inst); if (throwEx) { DacError(status); } return NULL; } if (!g_dacImpl->m_instances.Add(inst)) { g_dacImpl->m_instances.ReturnAlloc(inst); DacError(E_OUTOFMEMORY); UNREACHABLE(); } if (oldInst) { g_dacImpl->m_instances.Supersede(oldInst); } return inst + 1; #endif // !_PREFIX_ }
static BOOL DacReadAllAdapter(PVOID address, PVOID buffer, SIZE_T size) { HRESULT hr = DacReadAll((TADDR)address, (PVOID)buffer, size, false); return SUCCEEDED(hr); }