Skip to content

Commit

Permalink
provide a switch to use old school instrumentation - OpenCover#88
Browse files Browse the repository at this point in the history
  • Loading branch information
sawilde committed May 8, 2012
1 parent 33a7af2 commit be6e491
Show file tree
Hide file tree
Showing 17 changed files with 598 additions and 485 deletions.
4 changes: 2 additions & 2 deletions build/Version/Version.cs
@@ -1,3 +1,3 @@
using System.Reflection;
[assembly: AssemblyVersion("4.0.306.1")]
[assembly: AssemblyFileVersion("4.0.306.1")]
[assembly: AssemblyVersion("4.0.408.0")]
[assembly: AssemblyFileVersion("4.0.408.0")]
8 changes: 4 additions & 4 deletions build/Version/Version.h
@@ -1,4 +1,4 @@
#define FILEVER 4,0,306,1
#define PRODUCTVER 4,0,306,1
#define STRFILEVER "4.0.306.1"
#define STRPRODUCTVER "4.0.306.1"
#define FILEVER 4,0,408,0
#define PRODUCTVER 4,0,408,0
#define STRFILEVER "4.0.408.0"
#define STRPRODUCTVER "4.0.408.0"
2 changes: 1 addition & 1 deletion build/Version/Version.wxi
@@ -1,2 +1,2 @@
<?define Version = "4.0.306.1" ?>
<?define Version = "4.0.408.0" ?>
<Include />
2 changes: 1 addition & 1 deletion build/Version/build.number
@@ -1 +1 @@
4.0.306.1
4.0.408.0
3 changes: 3 additions & 0 deletions main/OpenCover.Console/Program.cs
Expand Up @@ -156,6 +156,9 @@ private static int RunProcess(CommandLineParser parser, Action<StringDictionary>
new ProcessStartInfo(Path.Combine(Environment.CurrentDirectory, parser.Target));
environment(startInfo.EnvironmentVariables);

if (parser.OldStyleInstrumentation)
startInfo.EnvironmentVariables[@"OpenCover_Profiler_Instrumentation"] = "oldSchool";

startInfo.Arguments = parser.TargetArgs;
startInfo.UseShellExecute = false;
startInfo.WorkingDirectory = parser.TargetDir;
Expand Down
Binary file modified main/OpenCover.Documentation/Usage.pdf
Binary file not shown.
584 changes: 317 additions & 267 deletions main/OpenCover.Documentation/Usage.rtf

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions main/OpenCover.Framework/CommandLineParser.cs
Expand Up @@ -58,6 +58,7 @@ public string Usage()
builder.AppendLine(" [-coverbytest:<filter>[;<filter>][;<filter>]]");
builder.AppendLine(" [-log:[Off|Fatal|Error|Warn|Info|Debug|Verbose|All]]");
builder.AppendLine(" [-service]");
builder.AppendLine(" [-oldStyle]");
builder.AppendLine("or");
builder.AppendLine(" -?");
builder.AppendLine("");
Expand Down Expand Up @@ -148,6 +149,9 @@ public void ExtractAndValidateArguments()
case "service":
Service = true;
break;
case "oldstyle":
OldStyleInstrumentation = true;
break;
case "?":
PrintUsage = true;
break;
Expand Down Expand Up @@ -263,6 +267,11 @@ private static List<string> ExtractFilters(string rawFilters)
/// </summary>
public bool Service { get; private set; }

/// <summary>
/// Use the old style of instrumentation that even though not APTCA friendly will
/// work when - ngen install /Profile "mscorlib" - has been used
/// </summary>
public bool OldStyleInstrumentation { get; private set; }
}

}
217 changes: 128 additions & 89 deletions main/OpenCover.Profiler/CodeCoverage.cpp

Large diffs are not rendered by default.

13 changes: 9 additions & 4 deletions main/OpenCover.Profiler/CodeCoverage.h
Expand Up @@ -20,11 +20,13 @@

