How do you map a native to IL instruction pointer in-process
In order to translate from a native instruction pointer as provided by ICorProfilerInfo2::DoStackSnapshot
to an intermediate language method offset, you must take two steps since DoStackSnapshot
provides a FunctionID
and native instruction pointer as a virtual memory address.
Step 1, is to convert the instruction pointer to a native code method offset. ( an offset from the beginning of the JITed method). This can be done with ICorProfilerInfo2::GetCodeInfo2
ULONG32 pcIL(0xffffffff);
HRESULT hr(E_FAIL);
COR_PRF_CODE_INFO* codeInfo(NULL);
COR_DEBUG_IL_TO_NATIVE_MAP* map(NULL);
ULONG32 cItem(0);
UINT_PTR nativePCOffset(0xffffffff);
if (SUCCEEDED(hr = pInfo->GetCodeInfo2(functioId, 0, &cItem, NULL)) &&
(NULL != (codeInfo = new COR_PRF_CODE_INFO[cItem])))
{
if (SUCCEEDED(hr = pInfo->GetCodeInfo2(functionId, cItem, &cItem, codeInfo)))
{
COR_PRF_CODE_INFO *pCur(codeInfo), *pEnd(codeInfo + cItem);
nativePCOffset = 0;
for (; pCur < pEnd; pCur++)
{
// 'ip' is the UINT_PTR passed to the StackSnapshotCallback as named in
// the docs I am looking at
if ((ip >= pCur->startAddress) && (ip < (pCur->startAddress + pCur->size)))
{
nativePCOffset += (instructionPtr - pCur->startAddress);
break;
}
else
{
nativePCOffset += pCur->size;
}
}
}
delete[] codeInfo; codeInfo = NULL;
}
Step 2. Once you have an offset from the begining of the natvie code method, you can use this to convert to an offset from the begining of the intermediate language method using ICorProfilerInfo2::GetILToNativeMapping
.
if ((nativePCOffset != -1) &&
SUCCEEDED(hr = pInfo->GetILToNativeMapping(functionId, 0, &cItem, NULL)) &&
(NULL != (map = new COR_DEBUG_IL_TO_NATIVE_MAP[cItem])))
{
if (SUCCEEDED(pInfo->GetILToNativeMapping(functionId, cItem, &cItem, map)))
{
COR_DEBUG_IL_TO_NATIVE_MAP* mapCurrent = map + (cItem - 1);
for (;mapCurrent >= map; mapCurrent--)
{
if ((mapCurrent->nativeStartOffset <= nativePCOffset) &&
(mapCurrent->nativeEndOffset > nativePCOffset))
{
pcIL = mapCurrent->ilOffset;
break;
}
}
}
delete[] map; map = NULL;
}
This can then be used to map the code location to a file and line number using the symbol APIs
Thanks to Mithun Shanbhag for direction in finding the solution.