Microsoft MVP성태의 닷넷 이야기
글쓴 사람
홈페이지
첨부 파일
 

windbg - !threads 출력 결과로부터 닷넷 관리 스레드(System.Threading.Thread) 객체를 구하는 방법

모든 스레드를 열거하는 가장 쉬운 방법으로 !threads 명령어가 있습니다.

0:017> !threads
ThreadCount: 298
UnstartedThread: 0
BackgroundThread: 298
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
                                      PreEmptive   GC Alloc           Lock
       ID OSID ThreadOBJ    State     GC       Context       Domain   Count APT Exception
  26    1  fd4 00117830   1808220 Enabled  406dc694:406dc6b8 07c6bf90     1 MTA (Threadpool Worker)
  44    2  dd8 001345c8      b220 Enabled  00000000:00000000 000de1d8     0 MTA (Finalizer)
  45    3  db8 03f8fc18    80a220 Enabled  00000000:00000000 000de1d8     0 MTA (Threadpool Completion Port)
  46    4  ddc 03fe6c78      1220 Enabled  00000000:00000000 000de1d8     0 Ukn
  47    5  de8 05450cd0      b220 Enabled  4ff022a0:4ff022b0 03fe7258     0 MTA
  48    6  dc8 058a38e0   200b220 Enabled  4fe61b04:4fe620d8 03fe7258     0 MTA
  49    7  a9c 07592be8   200b220 Enabled  3c477948:3c478044 03fe7258     0 MTA
  50    8  dbc 075935d8      b220 Enabled  4412dd90:4412dd90 03fe7258     0 MTA
  51    9  5b8 07592308   200b220 Enabled  00000000:00000000 03fe7258     0 MTA
  52    a 16c8 07625850    80a220 Enabled  00000000:00000000 000de1d8     0 MTA (Threadpool Completion Port)
  24    b 1794 07626358   180a220 Enabled  00000000:00000000 000de1d8     0 MTA (Threadpool Worker)
  53    c 1738 0762dfe0      b220 Enabled  1616926c:16169274 03fe7258     0 MTA
  54    d 1678 0766cc40   200b220 Enabled  00000000:00000000 03fe7258     0 MTA
  55    e 10e4 0766bd10   200b220 Enabled  00000000:00000000 03fe7258     0 MTA
  56    f   6c 0766dd68   200b220 Enabled  00000000:00000000 03fe7258     0 MTA
  57   10 1330 0766f550   180b220 Enabled  4ef9a2c0:4ef9a2c4 07c6bf90     1 MTA (Threadpool Worker)
  58   11  208 07670718   188b224 Enabled  43445c70:43445d60 07f41fc8     1 MTA (Threadpool Worker)
...[생략]...

그런데 이 정보들로부터 System.Threading.Thread 타입을 구할 수 있는 방법이 없습니다. (혹시 쉽게 구하는 방법을 아시는 분은 덧글 부탁드립니다. ^^)

물론 다소 불편하지만 우회 방법은 있습니다. 관리 힙을 전부 뒤져서 System.Threading.Thread 타입인 것을 찾는 것인데 시작은 우선 -mt에 해당하는 MethodTable 값을 찾아야 합니다. 이에 대해서는 전에도 설명했었는데,

windbg - 닷넷 메모리 덤프에서 전역 객체의 내용을 조사하는 방법
; https://www.sysnet.pe.kr/2/0/11460

위의 내용에 따라, 다음의 명령어로 가능합니다.

0:017> !name2ee mscorlib!System.Threading.Thread
Module: 02d32010 (mscorlib.dll)
Token: 0x02000154
MethodTable: 043117dc
EEClass: 02db3280
Name: System.Threading.Thread

이렇게 구한 MethodTable == 0x43117dc를 dumpheap 명령어에 전달하면, 관리 힙에 할당되어 있는 System.Threading.Thread 타입의 인스턴스를 모두 열람해 줍니다.

