2008-10-13 4 views
9

.NET Framework 용 관리되지 않는 API를 사용하여 in-process .NET 프로세스를 프로파일 링하는 경우 해당 프로세스와 관련된 IL 명령어 포인터를 조회 할 수 있습니까? StackSnapshotCallback 함수에 제공된 네이티브 명령어 포인터?네이티브에서 일리노이 명령 포인터를 처리 중일 때 어떻게 처리합니까?

아마도 현재 스택의 스냅 샷을 찍고 있으며 스택 덤프에 파일 및 줄 번호 정보를 제공하려고합니다. 관리 스택 탐색기ISymUnmanagedMethod::GetSequencePoints을 쿼리하여이 작업을 수행합니다. 이것은 훌륭하지만, 시퀀스 포인트는 오프셋과 관련되어 있으며, 나는 지금까지 (중간 언어에서) 메소드의 시작부터 오프셋이라고 가정했습니다.

그의 블로그 게시물 Profiler stack walking: Basics and beyond에 대한 후속 댓글에서 David Broman은이 매핑이 ICorDebugCode::GetILToNativeMapping을 사용하여 달성 될 수 있음을 나타냅니다. 그러나이 인터페이스를 가져 오려면 다른 프로세스에서 디버거 프로세스에 연결해야하므로 이상적인 것은 아닙니다.

나는 이러한 스냅 샷을 찍는 동안 Visual Studio 디버거 내에서 응용 프로그램을 계속 실행할 수 있기를 원하기 때문에이 단계를 피하고 싶습니다. 출력 창에서 행 번호를 클릭하고 해당 코드로 쉽게 이동합니다.

기능이 가능합니다. 관리 코드 내부에서 줄 번호가 지정된 스택 추적을 뱉어 낼 수 있습니다. 유일한 질문인데 액세스 할 수 있습니다. 또한 성능상의 이유로 스택의 실제 덤프를 지연시켜야하므로 System::Diagnostics::StackTrace 또는 System::Environment::StackTrace 기능을 사용하고 싶지 않습니다. 나중에 메서드 이름과 코드 위치를 확인하는 비용을 절약하는 것이 바람직합니다. ... 네이티브 프레임과 관리 프레임을 섞어 사용할 수 있습니다.

답변

5

ICorProfilerInfo2::DoStackSnapshot에서 제공하는 네이티브 명령 포인터를 중간 언어 메서드 오프셋으로 변환하려면 DoStackSnapshotFunctionID 및 가상 메모리 주소로 기본 명령 포인터를 제공하므로 두 단계를 수행해야합니다.

1 단계는 명령 포인터를 네이티브 코드 메서드 오프셋으로 변환하는 것입니다. (JITed 메서드의 시작 부분에서 오프셋). 사용자가 natvie 코드 방법의 시작 오프셋되면 이것은 2 단계 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; 
} 

수행 할 수 있습니다, 당신은 ICorProfilerInfo2::GetILToNativeMapping를 사용하여 중간 언어 방식의 시작에서 오프셋 (offset)로 변환하려면이 옵션을 사용할 수 있습니다.

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; 
} 

다음 해결책을 찾는 방향에 대한 Mithun Shanbhag

감사 심볼 API를 사용하여 파일과 줄 번호로 코드의 위치를지도하는 데 사용할 수 있습니다.

+0

여기서 작은 실수는 - 첫 번째 코드 조각의 17 번째 줄에있는 frame.pc가 "instructionPtr"이어야하며 이는 DoStackSnapshot 콜백의 UINT_PTR ip 매개 변수입니다. 스티븐 감사합니다! 당신은 정말로 나를 도왔습니다 :) –

+0

Hrm ... 좋은 지적. 나는 frame.pc가 어디에서 왔는지 기억이 안 난다. 어쩌면 내가 사용하고 있던 것이 무엇인지 분명히하려고 노력했을 것입니다. 어쨌든 어디서 오는지에 대한 의견이있는 실제 가치는 신중하게 보입니다. 편집 됨. 포인터 주셔서 감사. – Steven

0
Console.WriteLine("StackTrace: '{0}'", Environment.StackTrace); 

빌드가 심볼을 생성하는지 확인하십시오.

토론에 확장 :

아마 알 수있는 바와 같이

, 나는 현재 스택의 스냅 샷을 복용하고, 스택 덤프에있는 파일과 줄 번호 정보를 제공하고 싶습니다.

이 주어 - 그것은 당신이 그것을 개발하고 당신이 쉽게 당신의 도구를 디버깅, 또는 그것의 부품 수 있도록 당신이 프로세스에 연결하지 않는 유일한 이유는 것 같습니다. 그 IMO는 더 좋은 디자인 (ICorDebug 또는 w/e)을 사용할 수 없을 때 그것을 선택하지 않는 것에 대한 가난한 변명입니다. 코드가 (아마도) 외부 바이너리의 프로세스 공간에서 실행되어 알려진 (또는 더 나쁘고 알 수없는) 손상된 프로세스 상태에서 불쾌한 (때로는 드문) 부작용 (다른 사람 데이터의 손상 포함)을 유발하기 때문에 코드가 잘못 설계된 이유입니다. 그 정도면 충분하지만, 그렇지 않은 경우에도 멀티 스레드 코드 등 여러 가지 모서리 케이스가 있습니다. 디자인을 처리해야하는 곳이 있습니다.

대부분의 사람들은 일반적으로 "무엇을하고 싶으십니까?"라고 묻습니다. 명백하게 복잡한 일들에 대한 회신으로 대부분 경우에는 더 간단하고 쉬운 방법이 있습니다. 네이티브 코드에 대한 스택 추적 프로그램을 작성 했으니 지저분해질 수 있습니다.

어쩌면 당신은 결국 모든 것을 작동하게 만들 수 있습니다.02

+0

제안 해 주셔서 감사하지만 문제는 심볼의 해상도를 지연하고 관리되지 않는 프레임을 해결할 수 있음을 나타냅니다. 이 방법은 두 가지 요구 사항을 모두 충족하지 못합니다. 조금 더 노골적인 질문을 편집했습니다. – Steven

+0

디버거에서 실행중인 경우 '콜 스택'창이 이미 심볼을 해석하고 있습니다. 비 관리 프레임 - IMO 기본 스택은 이미 매우 잘 정의되어 있으며이를 수행하기위한 Win32 API 함수가 이미 있습니다. 예 : StackWalk64, SymGetLineFromAddr64 및 SymGetModuleBase64가 있습니다. –

+0

혼합 모드 스택을 표시하도록 누수 감지 도구를 수정 중이며 실제로 모든 스택을 해결하지 않으려합니다. 누출로 이어지는 것들. 모든 할당시 디버거를 중단하고 싶지 않습니다. 그리고 dbghlp 함수는 순수한 네이티브 스택에서만 작동합니다. – Steven

관련 문제