ExtOut("\n");
}
+void ExtOutStateMachineFields(AsyncRecord& ar)
+{
+ DacpMethodTableData mtabledata;
+ DacpMethodTableFieldData vMethodTableFields;
+ if (mtabledata.Request(g_sos, ar.StateMachineMT) == S_OK &&
+ vMethodTableFields.Request(g_sos, ar.StateMachineMT) == S_OK &&
+ vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0)
+ {
+ DisplayFields(ar.StateMachineMT, &mtabledata, &vMethodTableFields, (DWORD_PTR)ar.StateMachineAddr, TRUE, ar.IsValueType);
+ }
+}
+
+void FindStateMachineTypes(DWORD_PTR* corelibModule, mdTypeDef* stateMachineBox, mdTypeDef* debugStateMachineBox)
+{
+ int numModule;
+ ArrayHolder<DWORD_PTR> moduleList = ModuleFromName(const_cast<LPSTR>("System.Private.CoreLib.dll"), &numModule);
+ if (moduleList != NULL && numModule == 1)
+ {
+ *corelibModule = moduleList[0];
+ GetInfoFromName(*corelibModule, "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1", stateMachineBox);
+ GetInfoFromName(*corelibModule, "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+DebugFinalizableAsyncStateMachineBox`1", debugStateMachineBox);
+ }
+ else
+ {
+ *corelibModule = 0;
+ *stateMachineBox = 0;
+ *debugStateMachineBox = 0;
+ }
+}
+
DECLARE_API(DumpAsync)
{
INIT_API();
DisplayInvalidStructuresMessage();
}
+ // Find the state machine types
+ DWORD_PTR corelibModule;
+ mdTypeDef stateMachineBoxMd, debugStateMachineBoxMd;
+ FindStateMachineTypes(&corelibModule, &stateMachineBoxMd, &debugStateMachineBoxMd);
+
// Walk each heap object looking for async state machine objects. As we're targeting .NET Core 2.1+, all such objects
// will be Task or Task-derived types.
std::map<CLRDATA_ADDRESS, AsyncRecord> asyncRecords;
{
// Otherwise, we only care about AsyncStateMachineBox`1 as well as the DebugFinalizableAsyncStateMachineBox`1
// that's used when certain ETW events are set.
- if (_wcsncmp(itr->GetTypeName(), W("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1"), 79) != 0 &&
- _wcsncmp(itr->GetTypeName(), W("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+DebugFinalizableAsyncStateMachineBox`1"), 95) != 0)
+ DacpMethodTableData mtdata;
+ if (mtdata.Request(g_sos, TO_TADDR(itr->GetMT())) != S_OK ||
+ mtdata.Module != corelibModule ||
+ (mtdata.cl != stateMachineBoxMd && mtdata.cl != debugStateMachineBoxMd))
{
continue;
}
// Output the state machine's details as a single line.
sos::Object obj = TO_TADDR(arIt->second.Address);
- DacpMethodTableData mtabledata;
- DacpMethodTableFieldData vMethodTableFields;
- if (arIt->second.IsStateMachine &&
- mtabledata.Request(g_sos, arIt->second.StateMachineMT) == S_OK &&
- vMethodTableFields.Request(g_sos, arIt->second.StateMachineMT) == S_OK &&
- vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0)
+ if (arIt->second.IsStateMachine)
{
// This has a StateMachine. Output its details.
sos::MethodTable mt = TO_TADDR(arIt->second.StateMachineMT);
DMLOut("%s %s %8d ", DMLAsync(obj.GetAddress()), DMLDumpHeapMT(obj.GetMT()), obj.GetSize());
if (includeCompleted) ExtOut("%8s ", GetAsyncRecordStatusDescription(arIt->second));
ExtOut("%10d %S\n", arIt->second.StateValue, mt.GetName());
- if (dumpFields) DisplayFields(arIt->second.StateMachineMT, &mtabledata, &vMethodTableFields, (DWORD_PTR)arIt->second.StateMachineAddr, TRUE, arIt->second.IsValueType);
+ if (dumpFields) ExtOutStateMachineFields(arIt->second);
}
else
{
sos::MethodTable contMT = TO_TADDR(contAsyncRecord->second.StateMachineMT);
if (contAsyncRecord->second.IsStateMachine) ExtOut("(%d) ", contAsyncRecord->second.StateValue);
ExtOut("%S\n", contMT.GetName());
- }
+ if (contAsyncRecord->second.IsStateMachine && dumpFields) ExtOutStateMachineFields(contAsyncRecord->second);
+ }
else
{
ExtOut("%S\n", cont.GetTypeName());
* Find the EE data given a name. *
* *
\**********************************************************************/
-void GetInfoFromName(DWORD_PTR ModulePtr, const char* name)
+void GetInfoFromName(DWORD_PTR ModulePtr, const char* name, mdTypeDef* retMdTypeDef)
{
+ DWORD_PTR ignoredModuleInfoRet = NULL;
+ if (retMdTypeDef)
+ *retMdTypeDef = 0;
+
ToRelease<IMetaDataImport> pImport = MDImportForModule (ModulePtr);
if (pImport == 0)
return;
BOOL fStatus = FALSE;
while (ModuleDefinition->EnumMethodDefinitionByName(&h, &pMeth) == S_OK)
{
- if (fStatus)
+ if (fStatus && !retMdTypeDef)
ExtOut("-----------------------\n");
mdTypeDef token;
if (pMeth->GetTokenAndScope(&token, NULL) == S_OK)
{
- GetInfoFromModule(ModulePtr, token);
+ GetInfoFromModule(ModulePtr, token, retMdTypeDef ? &ignoredModuleInfoRet : NULL);
fStatus = TRUE;
}
pMeth->Release();
// @todo: Handle Nested classes correctly.
if (SUCCEEDED (pImport->FindTypeDefByName (pName, tkEnclose, &cl)))
{
- GetInfoFromModule(ModulePtr, cl);
+ if (retMdTypeDef)
+ *retMdTypeDef = cl;
+
+ GetInfoFromModule(ModulePtr, cl, retMdTypeDef ? &ignoredModuleInfoRet : NULL);
return;
}
// @todo: Handle Nested classes correctly.
if (SUCCEEDED(pImport->FindTypeDefByName (pName, tkEnclose, &cl)))
{
+ if (retMdTypeDef)
+ *retMdTypeDef = cl;
+
mdMethodDef token;
ULONG cTokens;
HCORENUM henum = NULL;
&token, 1, &cTokens))
&& cTokens == 1)
{
- ExtOut("Member (mdToken token) of\n");
- GetInfoFromModule(ModulePtr, cl);
+ if (!retMdTypeDef) ExtOut("Member (mdToken token) of\n");
+ GetInfoFromModule(ModulePtr, cl, retMdTypeDef ? &ignoredModuleInfoRet : NULL);
return;
}
&token, 1, &cTokens))
&& cTokens == 1)
{
- ExtOut("Field (mdToken token) of\n");
- GetInfoFromModule(ModulePtr, cl);
+ if (!retMdTypeDef) ExtOut("Field (mdToken token) of\n");
+ GetInfoFromModule(ModulePtr, cl, retMdTypeDef ? &ignoredModuleInfoRet : NULL);
return;
}
}