0:017> !DumpHeap -mt  043117dc
------------------------------
Heap 0
 Address       MT     Size
100b1c24 043117dc       56     
1019450c 043117dc       56     
101ad1b4 043117dc       56     
101ad5b4 043117dc       56     
101ad804 043117dc       56     
101ada00 043117dc       56     
10271920 043117dc       56     
10283be8 043117dc       56     
10283f3c 043117dc       56     
10284180 043117dc       56     
10284494 043117dc       56     
103334f8 043117dc       56     
10354f28 043117dc       56     
10441584 043117dc       56     
10451968 043117dc       56     
1053a824 043117dc       56     
105c7fe4 043117dc       56     
106139b0 043117dc       56     
10613d04 043117dc       56     
10613f48 043117dc       56     
1061425c 043117dc       56   
...[생략]...

출력 결과에 나온 각각의 Address 값을 덤프해 보면,

0:017> !do 100b1c24 
Name: System.Threading.Thread
MethodTable: 043117dc
EEClass: 02db3280
Size: 56(0x38) bytes
 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
05d011f4  4000640        4 ....Contexts.Context  0 instance 141c6858 m_Context
05d0fb08  4000641        8 ....ExecutionContext  0 instance 31df6ee0 m_ExecutionContext
02d3914c  4000642        c        System.String  0 instance 00000000 m_Name
04310bb4  4000643       10      System.Delegate  0 instance 00000000 m_Delegate
05f0e400  4000644       14    System.Object[][]  0 instance 1084adc0 m_ThreadStaticsBuckets
0493cc30  4000645       18       System.Int32[]  0 instance 1084addc m_ThreadStaticsBits
0431677c  4000646       1c ...ation.CultureInfo  0 instance 00000000 m_CurrentCulture
0431677c  4000647       20 ...ation.CultureInfo  0 instance 00000000 m_CurrentUICulture
02d36d5c  4000648       24        System.Object  0 instance 00000000 m_ThreadStartArg
0431698c  4000649       28        System.IntPtr  1 instance   117830 DONT_USE_InternalThread
043c9a54  400064a       2c         System.Int32  1 instance        2 m_Priority
043c9a54  400064b       30         System.Int32  1 instance        1 m_ManagedThreadId
0493e488  400064c      16c ...LocalDataStoreMgr  0   shared   static s_LocalDataStoreMgr
    >> Domain:Value  000de1d8:00000000 03fe7258:1a0b1d2c 0778f8c0:00000000 07c6bf90:00000000 07e6d3d0:00000000 07eb6318:00000000 07f41fc8:00000000 080977e0:00000000 0812b6f0:00000000 0814feb8:00000000 082a2228:1d154ca0 083bea88:00000000 2c9ba550:00000000 0835c508:00000000 2cc681a0:00000000 2d157008:00000000 2d84be60:00000000 2d8b07b8:00000000 2d9d1c10:00000000 2da783e0:00000000 2daf2008:00000000 2db19ff0:00000000 08359a40:00000000 2dc1eea8:1476a408 2dd59f48:00000000 2ddfa9b0:00000000 2cc617e8:00000000 2df14d18:00000000 <<
02d36d5c  400064d      170        System.Object  0   shared   static s_SyncObject
    >> Domain:Value  000de1d8:100b1c18 03fe7258:100b5334 0778f8c0:140b2f24 07c6bf90:141c91c4 07e6d3d0:190b422c 07eb6318:142ec160 07f41fc8:143e1aec 080977e0:101b45b4 0812b6f0:1028a610 0814feb8:1e0b4510 082a2228:10377148 083bea88:1c0e63b8 2c9ba550:1047b448 0835c508:10552bcc 2cc681a0:18116530 2d157008:14380520 2d84be60:18219410 2d8b07b8:1069b6f8 2d9d1c10:182f6058 2da783e0:107c3890 2daf2008:12109898 2db19ff0:10625e0c 08359a40:1713b278 2dc1eea8:1c24aa14 2dd59f48:1a19071c 2ddfa9b0:1d1c87ac 2cc617e8:1f1b7e34 2df14d18:1d2e5a0c <<