using namespace ATL;

#define COM_FAIL_RETURNMSG(hr, msg) if (!SUCCEEDED(hr)) { RELTRACE(msg, hr); return (hr); }
#define COM_FAIL_MSG_RETURN_ERROR(hr, msg) if (!SUCCEEDED(hr)) { RELTRACE(msg, hr); return (hr); }

#define COM_FAILMSG(hr, msg) if (!SUCCEEDED(hr)) { RELTRACE(msg, hr); return; }
//#define COM_FAILMSG(hr, msg) if (!SUCCEEDED(hr)) { RELTRACE(msg, hr); return; }

#define COM_FAIL(hr, ret) if (!SUCCEEDED(hr)) { return (ret); }
#define COM_FAIL_MSG_RETURN_OTHER(hr, ret, msg) if (!SUCCEEDED(hr)) { RELTRACE(msg, hr); return (ret); }

#include "CoverageInstrumentation.h"

// CCodeCoverage

Expand All @@ -38,6 +40,7 @@ class ATL_NO_VTABLE CCodeCoverage :
CCodeCoverage()
{
m_runtimeType = COR_PRF_DESKTOP_CLR;
m_useOldStyle = false;
}

DECLARE_REGISTRY_RESOURCEID(IDR_CODECOVERAGE)
Expand Down Expand Up @@ -104,6 +107,8 @@ END_COM_MAP()
COR_PRF_RUNTIME_TYPE m_runtimeType;
ASSEMBLYMETADATA m_runtimeVersion;

bool m_useOldStyle;

private:
mdSignature GetMethodSignatureToken_I4(ModuleID moduleID);
HRESULT GetModuleRef(ModuleID moduleId, WCHAR*moduleName, mdModuleRef &mscorlibRef);
Expand All @@ -118,6 +123,7 @@ END_COM_MAP()
HRESULT AddCriticalCuckooBody(ModuleID moduleId);
HRESULT AddSafeCuckooBody(ModuleID moduleId);
mdMemberRef RegisterSafeCuckooMethod(ModuleID moduleId);
void InstrumentMethod(ModuleID moduleId, Method& method, std::vector<SequencePoint> seqPoints, std::vector<BranchPoint> brPoints);

public:
static CCodeCoverage* g_pProfiler;
Expand All @@ -139,7 +145,6 @@ END_COM_MAP()
virtual HRESULT STDMETHODCALLTYPE JITCompilationStarted(
/* [in] */ FunctionID functionId,
/* [in] */ BOOL fIsSafeToBlock);

};

OBJECT_ENTRY_AUTO(__uuidof(CodeCoverage), CCodeCoverage)
38 changes: 22 additions & 16 deletions main/OpenCover.Profiler/CodeCoverage_ProfilerInfo.cpp
Expand Up @@ -16,15 +16,17 @@ std::wstring CCodeCoverage::GetModulePath(ModuleID moduleId)
{
ULONG dwNameSize = 512;
WCHAR szModulePath[512] = {};
COM_FAIL(m_profilerInfo->GetModuleInfo(moduleId, NULL, dwNameSize, &dwNameSize, szModulePath, NULL), std::wstring());
COM_FAIL_MSG_RETURN_OTHER(m_profilerInfo->GetModuleInfo(moduleId, NULL, dwNameSize, &dwNameSize, szModulePath, NULL), std::wstring(),
_T(" ::GetModulePath(ModuleID) => GetModuleInfo => 0x%X"));
return std::wstring(szModulePath);
}

