This is a moot point for pure C# apps, but what if you're writing in MC++ (or some other 'mixed' language) and you want to know if a function is getting compiled as managed or native code?

 

You can try and inspect the source and infer from the language rules. Eg, in MC++, look for #pragma managed / #pragma unmanaged.  However, that's risky because maybe there's some language rule that you're not aware of.  (Pop quiz: Do you know all the rules that will cause MC++ to compile a function into native code instead of IL?)

 

So if you want more paranoid verification...

  1. Use ILDasm to see if the function is actually IL.
  2. If it shows up while managed-only debugging, then it's managed code. So check if you're interop debugging,  and if you're not, anything you see is managed.
  3. Look for Managed-2-Native markers on the callstack.
  4. If you're actually stopped in the function while debugging, view the disassembly.

VS shows managed debugging disassembly starting with offset 0, eg:

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Hello World");
00000000  push        edi  
00000001  push        esi  
00000002  push        ebx  

 

Whereas native disassembly is shown with absolute addresses:

int Add(int a, int b)
{
00401000  push        ebp  
00401001  mov         ebp,esp 
    return a + b;
00401003  mov         eax,dword ptr [a] 
00401006  add         eax,dword ptr [b] 
}

This is clearly a heuristic since it's just a behavior-specific aspect of VS. The CLR Debugging services provides the actual address of jitted code, so VS could show both manage and native disassembly the same.  However, the stackwalking APIs are 100% clear about whether code is managed or native, so a debugger tool can also pass that information onto the user.