DONT_USE_InternalThread 값이 !threads 목록에 있는 것과 같다는 것을 알 수 있습니다.

그런데... 스레드가 한두 개라면 모를까, 일반적인 프로그램에서 그 많은 스레드의 객체를 일일이 저렇게 뒤져보는 것도 일입니다. 따라서 이런 경우에는 pykd의 도움을 받아 스크립트로 만들어 두면 됩니다. 관련 스크립트의 힌트는 다음에서 이미 설명했었습니다.

windbg - 풀 덤프에서 .NET 스레드의 상태를 알아내는 방법
; https://www.sysnet.pe.kr/2/0/11269

따라서 이 글에 저 스크립트를 적용하면 다음과 같이 모든 Thread 타입의 관련 값을 열거할 수 있습니다.

0:006> .foreach ($t {!dumpheap -mt 043117dc -short}) {  .printf " Thread Obj ${$t} and the Thread Id is %N \n",poi(${$t}+4c) }

또는 pykd를 이용하면 좀 더 구체적으로 결과를 뽑아낼 수 있습니다.

windbg에서 python 스크립트 실행하는 방법 - pykd
; https://www.sysnet.pe.kr/2/0/11227

즉, 다음과 같이 thread ID를 기준으로 System.Threading.Thread 객체를 구할 수 있습니다.

from pykd import *

findId = "7670718"

def getItem(text, key):
    for line in text.splitlines():
        if key in line:
            result = line.split(":")[1].strip()
    return result

def GetManagedId(text):
    for line in text.splitlines():
        items = line.split()
        if len(items) >= 7 and items[7] == "DONT_USE_InternalThread":
            return items[6]

    return "NOT FOUND"

outputText = pykd.dbgCommand("!name2ee mscorlib!System.Threading.Thread")

mtThread = getItem(outputText, "MethodTable:")

outputText = pykd.dbgCommand("!DumpHeap -mt " + mtThread)

for line in outputText.splitlines():
    items = line.split()
    if len(items) == 3:
        threadAddress = items[0].strip()
        threadText = pykd.dbgCommand("!do " + threadAddress)

        managedId = GetManagedId(threadText)

        if managedId != "NOT FOUND":
            if managedId == findId:
                dprintln(threadText)
                break

dprintln ("END")

그런데... 시간이 좀 오래 걸린다는 흠이 있긴 합니다. ^^ 참고로, 위의 명령어를 응용하면 Managed Thread Id 값을 알고 있는 상태에서 그것의 System.Threading.Thread 인스턴스를 구하는 것도 가능합니다.

from pykd import *

findId = "17"

def getItem(text, key):
    for line in text.splitlines():
        if key in line:
            result = line.split(":")[1].strip()
    return result

def GetManagedId(text):
    for line in text.splitlines():
        items = line.split()
        if len(items) >= 7 and items[7] == "m_ManagedThreadId":
            return items[6]

    return "NOT FOUND"

outputText = pykd.dbgCommand("!name2ee mscorlib!System.Threading.Thread")

mtThread = getItem(outputText, "MethodTable:")

outputText = pykd.dbgCommand("!DumpHeap -mt " + mtThread)

for line in outputText.splitlines():
    items = line.split()
    if len(items) == 3:
        threadAddress = items[0].strip()
        threadText = pykd.dbgCommand("!do " + threadAddress)

        managedId = GetManagedId(threadText)

        if managedId != "NOT FOUND":
            if managedId == findId:
                dprintln(threadText)
                break

dprintln ("END")




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





[최초 등록일: ]
[최종 수정일: 4/9/2018 ]

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

비밀번호

댓글 쓴 사람
 