std::wstring CCodeCoverage::GetModulePath(ModuleID moduleId, AssemblyID *pAssemblyID)
{
ULONG dwNameSize = 512;
WCHAR szModulePath[512] = {};
COM_FAIL(m_profilerInfo->GetModuleInfo(moduleId, NULL, dwNameSize, &dwNameSize, szModulePath, pAssemblyID), std::wstring());
COM_FAIL_MSG_RETURN_OTHER(m_profilerInfo->GetModuleInfo(moduleId, NULL, dwNameSize, &dwNameSize, szModulePath, pAssemblyID), std::wstring(),
_T(" ::GetModulePath(ModuleID,AssemblyID*) => GetModuleInfo => 0x%X"));
return std::wstring(szModulePath);
}

Expand All @@ -35,7 +37,8 @@ std::wstring CCodeCoverage::GetAssemblyName(AssemblyID assemblyId)
{
ULONG dwNameSize = 512;
WCHAR szAssemblyName[512] = {};
COM_FAIL(m_profilerInfo->GetAssemblyInfo(assemblyId, dwNameSize, &dwNameSize, szAssemblyName, NULL, NULL), std::wstring());
COM_FAIL_MSG_RETURN_OTHER(m_profilerInfo->GetAssemblyInfo(assemblyId, dwNameSize, &dwNameSize, szAssemblyName, NULL, NULL), std::wstring(),
_T(" ::GetAssemblyName(AssemblyID) => GetAssemblyInfo => 0x%X"));
return std::wstring(szAssemblyName);
}

Expand All @@ -44,7 +47,8 @@ std::wstring CCodeCoverage::GetAssemblyName(AssemblyID assemblyId)
/// </summary>
BOOL CCodeCoverage::GetTokenAndModule(FunctionID funcId, mdToken& functionToken, ModuleID& moduleId, std::wstring &modulePath, AssemblyID *pAssemblyId)
{
COM_FAIL(m_profilerInfo2->GetFunctionInfo2(funcId, NULL, NULL, &moduleId, &functionToken, 0, NULL, NULL), FALSE);
COM_FAIL_MSG_RETURN_OTHER(m_profilerInfo2->GetFunctionInfo2(funcId, NULL, NULL, &moduleId, &functionToken, 0, NULL, NULL), FALSE,
_T(" ::GetTokenAndModule(...) => GetFunctionInfo2 => 0x%X"));
modulePath = GetModulePath(moduleId, pAssemblyId);
return TRUE;
}
Expand All @@ -61,25 +65,27 @@ mdSignature CCodeCoverage::GetMethodSignatureToken_I4(ModuleID moduleID)
};

CComPtr<IMetaDataEmit> metaDataEmit;
COM_FAIL(m_profilerInfo2->GetModuleMetaData(moduleID, ofWrite, IID_IMetaDataEmit, (IUnknown**) &metaDataEmit), 0);
COM_FAIL_MSG_RETURN_OTHER(m_profilerInfo2->GetModuleMetaData(moduleID, ofWrite, IID_IMetaDataEmit, (IUnknown**) &metaDataEmit), 0,
_T(" ::GetMethodSignatureToken_I4(ModuleID) => GetModuleMetaData => 0x%X"));

mdSignature pmsig ;
COM_FAIL(metaDataEmit->GetTokenFromSig(unmanagedCallSignature, sizeof(unmanagedCallSignature), &pmsig), 0);
COM_FAIL_MSG_RETURN_OTHER(metaDataEmit->GetTokenFromSig(unmanagedCallSignature, sizeof(unmanagedCallSignature), &pmsig), 0,
_T(" ::GetMethodSignatureToken_I4(ModuleID) => GetTokenFromSig => 0x%X"));
return pmsig;
}


