디버깅 이벤트

디버깅 이벤트는 시스템이 디버거에 알리도록 하는 디버깅 중인 프로세스의 인시던트입니다. 디버깅 이벤트에는 프로세스 만들기, 스레드 만들기, DLL(동적 연결 라이브러리 로드), DLL 언로드, 출력 문자열 보내기 및 예외 생성이 포함됩니다.

디버거가 대기하는 동안 디버깅 이벤트가 발생하는 경우 시스템은 WaitForDebugEvent에 의해 지정된 DEBUG_EVENT 구조체를 이벤트를 설명하는 정보로 채웁니다.

시스템에서 디버깅 이벤트를 디버거에 알릴 때 영향을 받는 프로세스의 모든 스레드도 일시 중단합니다. 스레드는 디버거가 ContinueDebugEvent를 사용하여 디버깅 이벤트를 계속할 때까지 실행을 다시 시작하지 않습니다. 프로세스를 디버그하는 동안 다음과 같은 디버깅 이벤트가 발생할 수 있습니다.

디버깅 이벤트 설명
CREATE_PROCESS_DEBUG_EVENT
디버그 중인 프로세스에서 새 프로세스가 만들어지거나 디버거가 이미 활성 프로세스의 디버깅을 시작할 때마다 생성됩니다. 시스템은 프로세스가 사용자 모드에서 실행되기 전과 시스템에서 새 프로세스에 대한 다른 디버깅 이벤트를 생성하기 전에 이 디버깅 이벤트를 생성합니다.
DEBUG_EVENT 구조체에는 CREATE_PROCESS_DEBUG_INFO 구조체가 포함됩니다. 이 구조체에는 새 프로세스에 대한 핸들, 프로세스의 이미지 파일에 대한 핸들, 프로세스의 초기 스레드에 대한 핸들 및 새 프로세스를 설명하는 기타 정보가 포함됩니다.
프로세스에 대한 핸들에는 PROCESS_VM_READ 및 PROCESS_VM_WRITE 액세스 권한이 있습니다. 디버거에 스레드에 대한 이러한 유형의 액세스 권한이 있는 경우 ReadProcessMemoryWriteProcessMemory 함수를 사용하여 프로세스의 메모리를 읽고 쓸 수 있습니다. 시스템은 이전에 EXIT_PROCESS_DEBUG_EVENT 이벤트를 보고한 경우 디버거가 ContinueDebugEvent 함수를 호출할 때 이 핸들을 닫습니다.
프로세스의 이미지 파일에 대한 핸들은 GENERIC_READ 액세스 권한이 있으며 읽기 공유를 위해 열립니다. 디버거는 CREATE_PROCESS_DEBUG_EVENT를 처리하는 동안 이 핸들을 닫아야 합니다.
프로세스의 초기 스레드에 대한 핸들에는 스레드에 대한 THREAD_GET_CONTEXT, THREAD_SET_CONTEXT 및 THREAD_SUSPEND_RESUME 액세스 권한이 있습니다. 디버거가 이러한 유형의 스레드에 액세스할 수 있는 경우 GetThreadContextSetThreadContext 함수를 사용하여 스레드의 레지스터에서 읽고 쓸 수 있으며 SuspendThreadResumeThread 함수를 사용하여 스레드를 일시 중단하고 다시 시작할 수 있습니다. 시스템은 이전에 EXIT_PROCESS_DEBUG_EVENT 이벤트를 보고한 경우 디버거가 ContinueDebugEvent 함수를 호출할 때 이 핸들을 닫습니다.
CREATE_THREAD_DEBUG_EVENT
디버그 중인 프로세스에서 새 스레드가 만들어지거나 디버거가 이미 활성 프로세스의 디버깅을 시작할 때마다 생성됩니다. 이 디버깅 이벤트는 새 스레드가 사용자 모드에서 실행되기 전에 생성됩니다.
DEBUG_EVENT 구조체에는 CREATE_THREAD_DEBUG_INFO 구조체가 포함됩니다. 이 구조체에는 새 스레드에 대한 핸들과 스레드의 시작 주소가 포함됩니다. 핸들에는 스레드에 대한 THREAD_GET_CONTEXT, THREAD_SET_CONTEXT 및 THREAD_SUSPEND_RESUME 액세스 권한이 있습니다. 디버거가 이러한 유형의 스레드에 액세스할 수 있는 경우 GetThreadContextSetThreadContext 함수를 사용하여 스레드의 레지스터에서 읽고 쓸 수 있으며 SuspendThreadResumeThread 함수를 사용하여 스레드를 일시 중단하고 다시 시작할 수 있습니다.
시스템에서 이전에 EXIT_THREAD_DEBUG_EVENT 이벤트를 보고한 경우 디버거가 ContinueDebugEvent 함수를 호출할 때 시스템은 새 스레드에 대한 핸들을 닫습니다.
EXCEPTION_DEBUG_EVENT
디버그 중인 프로세스에서 예외가 발생할 때마다 생성됩니다. 가능한 예외에는 액세스할 수 없는 메모리 액세스 시도, 중단점 명령 실행, 0으로 나누기 시도 또는 구조적 예외 처리에 기록된 기타 예외가 포함됩니다.
DEBUG_EVENT 구조체에는 EXCEPTION_DEBUG_INFO 구조체가 포함됩니다. 이 구조체는 디버깅 이벤트를 발생시킨 예외를 설명합니다.
표준 예외 조건 외에도 콘솔 프로세스 디버깅 중에 추가 예외 코드가 발생할 수 있습니다. Ctrl+C가 Ctrl+C 신호를 처리하고 디버그되는 콘솔 프로세스에 입력될 때 시스템에서 DBG_CONTROL_C 예외 코드를 생성합니다. 이 예외 코드는 애플리케이션에서 처리할 수 없습니다. 애플리케이션은 이 예외 코드를 처리하기 위해 예외 처리기를 사용하면 안 됩니다. 이 예외 코드는 디버거의 이점을 위해서만 발생하며 디버거가 콘솔 프로세스에 연결된 경우에만 사용됩니다.
프로세스가 디버그되지 않거나 디버거가 처리되지 않은 DBG_CONTROL_C 예외를 전달하는 경우(gn 명령을 통해) SetConsoleCtrlHandler 함수에 설명된 대로 애플리케이션의 처리기 함수 목록이 검색됩니다.
디버거가 gh 명령을 통해 DBG_CONTROL_C 예외를 처리하는 경우 애플리케이션은 이와 같은 코드가 없다면 Ctrl+C를 알 수 없습니다.
while ((inputChar = getchar()) != EOF) ...
따라서 디버거를 사용하여 이러한 코드의 읽기 대기가 종료되지 않도록 할 수 없습니다.
EXIT_PROCESS_DEBUG_EVENT
디버그 중인 프로세스의 마지막 스레드가 종료될 때마다 생성됩니다. 이 디버깅 이벤트는 시스템이 프로세스의 DLL을 언로드하고 프로세스의 종료 코드를 업데이트한 직후에 발생합니다.
DEBUG_EVENT 구조체에는 종료 코드를 지정하는 EXIT_PROCESS_DEBUG_INFO 구조체가 포함되어 있습니다.
디버거는 이 디버깅 이벤트를 수신할 때 프로세스와 연결된 내부 구조를 할당 취소합니다. 시스템은 종료 프로세스 및 프로세스의 모든 스레드에 대한 디버거의 핸들을 닫습니다. 디버거는 이러한 핸들을 닫아서는 안 됩니다.
이 이벤트를 수신하는 디버거가 ContinueDebugEvent를 호출할 때까지 프로세스 종료의 커널 모드 부분을 완료할 수 없습니다. 그때까지 프로세스 핸들이 열려 있고 가상 주소 공간이 해제되지 않으므로 디버거가 자식 프로세스를 검사할 수 있습니다. 프로세스 종료의 커널 모드 부분이 완료될 때 알림을 받으려면 CREATE_PROCESS_DEBUG_EVENT로 반환된 핸들을 복제하고 ContinueDebugEvent를 호출한 다음, 중복된 프로세스 핸들이 신호를 받을 때까지 기다립니다.
EXIT_THREAD_DEBUG_EVENT
디버그 중인 프로세스의 일부인 스레드가 종료될 때마다 생성됩니다. 시스템은 스레드의 종료 코드를 업데이트한 직후 이 디버깅 이벤트를 생성합니다.
DEBUG_EVENT 구조체에는 종료 코드를 지정하는 EXIT_THREAD_DEBUG_INFO 구조체가 포함되어 있습니다.
이 디버깅 이벤트는 종료 스레드가 프로세스의 마지막 스레드인 경우 발생하지 않습니다. 이 경우 EXIT_PROCESS_DEBUG_EVENT 디버깅 이벤트가 대신 발생합니다.
디버거는 이 디버깅 이벤트를 수신할 때 스레드와 연결된 내부 구조를 할당 취소합니다. 시스템은 종료 스레드에 대한 디버거의 핸들을 닫습니다. 디버거는 이 핸들을 닫아서는 안 됩니다.
LOAD_DLL_DEBUG_EVENT
디버그 중인 프로세스가 DLL을 로드할 때마다 생성됩니다. 이 디버깅 이벤트는 시스템 로더가 DLL에 대한 링크를 확인하거나 디버그된 프로세스가 LoadLibrary 함수를 사용하는 경우에 발생합니다. 이 디버깅 이벤트는 시스템이 프로세스의 가상 주소 공간에 DLL을 처음 연결할 때만 발생합니다.
DEBUG_EVENT 구조체에는 LOAD_DLL_DEBUG_INFO 구조체가 포함됩니다. 이 구조체에는 새로 로드된 DLL에 대한 핸들, DLL의 기본 주소 및 DLL을 설명하는 기타 정보가 포함됩니다. 디버거는 LOAD_DLL_DEBUG_EVENT를 처리하는 동안 DLL 핸들에 대한 핸들을 닫아야 합니다.
일반적으로 디버거는 이 디버깅 이벤트를 수신할 때 DLL과 연결된 기호 테이블을 로드합니다.
OUTPUT_DEBUG_STRING_EVENT
디버그 중인 프로세스가 다음을 사용하는 경우 생성됩니다.
OutputDebugString 함수. DEBUG_EVENT 구조체에는 OUTPUT_DEBUG_STRING_INFO 구조체가 포함됩니다. 이 구조체는 디버깅 문자열의 주소, 길이 및 형식을 지정합니다.
UNLOAD_DLL_DEBUG_EVENT
디버그 중인 프로세스가 FreeLibrary 함수를 사용하여 DLL을 언로드할 때마다 생성됩니다. 이 디버깅 이벤트는 프로세스의 주소 공간에서 DLL을 마지막으로 언로드할 때만 발생합니다(즉, DLL의 사용 횟수가 0인 경우).
DEBUG_EVENT 구조체에는 UNLOAD_DLL_DEBUG_INFO 구조체가 포함됩니다. 이 구조체는 DLL을 언로드하는 프로세스의 주소 공간에서 DLL의 기본 주소를 지정합니다.
일반적으로 디버거는 이 디버깅 이벤트를 수신할 때 DLL과 연결된 기호 테이블을 언로드합니다.
프로세스가 종료되면 시스템은 프로세스의 DLL을 자동으로 언로드하지만 UNLOAD_DLL_DEBUG_EVENT 디버깅 이벤트를 생성하지는 않습니다.
RIP_EVENT
디버그 중인 프로세스가 시스템 디버거의 제어 외부에서 종료될 때마다 생성됩니다.
DEBUG_EVENT 구조체에는 RIP_INFO 구조체가 포함됩니다. 이 구조체는 오류 및 오류 유형을 지정합니다.