1  2  3  4  5  6  7  8  9  10  11  12  13  14  [15]  ...
NoWriterDateCnt.TitleFile(s)
11873정성태2/22/2020981.NET Framework: 820. (번역글) .NET Internals Cookbook Part 5 - Methods, parameters, modifiers파일 다운로드1
11872정성태5/9/20191231.NET Framework: 819. (번역글) .NET Internals Cookbook Part 4 - Type members파일 다운로드1
11871정성태5/9/20191357.NET Framework: 818. (번역글) .NET Internals Cookbook Part 3 - Initialization tricks [3]파일 다운로드1
11870정성태4/16/20191189.NET Framework: 817. Process.Start로 실행한 콘솔 프로그램의 출력 결과를 얻는 방법파일 다운로드1
11869정성태5/9/20191199.NET Framework: 816. (번역글) .NET Internals Cookbook Part 2 - GC-related things파일 다운로드1
11868정성태4/15/20191090.NET Framework: 815. CER(Constrained Execution Region)이란?파일 다운로드1
11867정성태4/15/20191123.NET Framework: 814. Critical Finalizer와 SafeHandle의 사용 의미파일 다운로드1
11866정성태4/9/20192298Windows: 159. 네트워크 공유 폴더(net use)에 대한 인증 정보는 언제까지 유효할까요?
11865정성태4/9/20191126오류 유형: 529. 제어판 - C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools is not accessible.
11864정성태4/9/20191273오류 유형: 528. '...' could be '0': this does not adhere to the specification for the function '...'
11863정성태4/9/20191464디버깅 기술: 127. windbg - .NET x64 EXE의 EntryPoint
11862정성태4/7/20191324개발 환경 구성: 437. .NET EXE의 ASLR 기능을 끄는 방법
11861정성태4/6/20191444디버깅 기술: 126. windbg - .NET x86 CLR2/CLR4 EXE의 EntryPoint
11860정성태4/5/20192223오류 유형: 527. Visual C++ 컴파일 오류 - error C2220: warning treated as error - no 'object' file generated
11859정성태4/4/20191669디버깅 기술: 125. WinDbg로 EXE의 EntryPoint에서 BP 거는 방법
11858정성태3/27/20191485VC++: 129. EXE를 LoadLibrary로 로딩해 PE 헤더에 있는 EntryPoint를 직접 호출하는 방법파일 다운로드1
11857정성태3/26/20191646VC++: 128. strncpy 사용 시 주의 사항(Linux / Windows)
11856정성태3/25/20191383VS.NET IDE: 134. 마이크로소프트의 CoreCLR 프로파일러 리눅스 예제를 Visual Studio F5 원격 디버깅하는 방법 [1]파일 다운로드1
11855정성태3/25/20191970개발 환경 구성: 436. 페이스북 HTTPS 인증을 localhost에서 테스트하는 방법
11854정성태3/25/20191027VS.NET IDE: 133. IIS Express로 호스팅하는 사이트를 https로 접근하는 방법
11853정성태3/24/20191375개발 환경 구성: 435. 존재하지 않는 IP 주소에 대한 Dns.GetHostByAddress/gethostbyaddr/GetNameInfoW 실행이 느리다면? - 두 번째 이야기
11852정성태3/20/20191447개발 환경 구성: 434. 존재하지 않는 IP 주소에 대한 Dns.GetHostByAddress/gethostbyaddr/GetNameInfoW 실행이 느리다면?파일 다운로드1
11851정성태3/19/20191720Linux: 8. C# - 리눅스 환경에서 DllImport 대신 라이브러리 동적 로드 처리
11850정성태3/18/20191252.NET Framework: 813. C# async 메서드에서 out/ref/in 유형의 인자를 사용하지 못하는 이유
11849정성태3/18/20191862.NET Framework: 812. pscp.exe 기능을 C#으로 제어하는 방법파일 다운로드1
11848정성태3/17/20191148스크립트: 14. 윈도우 CMD - 파일이 변경된 경우 파일명을 변경해 복사하고 싶다면?
1  2  3  4  5  6  7  8  9  10  11  12  13  14  [15]  ...