다음을 통해 공유


.jdinfo(JIT_DEBUG_INFO 사용)

.jdinfo 명령은 JIT(Just-In-Time) 디버깅에 대한 예외 및 컨텍스트의 원본으로 JIT_DEBUG_INFO 구조를 사용합니다. 구조체에 대한 주소는 AeDebug 레지스트리 항목에 지정된 %p 매개 변수를 사용하여 .jdinfo 명령에 전달됩니다.

사용되는 레지스트리 키에 대한 자세한 내용은 Postmortem 디버깅 사용을 참조하세요. 레지스터 컨텍스트에 대한 자세한 내용은 컨텍스트 변경을 참조하세요.

.jdinfo Address 

매개 변수

주소
JIT_DEBUG_INFO 구조체의 주소를 지정합니다. 구조체에 대한 주소는 AeDebug 레지스트리 항목에 지정된 %p 매개 변수를 사용하여 .jdinfo 명령에 전달됩니다.

Environment

모드

사용자 모드

대상

라이브, 크래시 덤프

플랫폼

모두

예제

이 예제에서는 WinDbg를 사용하도록 AeDebug 레지스트리 항목을 구성하는 방법을 JIT 디버거로 사용할 수 있습니다.

Debugger = "Path\WinDbg.EXE -p %ld -e %ld -c ".jdinfo 0x%p"

그런 다음 크래시가 발생하면 구성된 JIT 디버거가 호출되고 %p 매개 변수를 사용하여 디버거가 시작된 후 실행되는 .jdinfo 명령에 JIT_DEBUG_INFO 구조체의 주소를 전달합니다.

nMicrosoft (R) Windows Debugger Version 10.0.10240.9 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

*** wait with pending attach
Executable search path is: 
...
ModLoad: 00000000`68a20000 00000000`68ac3000   C:\WINDOWS\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9247_none_08e394a1a83e212f\MSVCR90.dll
(153c.5d0): Break instruction exception - code 80000003 (first chance)
Processing initial command '.jdinfo 0x00000000003E0000'
ntdll!DbgBreakPoint:
00007ffc`81a986a0 cc              int     3
0:003> .jdinfo 0x00000000003E0000
----- Exception occurred on thread 0:15c8
ntdll!ZwWaitForMultipleObjects+0x14:
00007ffc`81a959a4 c3              ret

----- Exception record at 00000000`003e0028:
ExceptionAddress: 00007ff791d81014 (CrashAV_x64!wmain+0x0000000000000014)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000001
   Parameter[1]: 0000000000000000
Attempt to write to address 0000000000000000

----- Context record at 00000000`003e00c0:
rax=0000000000000000 rbx=0000000000000000 rcx=00007ffc81a954d4
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000001
rip=00007ff791d81014 rsp=00000000006ff8b0 rbp=0000000000000000
 r8=00000000006ff808  r9=0000000000000000 r10=0000000000000000
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
CrashAV_x64!wmain+0x14:
00007ff7`91d81014 45891b          mov     dword ptr [r11],r11d ds:00000000`00000000=????????

설명

.jdinfo 명령은 Windows Vista에 도입된 AeDebug 레지스트리 정보를 사용합니다. 사용되는 레지스트리 키에 대한 자세한 내용은 Postmortem 디버깅 사용을 참조하세요. .jdinfo 명령은 시스템이 AeDebug에 대해 설정한 JIT_DEBUG_INFO 주소를 사용하고 컨텍스트를 크래시가 발생한 예외로 설정합니다.

AeDebug에서 -g 대신 .jdinfo 명령을 사용하여 실행 없이 디버거를 AeDebug 상태로 설정할 수 있습니다.

일반적인 조건에서 사용자 모드 예외가 발생할 때 다음 시퀀스가 발생하기 때문에 이 상태가 유리할 수 있습니다.

  1. Microsoft Windows 운영 체제는 애플리케이션 실행을 중지합니다.

  2. 사후 관리 디버거가 시작됩니다.

  3. 디버거는 애플리케이션에 연결됩니다.

  4. 디버거는 "Go" 명령을 실행합니다. (이 명령은 AeDebug 키의 -g에 의해 발생합니다.)

  5. 대상은 실행을 시도하며 동일한 예외가 발생할 수도 있고 그렇지 않을 수도 있습니다.

  6. 이 예외는 디버거에 침입합니다.

