Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

C# - 닷넷 코어에서 다른 스레드의 callstack을 구하는 방법

.NET Framework와는 다르게,

다른 스레드의 호출 스택 덤프 구하는 방법
; https://www.sysnet.pe.kr/2/0/802

.NET Core에서는 기본적으로 System.Diagnostics.StackTrace 타입이 없습니다. 그것을 사용하려면 명시적으로 Nuget으로부터 System.Diagnostics.StackTrace를 참조 추가해야 합니다.

Install-Package System.Diagnostics.StackTrace

그런데, nuget의 StackTrace 타입에는 Thread 타입을 받는 생성자가 없습니다.

Thread newThread = new Thread(Run);
newThread.Start();

newThread.Suspend();
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(/* newThread, */ false);
newThread.Resume();

그래서 다른 스레드의 호출 스택을 받을 방법이 없습니다.




이를 우회할 수 있는 현실적인 방법으로는 그나마 ClrMD가 적당해 보입니다.

.NET 스레드 콜 스택 덤프 (7) - ClrMD(Microsoft.Diagnostics.Runtime)를 이용한 방법
; https://www.sysnet.pe.kr/2/0/11043

Install-Package Microsoft.Diagnostics.Runtime

다음은 .NET Core에서의 사용 예제입니다.

using Microsoft.Diagnostics.Runtime;
using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main: " + Thread.CurrentThread.ManagedThreadId);

            Thread t = new Thread(CallMethod);
            t.Start();

            DoLoop();
        }

        private static void DoLoop()
        {
            int i = 0;
            while (true)
            {
                Console.WriteLine("==================================================" + (i++).ToString());
                Thread.Sleep(1000);
            }
        }

        private static void CallMethod(object obj)
        {
            while (true)
            {
                var pid = Process.GetCurrentProcess().Id;

                using (var dataTarget = DataTarget.AttachToProcess(pid, false))
                {
                    ClrInfo runtimeInfo = dataTarget.ClrVersions[0];
                    using (ClrRuntime runtime = runtimeInfo.CreateRuntime())
                    {
                        foreach (var t in runtime.Threads)
                        {
                            foreach (ClrStackFrame st in t.EnumerateStackTrace())
                            {
                                // Console.WriteLine($"{t.ManagedThreadId} {st.Method} {st.Kind} at 0x{st.InstructionPointer.ToString("x")}");

                                Console.WriteLine(st);
                            }

                            Console.WriteLine();
                        }
                    }
                }
            }
        }
    }
}
/* 출력 결과 Console.WriteLine($"{t.ManagedThreadId} {st.Method} {st.Kind} at 0x{st.InstructionPointer.ToString("x")}");

1  Runtime at 0x0
1 System.Threading.Thread.Sleep(Int32) ManagedMethod at 0x7ff83de0b92b
1 ConsoleApp1.Program.DoLoop() ManagedMethod at 0x7ff7e1e46347
1 ConsoleApp1.Program.Main(System.String[]) ManagedMethod at 0x7ff7e1e41046
1  Runtime at 0x7ff841953903
1  Runtime at 0x7ff841953903

2  Runtime at 0x0

3  ManagedMethod at 0x0
*/

/* 출력 결과 Console.WriteLine(st);

[HelperMethodFrame]
System.Threading.Thread.Sleep(Int32)
ConsoleApp1.Program.DoLoop()
ConsoleApp1.Program.Main(System.String[])
[GCFrame]
[GCFrame]

[DebuggerU2MCatchHandlerFrame]
*/

(첨부 파일은 이 글의 예제 코드를 포함합니다.)

보는 바와 같이 순수 Managed 영역의 호출 스택만 정상적으로 값을 받아올 수 있고 그 외 Native/Runtime 등의 호출 스택 정보는 알 수 없습니다. 또한, (아마도 향후 지원할지는 모르겠지만) 소스 코드 라인 정보도 구할 방법이 없습니다.

