This repository has been archived by the owner on Nov 15, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 248
/
CodeCoverage_Cuckoo.cpp
236 lines (189 loc) · 9.54 KB
/
CodeCoverage_Cuckoo.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#include "stdafx.h"
#include "CodeCoverage.h"
#define CUCKOO_SAFE_METHOD_NAME L"SafeVisited"
#define CUCKOO_CRITICAL_METHOD_NAME L"VisitedCritical"
#define CUCKOO_NEST_TYPE_NAME L"System.CannotUnloadAppDomainException"
static COR_SIGNATURE visitedMethodCallSignature[] =
{
IMAGE_CEE_CS_CALLCONV_DEFAULT,
0x01,
ELEMENT_TYPE_VOID,
ELEMENT_TYPE_I4
};
static COR_SIGNATURE ctorCallSignature[] =
{
IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS,
0x00,
ELEMENT_TYPE_VOID
};
HRESULT CCodeCoverage::RegisterCuckoos(ModuleID moduleId){
CComPtr<IMetaDataEmit> metaDataEmit;
COM_FAIL_MSG_RETURN_ERROR(m_profilerInfo->GetModuleMetaData(moduleId,
ofRead | ofWrite, IID_IMetaDataEmit, (IUnknown**)&metaDataEmit),
_T(" ::ModuleLoadFinished(...) => GetModuleMetaData => 0x%X"));
if (metaDataEmit == NULL) return S_OK;
CComPtr<IMetaDataImport> metaDataImport;
COM_FAIL_MSG_RETURN_ERROR(m_profilerInfo->GetModuleMetaData(moduleId,
ofRead | ofWrite, IID_IMetaDataImport, (IUnknown**)&metaDataImport),
_T(" ::ModuleLoadFinished(...) => GetModuleMetaData => 0x%X"));
if (metaDataImport == NULL) return S_OK;
mdTypeDef systemObject = mdTokenNil;
if (S_OK == metaDataImport->FindTypeDefByName(L"System.Object", mdTokenNil, &systemObject))
{
RELTRACE(_T("::ModuleLoadFinished(...) => Adding methods to mscorlib..."));
mdMethodDef systemObjectCtor;
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->FindMethod(systemObject, L".ctor",
ctorCallSignature, sizeof(ctorCallSignature), &systemObjectCtor),
_T(" ::ModuleLoadFinished(...) => FindMethod => 0x%X)"));
ULONG ulCodeRVA = 0;
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->GetMethodProps(systemObjectCtor, NULL, NULL,
0, NULL, NULL, NULL, NULL, &ulCodeRVA, NULL),
_T(" ::ModuleLoadFinished(...) => GetMethodProps => 0x%X"));
mdCustomAttribute customAttr;
mdToken attributeCtor;
mdTypeDef attributeTypeDef;
mdTypeDef nestToken;
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->FindTypeDefByName(CUCKOO_NEST_TYPE_NAME, mdTokenNil, &nestToken),
_T(" ::ModuleLoadFinished(...) => FindTypeDefByName => 0x%X"));
// create a method that we will mark up with the SecurityCriticalAttribute
COM_FAIL_MSG_RETURN_ERROR(metaDataEmit->DefineMethod(nestToken, CUCKOO_CRITICAL_METHOD_NAME,
mdPublic | mdStatic | mdHideBySig, visitedMethodCallSignature, sizeof(visitedMethodCallSignature),
ulCodeRVA, miIL | miManaged | miPreserveSig | miNoInlining, &m_cuckooCriticalToken),
_T(" ::ModuleLoadFinished(...) => DefineMethod => 0x%X"));
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->FindTypeDefByName(L"System.Security.SecurityCriticalAttribute",
NULL, &attributeTypeDef), _T(" :ModuleLoadFinished(...) => FindTypeDefByName => 0x%X"));
if (m_runtimeType == COR_PRF_DESKTOP_CLR)
{
// for desktop we use the .ctor that takes a SecurityCriticalScope argument as the
// default (no arguments) constructor fails with "0x801311C2 - known custom attribute value is bad"
// when we try to attach it in .NET2 - .NET4 version doesn't care which one we use
mdTypeDef scopeToken;
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->FindTypeDefByName(L"System.Security.SecurityCriticalScope", mdTokenNil, &scopeToken),
_T(" ::ModuleLoadFinished(...) => FindTypeDefByName => 0x%X"));
ULONG sigLength = 4;
COR_SIGNATURE ctorCallSignatureEnum[] =
{
IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS,
0x01,
ELEMENT_TYPE_VOID,
ELEMENT_TYPE_VALUETYPE,
0x00, 0x00, 0x00, 0x00 // make room for our compressed token - should always be 2 but...
};
sigLength += CorSigCompressToken(scopeToken, &ctorCallSignatureEnum[4]);
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->FindMember(attributeTypeDef,
L".ctor", ctorCallSignatureEnum, sigLength, &attributeCtor),
_T(" ::ModuleLoadFinished(...) => FindMember => 0x%X"));
unsigned char blob[] = { 0x01, 0x00, 0x01, 0x00, 0x00, 0x00 }; // prolog U2 plus an enum of I4 (little-endian)
COM_FAIL_MSG_RETURN_ERROR(metaDataEmit->DefineCustomAttribute(m_cuckooCriticalToken, attributeCtor, blob, sizeof(blob), &customAttr),
_T(" ::ModuleLoadFinished(...) => DefineCustomAttribute => 0x%X"));
}
else
{
// silverlight only has one .ctor for this type
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->FindMember(attributeTypeDef,
L".ctor", ctorCallSignature, sizeof(ctorCallSignature), &attributeCtor),
_T(" ::ModuleLoadFinished(...) => FindMember => 0x%X"));
COM_FAIL_MSG_RETURN_ERROR(metaDataEmit->DefineCustomAttribute(m_cuckooCriticalToken, attributeCtor, NULL, 0, &customAttr),
_T(" ::ModuleLoadFinished(...) => DefineCustomAttribute => 0x%X"));
}
// create a method that we will mark up with the SecuritySafeCriticalAttribute
COM_FAIL_MSG_RETURN_ERROR(metaDataEmit->DefineMethod(nestToken, CUCKOO_SAFE_METHOD_NAME,
mdPublic | mdStatic | mdHideBySig, visitedMethodCallSignature, sizeof(visitedMethodCallSignature),
ulCodeRVA, miIL | miManaged | miPreserveSig | miNoInlining, &m_cuckooSafeToken),
_T(" ::ModuleLoadFinished(...) => DefineMethod => 0x%X"));
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->FindTypeDefByName(L"System.Security.SecuritySafeCriticalAttribute",
NULL, &attributeTypeDef),
_T(" ::ModuleLoadFinished(...) => FindTypeDefByName => 0x%X"));
COM_FAIL_MSG_RETURN_ERROR(metaDataImport->FindMember(attributeTypeDef,
L".ctor", ctorCallSignature, sizeof(ctorCallSignature), &attributeCtor),
_T(" ::ModuleLoadFinished(...) => FindMember => 0x%X"));
COM_FAIL_MSG_RETURN_ERROR(metaDataEmit->DefineCustomAttribute(m_cuckooSafeToken, attributeCtor, NULL, 0, &customAttr),
_T(" ::ModuleLoadFinished(...) => DefineCustomAttribute => 0x%X"));
RELTRACE(_T("::ModuleLoadFinished(...) => Added methods to mscorlib"));
}
return S_OK;
}
mdMemberRef CCodeCoverage::RegisterSafeCuckooMethod(ModuleID moduleId)
{
ATLTRACE(_T("::RegisterSafeCuckooMethod(%X) => %s"), moduleId, CUCKOO_SAFE_METHOD_NAME);
// for modules we are going to instrument add our reference to the method marked
// with the SecuritySafeCriticalAttribute
CComPtr<IMetaDataEmit> metaDataEmit;
COM_FAIL_MSG_RETURN_ERROR(m_profilerInfo->GetModuleMetaData(moduleId,
ofRead | ofWrite, IID_IMetaDataEmit, (IUnknown**)&metaDataEmit),
_T(" ::RegisterSafeCuckooMethod(...) => GetModuleMetaData => 0x%X"));
mdModuleRef mscorlibRef;
COM_FAIL_MSG_RETURN_ERROR(GetModuleRef(moduleId, MSCORLIB_NAME, mscorlibRef),
_T(" ::RegisterSafeCuckooMethod(...) => GetModuleRef => 0x%X"));
mdTypeDef nestToken;
COM_FAIL_MSG_RETURN_ERROR(metaDataEmit->DefineTypeRefByName(mscorlibRef, CUCKOO_NEST_TYPE_NAME, &nestToken),
_T(" ::RegisterSafeCuckooMethod(...) => DefineTypeRefByName => 0x%X"));
mdMemberRef cuckooSafeToken;
COM_FAIL_MSG_RETURN_ERROR(metaDataEmit->DefineMemberRef(nestToken, CUCKOO_SAFE_METHOD_NAME,
visitedMethodCallSignature, sizeof(visitedMethodCallSignature), &cuckooSafeToken),
_T(" ::RegisterSafeCuckooMethod(...) => DefineMemberRef => 0x%X"));
return cuckooSafeToken;
}
/// <summary>This is the method marked with the SecurityCriticalAttribute</summary>
/// <remarks>This method makes the call into the profiler</remarks>
HRESULT CCodeCoverage::AddCriticalCuckooBody(ModuleID moduleId)
{
ATLTRACE(_T("::AddCriticalCuckooBody => Adding VisitedCritical..."));
mdSignature pvsig = GetMethodSignatureToken_I4(moduleId);
void(__fastcall *pt)(ULONG) = GetInstrumentPointVisit();
BYTE data[] = { (0x01 << 2) | CorILMethod_TinyFormat, CEE_RET };
Method criticalMethod((IMAGE_COR_ILMETHOD*)data);
InstructionList instructions;
instructions.push_back(new Instruction(CEE_LDARG_0));
#if _WIN64
instructions.push_back(new Instruction(CEE_LDC_I8, (ULONGLONG)pt));
#else
instructions.push_back(new Instruction(CEE_LDC_I4, (ULONG)pt));
#endif
instructions.push_back(new Instruction(CEE_CALLI, pvsig));
criticalMethod.InsertInstructionsAtOffset(0, instructions);
//criticalMethod.DumpIL();
InstrumentMethodWith(moduleId, m_cuckooCriticalToken, instructions);
ATLTRACE(_T("::AddCriticalCuckooBody => Adding VisitedCritical - Done!"));
return S_OK;
}
/// <summary>This is the body of our method marked with the SecuritySafeCriticalAttribute</summary>
/// <remarks>Calls the method that is marked with the SecurityCriticalAttribute</remarks>
HRESULT CCodeCoverage::AddSafeCuckooBody(ModuleID moduleId)
{
ATLTRACE(_T("::AddSafeCuckooBody => Adding SafeVisited..."));
BYTE data[] = { (0x01 << 2) | CorILMethod_TinyFormat, CEE_RET };
Method criticalMethod((IMAGE_COR_ILMETHOD*)data);
InstructionList instructions;
instructions.push_back(new Instruction(CEE_LDARG_0));
instructions.push_back(new Instruction(CEE_CALL, m_cuckooCriticalToken));
criticalMethod.InsertInstructionsAtOffset(0, instructions);
//criticalMethod.DumpIL();
InstrumentMethodWith(moduleId, m_cuckooSafeToken, instructions);
ATLTRACE(_T("::AddSafeCuckooBody => Adding SafeVisited - Done!"));
return S_OK;
}
HRESULT CCodeCoverage::CuckooSupportCompilation(
AssemblyID assemblyId,
mdToken functionToken,
ModuleID moduleId)
{
// early escape if token is not one we want
if ((m_cuckooCriticalToken != functionToken) && (m_cuckooSafeToken != functionToken))
return S_OK;
// check that we have the right module
if (MSCORLIB_NAME == GetAssemblyName(assemblyId))
{
if (m_cuckooCriticalToken == functionToken)
{
COM_FAIL_MSG_RETURN_ERROR(AddCriticalCuckooBody(moduleId),
_T(" ::JITCompilationStarted(...) => AddCriticalCuckooBody => 0x%X"));
}
if (m_cuckooSafeToken == functionToken)
{
COM_FAIL_MSG_RETURN_ERROR(AddSafeCuckooBody(moduleId),
_T(" ::JITCompilationStarted(...) => AddSafeCuckooBody => 0x%X"));
}
}
return S_OK;
}