성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>.NET Profiler - FunctionID와 연관된 ClassID를 구할 수 없는 문제</h1> <p> 일단, 이것은 정리 차원에서 쓰는 것이고 해결 방법을 포함하지 않습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> <a target='tab' href='https://www.sysnet.pe.kr/2/0/10950'>.NET Profiler</a>의 여러 이벤트 중 ClassLoadFinished 콜백은 ClassID를 인자로 받습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > HRESULT CDotnetProfiler::ClassLoadFinished(<span style='color: blue; font-weight: bold'>ClassID</span> classId, HRESULT hrStatus) { // ...[생략]... } </pre> <br /> 그리고 이후 해당 클래스의 메서드가 최초 실행되면 <a target='tab' href='https://www.sysnet.pe.kr/2/0/10959#JITCompilationStarted'>JITCompilationStarted 콜백</a>이 발생합니다. 재미있는 것은, JITCompilationStarted 단계에서 <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo-getfunctioninfo-method'>GetFunctionInfo</a>로 현재 실행 중인 메서드와 연관된 ClassID를 구하고 싶을 때가 있는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > HRESULT CDotnetProfiler::JITCompilationStarted(<span style='color: blue; font-weight: bold'>FunctionID</span> functionId, BOOL fIsSafeToBlock) { // ...[생략]... HRESULT hr = m_pICorProfilerInfo->GetFunctionInfo(functionId, <span style='color: blue; font-weight: bold'>&classId</span>, &moduleId, &methodToken); if (hr != S_OK || methodToken == 0) { return S_OK; } // ...[생략]... } </pre> <br /> GetFunctionInfo의 두 번째 인자 값이 classId == 0으로 나올 수 있습니다. 즉, 이전의 ClassLoadFinished 단계에서 알게 된 ClassID와 JITCompilationStarted 이벤트 단계에서 실행 중인 FunctionID를 연결할 수 없는 경우가 있다는 것입니다. 이런 경우 정상적으로 반환한 moduleId와 methodToken으로 다시 GetFunctionFromToken을 호출해 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > FunctionID funcId; if (m_pICorProfilerInfo->GetFunctionFromToken(moduleId, methodToken, &funcId) == S_OK) { // ...[생략]... } // hr == 0x8013135d : The given function is a generic and cannot be used with this method </pre> <br /> 0x8013135d 오류가 나오는데 이유는 해당 메서드가 Generic 타입에 속해 있기 때문입니다. 사실 GetFunctionInfo는 .NET 1.x 시절에 나온 것이므로 Generic이 추가된 .NET 2.x 이후에는 GetFunctionInfo2를 사용해 ClassID를 구할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ICorProfilerInfo2::GetFunctionInfo2 ; <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo2-getfunctioninfo2-method'>https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo2-getfunctioninfo2-method</a> </pre> <br /> 문제는 GetFunctionInfo2의 두 번째 인자로 COR_PRF_FRAME_INFO를 요구한다는 것인데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > HRESULT GetFunctionInfo2( [in] FunctionID funcId, [in] <span style='color: blue; font-weight: bold'>COR_PRF_FRAME_INFO</span> frameInfo, [out] ClassID *pClassId, [out] ModuleID *pModuleId, [out] mdToken *pToken, [in] ULONG32 cTypeArgs, [out] ULONG32 *pcTypeArgs, [out] ClassID typeArgs[]); </pre> <br /> 이 값을 Profiler에서 사용할 수 있는 경우는 FunctionEnter2가 유일합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > FunctionEnter2 Function ; <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/functionenter2-function'>https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/functionenter2-function</a> </pre> <br /> 따라서 사실상 JITCompilationStarted 이벤트에서는 ClassLoadFinished 단계의 ClassID와 연관성을 찾을 수 있는 방법이 없습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 다행이라면, 제 경우에는 ClassID를 편하게 사용한 것이긴 해도 Type Token 값으로 대체할 수 있는 상황이었다는 점입니다. 그래서 IMetaDataImport를 통해 Type Token(mdTypeRef, mdTypeDef)을 구하는 식으로 우회할 수 있었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // JITCompilationStarted IMetaDataImport* pMDImport = nullptr; hr = m_pICorProfilerInfo-><span style='color: blue; font-weight: bold'>GetTokenAndMetaDataFromFunction</span>(<span style='color: blue; font-weight: bold'>functionId</span>, IID_IMetaDataImport, (IUnknown**)&pMDImport, &methodToken); hr = pMDImport->GetMethodProps(methodToken, <span style='color: blue; font-weight: bold'>&typeToken</span>, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (hr != S_OK) { break; } </pre> <br /> 참고로, 이렇게 type token을 구한 후 이 정보를 바탕으로 ClassID를 구하는 시도를 해봤는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > hr = m_pICorProfilerInfo4->GetClassFromToken(moduleId, typeDef, &classId); // hr == 0x8013135c - The given function is a generic and cannot be used with this method. </pre> <br /> 역시나 Generic인 경우 오류가 발생합니다. ^^; 어쩔 수 없군요, 그냥 ClassID 대신 Type Token까지 얻은 걸로 만족해야겠습니다. (혹시 FunctionID로부터 ClassID를 구할 수 있는 방법을 아시는 분은 덧글 부탁드립니다. ^^)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
9146
(왼쪽의 숫자를 입력해야 합니다.)