HRESULT CCodeCoverage::GetModuleRef(ModuleID moduleId, WCHAR*moduleName, mdModuleRef &mscorlibRef)
{
CComPtr<IMetaDataEmit> metaDataEmit;
COM_FAIL_RETURNMSG(m_profilerInfo->GetModuleMetaData(moduleId,
COM_FAIL_MSG_RETURN_ERROR(m_profilerInfo->GetModuleMetaData(moduleId,
ofRead | ofWrite, IID_IMetaDataEmit, (IUnknown**)&metaDataEmit),
_T("GetModuleRef => GetModuleMetaData(0x%x)"));
_T("GetModuleRef(...) => GetModuleMetaData => 0x%X"));

CComPtr<IMetaDataAssemblyEmit> metaDataAssemblyEmit;
COM_FAIL_RETURNMSG(metaDataEmit->QueryInterface(
COM_FAIL_MSG_RETURN_ERROR(metaDataEmit->QueryInterface(
IID_IMetaDataAssemblyEmit, (void**)&metaDataAssemblyEmit),
_T("GetModuleRef => QueryInterface(0x%x)"));
_T("GetModuleRef(...) => QueryInterface => 0x%X"));

if (m_profilerInfo3 != NULL)
{
Expand All @@ -105,9 +111,9 @@ HRESULT CCodeCoverage::GetModuleRef4000(IMetaDataAssemblyEmit *metaDataAssemblyE
assembly.usBuildNumber = 0;
assembly.usRevisionNumber = 0;
BYTE publicKey[] = { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 };
COM_FAIL_RETURNMSG(metaDataAssemblyEmit->DefineAssemblyRef(publicKey,
COM_FAIL_MSG_RETURN_ERROR(metaDataAssemblyEmit->DefineAssemblyRef(publicKey,
sizeof(publicKey), moduleName, &assembly, NULL, 0, 0,
&mscorlibRef), _T("GetModuleRef4000 => DefineAssemblyRef(0x%x)"));
&mscorlibRef), _T("GetModuleRef4000(...) => DefineAssemblyRef => 0x%X"));

return S_OK;
}
Expand All @@ -121,9 +127,9 @@ HRESULT CCodeCoverage::GetModuleRef2000(IMetaDataAssemblyEmit *metaDataAssemblyE
assembly.usBuildNumber = 0;
assembly.usRevisionNumber = 0;
BYTE publicKey[] = { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 };
COM_FAIL_RETURNMSG(metaDataAssemblyEmit->DefineAssemblyRef(publicKey,
COM_FAIL_MSG_RETURN_ERROR(metaDataAssemblyEmit->DefineAssemblyRef(publicKey,
sizeof(publicKey), moduleName, &assembly, NULL, 0, 0, &mscorlibRef),
_T("GetModuleRef2000 => DefineAssemblyRef(0x%x)"));
_T("GetModuleRef2000(...) => DefineAssemblyRef => 0x%X"));

return S_OK;
}
Expand All @@ -138,9 +144,9 @@ HRESULT CCodeCoverage::GetModuleRef2050(IMetaDataAssemblyEmit *metaDataAssemblyE
assembly.usRevisionNumber = 0;

BYTE publicKey[] = { 0x7C, 0xEC, 0x85, 0xD7, 0xBE, 0xA7, 0x79, 0x8E };
COM_FAIL_RETURNMSG(metaDataAssemblyEmit->DefineAssemblyRef(publicKey,
COM_FAIL_MSG_RETURN_ERROR(metaDataAssemblyEmit->DefineAssemblyRef(publicKey,
sizeof(publicKey), moduleName, &assembly, NULL, 0, 0, &mscorlibRef),
_T("GetModuleRef2050 => DefineAssemblyRef(0x%x)"));
_T("GetModuleRef2050(...) => DefineAssemblyRef => 0x%X"));

return S_OK;
}
Expand Down
107 changes: 18 additions & 89 deletions main/OpenCover.Profiler/CoverageInstrumentation.cpp
Expand Up @@ -8,98 +8,27 @@
#define DUMP_PT 1
#endif

CoverageInstrumentation::CoverageInstrumentation(IMAGE_COR_ILMETHOD* pMethod) : Method(pMethod)
namespace CoverageInstrumentation
{
}


CoverageInstrumentation::~CoverageInstrumentation(void)
{
}

void CoverageInstrumentation::AddSequenceCoverage(mdMethodDef methodDef, std::vector<SequencePoint> points)
{
#ifdef DUMP_PT
int i = 0;
for (auto it = points.begin(); it != points.end(); it++)
{
ATLTRACE(_T("SEQPT %04d IL_%04X"), i++, (*it).Offset);
}
#endif

for (auto it = points.begin(); it != points.end(); it++)
{
InstructionList instructions;

CreateInstrumentationBlock(instructions, methodDef, (*it).UniqueId);

InsertInstructionsAtOriginalOffset((*it).Offset, instructions);
}
}

void CoverageInstrumentation::AddBranchCoverage(mdMethodDef methodDef, std::vector<BranchPoint> points)
{
if (points.size() == 0) return;

#ifdef DUMP_PT
int i = 0;
for (auto bit = points.begin(); bit != points.end(); bit++)
Instruction* InsertInjectedMethod(InstructionList &instructions, mdMethodDef injectedMethodDef, ULONG uniqueId)
{
ATLTRACE(_T("BRPT %04d IL_%04X %d"), i++, (*bit).Offset, (*bit).Path);
Instruction *firstInstruction = new Instruction(CEE_LDC_I4, uniqueId);
instructions.push_back(firstInstruction);
instructions.push_back(new Instruction(CEE_CALL, injectedMethodDef));
return firstInstruction;
}
#endif

for (auto it = m_instructions.begin(); it != m_instructions.end(); ++it)
Instruction* InsertFunctionCall(InstructionList &instructions, mdSignature pvsig, FPTR pt, ULONGLONG uniqueId)
{
if ((*it)->m_isBranch && ((*it)->m_origOffset != -1))
{
OperationDetails &details = Operations::m_mapNameOperationDetails[(*it)->m_operation];
if (details.controlFlow == COND_BRANCH)
{
Instruction *pCurrent = *it;
++it;
Instruction *pNext = *it;

int idx = 0;

InstructionList instructions;

CreateInstrumentationBlock(instructions, methodDef,
(*std::find_if(points.begin(), points.end(), [pCurrent, idx](BranchPoint &bp){return bp.Offset == pCurrent->m_origOffset && bp.Path == idx;})).UniqueId);

Instruction *pJumpNext = new Instruction(CEE_BR);
pJumpNext->m_isBranch = true;
instructions.push_back(pJumpNext);
pJumpNext->m_branches.push_back(pNext);

for(auto sbit = pCurrent->m_branches.begin(); sbit != pCurrent->m_branches.end(); sbit++)
{
idx++;
Instruction *pRecordJmp = CreateInstrumentationBlock(instructions, methodDef,
(*std::find_if(points.begin(), points.end(), [pCurrent, idx](BranchPoint &bp){return bp.Offset == pCurrent->m_origOffset && bp.Path == idx;})).UniqueId);

Instruction *pSwitchJump = new Instruction(CEE_BR);
pSwitchJump->m_isBranch = true;
instructions.push_back(pSwitchJump);
pSwitchJump->m_branches.push_back(*sbit);
*sbit = pRecordJmp;
}

m_instructions.insert(it, instructions.begin(), instructions.end());
for (it = m_instructions.begin(); *it != pNext; ++it);
}
}
Instruction *firstInstruction = new Instruction(CEE_LDC_I4, uniqueId);
instructions.push_back(firstInstruction);
#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));

return firstInstruction;
}
RecalculateOffsets();
}

Instruction* CoverageInstrumentation::CreateInstrumentationBlock(InstructionList &instructions,
mdMethodDef methodDef, ULONGLONG uniqueId)
{
Instruction *firstInstruction = new Instruction(CEE_LDC_I4, uniqueId);

instructions.push_back(firstInstruction);
instructions.push_back(new Instruction(CEE_CALL, methodDef));

return firstInstruction;
}
}

0 comments on commit be6e491

Please sign in to comment.