locked
How do I resolve managed symbol names using the unmanged profiling API In-process? RRS feed

  • Question

  • Basically, I need to take and store a stack trace of a mixed-mode application using the DoStackTrace callback method.   I don't know if this qualifies as synchronous or asynchronous because I am initiating the stack trace outside of a profiler callback, but for the same thread in which I am executing.

    Anyways, assuming I get a trace and can store the function or metadata ids for each funtion on the stack, how do I resolve these ids to symbol names?  I have a procedure to follow which involves using the symbol binding api and the dostacktracecallback-supplied instruction pointer, but I haven't succeeded in completing the chain from ip to function name, file and line number.

    I have a little more detailed information here How Do You Map A Native To IL Instruction Pointer In-process

    Which basically hypothesizes that I can use ICorProfilerInfo::GetILToNativeMapping for one step, but currently I am also failing to get the metadata since I am trying to do so outside of a callback ( I think ).  I am thinking of pre-emptively getting module metadata in the module load callback, but haven't worked this out yet.  And I am wongering how long that metadata pointer will be valid, and the same for metadata ids and function ids.

    Thanks,
    Steven
    • Moved by nobugz Thursday, October 23, 2008 1:25 PM better forum (Moved from Common Language Runtime to Building Development and Diagnostic Tools for .Net)
    Wednesday, October 22, 2008 7:11 PM

Answers

  • You'll have to track the module lifetimes via the ModuleLoadFinished/ModuleAttachToAssembly and ModuleUnloadStarted callbacks respectively. The module metadata will be valid only between this interval.

    To get the complete file and line information, you'll have to -

    1. Get the IL->Native code maps. This is retrievable via the ICorProfilerInfo::GetILToNativeMapping method.
    2. Once you have the corresponding IL offset, you'll have to query the PDB symbol to get the file-name & line-number. You'll have to use the APIs in DIASymReader.dll to do this. Mike stall has posted two entries on how to do this - 
    http://blogs.msdn.com/jmstall/archive/2005/09/19/il-source-map.aspx
    http://blogs.msdn.com/jmstall/archive/2005/10/08/symbol-apis.aspx

    HTH,
    -Mithun
    • Proposed as answer by Mithun Shanbhag Friday, October 24, 2008 1:46 AM
    • Marked as answer by Zhi-Xin Ye Wednesday, October 29, 2008 12:04 PM
    Friday, October 24, 2008 1:46 AM

All replies

  • You'll have to track the module lifetimes via the ModuleLoadFinished/ModuleAttachToAssembly and ModuleUnloadStarted callbacks respectively. The module metadata will be valid only between this interval.

    To get the complete file and line information, you'll have to -

    1. Get the IL->Native code maps. This is retrievable via the ICorProfilerInfo::GetILToNativeMapping method.
    2. Once you have the corresponding IL offset, you'll have to query the PDB symbol to get the file-name & line-number. You'll have to use the APIs in DIASymReader.dll to do this. Mike stall has posted two entries on how to do this - 
    http://blogs.msdn.com/jmstall/archive/2005/09/19/il-source-map.aspx
    http://blogs.msdn.com/jmstall/archive/2005/10/08/symbol-apis.aspx

    HTH,
    -Mithun
    • Proposed as answer by Mithun Shanbhag Friday, October 24, 2008 1:46 AM
    • Marked as answer by Zhi-Xin Ye Wednesday, October 29, 2008 12:04 PM
    Friday, October 24, 2008 1:46 AM
  • Great response.  I'll mark it as answer after I have had a chance to test it.

    Thanks!
    Friday, October 24, 2008 1:45 PM
  • looks like someone already marked as answer, but let me make a note that this is a little incomplete.  If you start with a native-code instruction pointer like what you get from DoStackWalk, you must first get the offset from the beginning of the native-code method since the instruction pointer is a virtual memory address. 

    This can be done with ICorProfilerInfo2::GetCodeInfo2.  Apparantly JIT-ed native methods can be discontiguous in memory, so I added logic to treat it as contiguous so that there is single offset from the method start and non-method blocks are not included.
        UINT_PTR nativePCOffset(0xffffffff);  
        if (SUCCEEDED(hr = pInfo->GetCodeInfo2(frame.fid, 0, &cItem, NULL)) &&  
            (NULL != (codeInfo = new COR_PRF_CODE_INFO[cItem])))  
        {  
            if (SUCCEEDED(hr = pInfo->GetCodeInfo2(frame.fid, cItem, &cItem, codeInfo)))  
            {  
                COR_PRF_CODE_INFO *pCur(codeInfo), *pEnd(codeInfo + cItem);  
                nativePCOffset = 0;  
                for (; pCur < pEnd; pCur++)  
                {  
                    if ((frame.pc >= pCur->startAddress) && (frame.pc < (pCur->startAddress + pCur->size)))  
                    {  
                        nativePCOffset += (frame.pc - pCur->startAddress);  
                        break;  
                    }  
                    else 
                    {  
                        nativePCOffset += pCur->size;  
                    }  
     
                }  
            }  
            delete[] codeInfo; codeInfo = NULL;  
        }  
     
    Saturday, November 1, 2008 5:01 PM
  • Here is a link to a stackoverflow question that was started by the original poster, in which he shares the full code of his solution.
    Tuesday, August 31, 2010 10:50 PM