게다가, 이전 버전(1.1.142101)과는 달리 현재 2.0.161401에서는 저렇게 무한 루프를 돌며 호출 스택을 구하면 어느 순간 화면에 "[Unknown Frame]"이 반복되며 더 이상 정상적인 동작을 하지 않는 문제가 있습니다. (그러니까, "그나마" 나은 방법입니다. ^^;)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 1/5/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... [106]  107  108  109  110  111  112  113  114  115  116  117  118  119  120  ...
NoWriterDateCnt.TitleFile(s)
11274정성태8/22/201719341.NET Framework: 674. Thread 타입의 Suspend/Resume/Join 사용 관련 예외 처리
11273정성태8/22/201721627오류 유형: 415. 윈도우 업데이트 에러 Error 0x80070643
11272정성태8/21/201724778VS.NET IDE: 120. 비주얼 스튜디오 2017 버전 15.3.1 - C# 7.1 공개 [2]
11271정성태8/19/201719202VS.NET IDE: 119. Visual Studio 2017에서 .NET Core 2.0 프로젝트 환경 구성하는 방법
11270정성태8/17/201730686.NET Framework: 673. C#에서 enum을 boxing 없이 int로 변환하기 [2]
11269정성태8/17/201721465디버깅 기술: 93. windbg - 풀 덤프에서 .NET 스레드의 상태를 알아내는 방법
11268정성태8/14/201721030디버깅 기술: 92. windbg - C# Monitor Lock을 획득하고 있는 스레드 찾는 방법
11267정성태8/10/201725095.NET Framework: 672. 모노 개발 환경
11266정성태8/10/201724903.NET Framework: 671. C# 6.0 이상의 소스 코드를 Visual Studio 설치 없이 명령행에서 컴파일하는 방법
11265정성태8/10/201753135기타: 66. 도서: 시작하세요! C# 7.1 프로그래밍: 기본 문법부터 실전 예제까지 [11]
11264정성태8/9/201724038오류 유형: 414. UWP app을 signtool.exe로 서명 시 0x8007000b 오류 발생
11263정성태8/9/201719520오류 유형: 413. The C# project "..." is targeting ".NETFramework, Version=v4.0", which is not installed on this machine. [3]
11262정성태8/5/201718225오류 유형: 412. windbg - SOS does not support the current target architecture. [3]
11261정성태8/4/201720818디버깅 기술: 91. windbg - 풀 덤프 파일로부터 강력한 이름의 어셈블리 추출 후 사용하는 방법
11260정성태8/3/201718907.NET Framework: 670. C# - 실행 파일로부터 공개키를 추출하는 방법
11259정성태8/2/201718139.NET Framework: 669. 지연 서명된 어셈블리를 sn.exe -Vr 등록 없이 사용하는 방법
11258정성태8/1/201718931.NET Framework: 668. 지연 서명된 DLL과 서명된 DLL의 차이점파일 다운로드1
11257정성태7/31/201719142.NET Framework: 667. bypassTrustedAppStrongNames 옵션 설명파일 다운로드1
11256정성태7/25/201720628디버깅 기술: 90. windbg의 lm 명령으로 보이지 않는 .NET 4.0 ClassLibrary를 명시적으로 로드하는 방법 [1]
11255정성태7/18/201723185디버깅 기술: 89. Win32 Debug CRT Heap Internals의 0xBAADF00D 표시 재현 [1]파일 다운로드3
11254정성태7/17/201719522개발 환경 구성: 322. "Visual Studio Emulator for Android" 에뮬레이터를 "Android Studio"와 함께 쓰는 방법
11253정성태7/17/201719828Math: 21. "Coding the Matrix" 문제 2.5.1 풀이 [1]파일 다운로드1
11252정성태7/13/201718428오류 유형: 411. RTVS 또는 PTVS 실행 시 Could not load type 'Microsoft.VisualStudio.InteractiveWindow.Shell.IVsInteractiveWindowFactory2'
11251정성태7/13/201717098디버깅 기술: 88. windbg 분석 - webengine4.dll의 MgdExplicitFlush에서 발생한 System.AccessViolationException의 crash 문제 (2)
11250정성태7/13/201720674디버깅 기술: 87. windbg 분석 - webengine4.dll의 MgdExplicitFlush에서 발생한 System.AccessViolationException의 crash 문제 [1]
11249정성태7/12/201718484오류 유형: 410. LoadLibrary("[...].dll") failed - The specified procedure could not be found.
... [106]  107  108  109  110  111  112  113  114  115  116  117  118  119  120  ...