이러한 이벤트로 인해 발생할 수 있는 몇 가지 문제가 있습니다.

  • 예외가 다시 시작될 때 더 이상 존재하지 않는 일시적인 조건으로 인해 예외가 항상 반복되는 것은 아닙니다.

  • 다른 예외와 같은 다른 이벤트가 발생할 수 있습니다. 원래 이벤트와 동일한지 여부를 알 수 있는 방법은 없습니다.

  • 디버거를 연결하려면 새 스레드를 삽입해야 하며, 스레드가 로더 잠금을 유지하는 경우 차단할 수 있습니다. 새 스레드를 삽입하는 것은 프로세스의 상당한 방해가 될 수 있습니다.

AeDebug 키에서 -g 대신 -c .jdinfo를 사용하는 경우 실행이 발생하지 않습니다. 대신 예외 정보는 %p 변수를 사용하여 JIT_DEBUG_INFO 구조에서 검색됩니다.

예를 들어 다음 AeDebug 키를 고려합니다.

ntsd -p %ld -e %ld -c ".jdinfo 0x%p"

다음 예제는 훨씬 덜 침습적입니다. -pv 스위치를 사용하면 디버거가 비침범적으로 연결되어 새 스레드가 대상에 삽입되지 않습니다.

ntsd -pv -p %ld -e %ld -c ".jdinfo 0x%p"

이 비침범성 옵션을 사용하는 경우 디버거를 종료해도 프로세스가 종료되지 않습니다. .kill(프로세스 종료) 명령을 사용하여 프로세스를 종료할 수 있습니다.

덤프 파일 디버깅에 이 값을 사용하려면 덤프 파일을 만들 때 .dump /j 를 사용하여 덤프 파일에 JIT_DEBUG_INFO 구조를 추가해야 합니다.

JIT_DEBUG_INFO 구조체는 다음과 같이 정의됩니다.

typedef struct _JIT_DEBUG_INFO {
    DWORD dwSize;
    DWORD dwProcessorArchitecture;
    DWORD dwThreadID;
    DWORD dwReserved0;
    ULONG64 lpExceptionAddress;
    ULONG64 lpExceptionRecord;
    ULONG64 lpContextRecord;
} JIT_DEBUG_INFO, *LPJIT_DEBUG_INFO;

dt 명령을 사용하여 JIT_DEBUG_INFO 구조를 표시할 수 있습니다.

0: kd> dt JIT_DEBUG_INFO
nt!JIT_DEBUG_INFO
   +0x000 dwSize           : Uint4B
   +0x004 dwProcessorArchitecture : Uint4B
   +0x008 dwThreadID       : Uint4B
  +0x00c dwReserved0      : Uint4B
   +0x010 lpExceptionAddress : Uint8B
   +0x018 lpExceptionRecord : Uint8B
   +0x020 lpContextRecord  : Uint8B

WinDbg를 사용하여 예외 레코드, 호출 스택 및 LastEvent 보기

.jdinfo 명령을 사용하여 컨텍스트를 실패 시점으로 설정한 후에는 아래와 같이 .jdinfo, 호출 스택 및 lastevent에서 반환된 예외 레코드를 보고 원인을 조사할 수 있습니다.

0:000> .jdinfo  0x00000000003E0000
----- Exception occurred on thread 0:15c8
ntdll!NtWaitForMultipleObjects+0x14:
00007ffc`81a959a4 c3              ret

----- Exception record at 00000000`003e0028:
ExceptionAddress: 00007ff791d81014 (CrashAV_x64!wmain+0x0000000000000014)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000001
   Parameter[1]: 0000000000000000
Attempt to write to address 0000000000000000
...

0:000> k
  *** Stack trace for last set context - .thread/.cxr resets it
# Child-SP          RetAddr           Call Site
00 00000000`006ff8b0 00007ff7`91d811d2 CrashAV_x64!wmain+0x14 [c:\my\my_projects\crash\crashav\crashav.cpp @ 14]
01 00000000`006ff8e0 00007ffc`7fa38364 CrashAV_x64!__tmainCRTStartup+0x11a [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crtexe.c @ 579]
02 00000000`006ff910 00007ffc`81a55e91 KERNEL32!BaseThreadInitThunk+0x14
03 00000000`006ff940 00000000`00000000 ntdll!RtlUserThreadStart+0x21

0:000> .lastevent
Last event: 153c.5d0: Break instruction exception - code 80000003 (first chance)
  debugger time: Thu Sep  8 12:55:08.968 2016 (UTC - 7:00)