다음을 통해 공유


서비스 애플리케이션 디버그 준비

이 항목에서는 서비스 애플리케이션을 디버깅하기 전에 필요할 수 있는 모든 준비 단계를 나열합니다. 시나리오에서 필요한 단계는 선택한 연결 옵션과 선택한 디버깅 구성에 따라 달라집니다. 이러한 선택 항목 목록은 서비스 애플리케이션디버그하는 가장 좋은 방법 선택을 참조하세요.

이 항목에 설명된 각 준비 단계는 필요한 조건을 지정합니다. 이러한 단계는 순서에 따라 수행할 수 있습니다.

초기화 코드 디버깅 활성화

초기화 코드를 포함하여 실행 처음부터 서비스 애플리케이션을 디버그하려는 경우 이 준비 단계가 필요합니다.

다음 레지스트리 키를 찾거나 만듭니다. 여기서 ProgramName 서비스 애플리케이션의 실행 파일 이름입니다.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ProgramName 

ProgramName 파일 이름 확장명을 포함해야 하지만 경로는 포함하지 않아야 합니다. 예를 들어 ProgramName은 Myservice.exe 또는 Thisservice.dll일 수 있습니다.

이 레지스트리 키에서 디버거문자열 데이터 값을 만듭니다. 이 문자열의 값은 서비스 애플리케이션에 연결할 디버거의 전체 경로 및 파일 이름으로 설정해야 합니다.

  • 로컬로 디버그하려는 경우 다음과 같은 문자열을 사용합니다.

    c:\Debuggers\windbg.exe 
    

    Windows Vista 또는 이후 버전의 Windows를 실행하는 경우 이 옵션을 선택하지 마세요.

  • 원격 디버깅을 사용하려는 경우 -noio 옵션으로 NTSD를 지정합니다. 이렇게 하면 원격 연결을 통해서만 액세스할 수 있는 자체 콘솔 없이 NTSD가 실행됩니다. 예를 들어:

    c:\Debuggers\ntsd.exe -server ServerTransport -noio -y SymbolPath 
    

    Windows가 완전히 로드되기 전에 디버깅 세션이 시작되는 경우 원격 공유에서 기호에 액세스하지 못할 수 있습니다. 이 경우 로컬 기호를 사용해야 합니다. ServerTransport TCP 또는 NPIPE와 같은 사용자 모드 서비스와 상호 작용하지 않고 Windows 커널에 의해 구현되는 전송 프로토콜을 지정해야 합니다. ServerTransport의 구문에 대해서는 디버깅 서버활성화를 참조하세요.

  • 커널 모드 디버거에서 사용자 모드 디버거를 제어하려는 경우 -d 옵션을 사용하여 NTSD를 지정합니다. 예를 들어:

    c:\Debuggers\ntsd.exe -d -y SymbolPath 
    

    이 메서드를 사용하려는 경우 기호 서버에서 사용자 모드 기호에 액세스하려면 이 메서드를 원격 디버깅과 결합해야 합니다. 이 경우 -ddefer 옵션을 사용하여 NTSD를 지정합니다. TCP 또는 NPIPE와 같은 사용자 모드 서비스와 상호 작용하지 않고 Windows 커널에서 구현되는 전송 프로토콜을 선택합니다. 예를 들어:

    c:\Debuggers\ntsd.exe -server ServerTransport -ddefer -y SymbolPath 
    

    자세한 내용은 커널 디버거에서 User-Mode 디버거 제어를 참조하세요.

이 레지스트리 편집이 완료되면 이 이름의 서비스가 시작되거나 다시 시작될 때마다 디버거가 시작됩니다.

서비스 애플리케이션이 디버거에 침입할 수 있도록 설정

서비스 애플리케이션이 충돌하거나 예외가 발생할 때 디버거에 침입하도록 하려면 이 준비 단계가 필요합니다. 서비스 애플리케이션이 DebugBreak 함수를 호출하여 디버거에 침입하려는 경우에도 이 단계가 필요합니다.

참고 초기화 코드의 디버깅을 사용하도록 설정한 경우("초기화 코드 디버깅 사용" 하위 섹션에 설명된 단계) 이 단계를 건너뛰어야 합니다. 초기화 코드 디버깅을 사용하도록 설정하면 디버거가 시작되면 서비스 애플리케이션에 연결되므로 추가 준비 없이 모든 크래시, 예외 및 DebugBreak 대한 호출이 디버거로 라우팅됩니다.

이 준비 단계에는 선택한 디버거를 사후 디버거로 등록하는 작업이 포함됩니다. 이 작업은 디버거 명령줄에서 -iae 또는 -iaec 옵션을 사용하여 수행됩니다. 다음 명령을 사용하는 것이 좋지만, 이를 변경하려면 명령의 구문 세부 정보는 사후 디버깅 사용을 참조하세요.

  • 로컬로 디버그하려는 경우 다음과 같은 명령을 사용합니다.

    windbg -iae 
    

    Windows Vista 또는 이후 버전의 Windows를 실행하는 경우 이 옵션을 선택하지 마세요.

  • 원격 디버깅을 사용하려는 경우 -noio 옵션으로 NTSD를 지정합니다. 이렇게 하면 원격 연결을 통해서만 액세스할 수 있는 자체 콘솔 없이 NTSD가 실행됩니다. -server 매개 변수를 포함하는 사후 디버거를 설치하려면 레지스트리를 수동으로 편집해야 합니다. 자세한 내용은 사후 디버깅 사용을 참조하십시오. 예를 들어 AeDebug 키의 디버거 값은 다음과 같습니다.

    ntsd -server npipe:pipe=myproc%x -noio -p %ld -e %ld -g -y SymbolPath 
    

    파이프 사양에서 %x 토큰은 디버거를 시작하는 프로세스의 프로세스 ID로 바뀝니다. 이로 인해 둘 이상의 프로세스가 포스트모템 디버거를 시작하는 경우 각각에게 고유한 파이프 이름이 보장됩니다. Windows가 완전히 로드되기 전에 디버깅 세션이 시작되는 경우 원격 공유에서 기호에 액세스하지 못할 수 있습니다. 이 경우 로컬 기호를 사용해야 합니다. ServerTransport TCP 또는 NPIPE와 같은 사용자 모드 서비스와 상호 작용하지 않고 Windows 커널에 의해 구현되는 전송 프로토콜을 지정해야 합니다. ServerTransport구문에 대한 내용은 디버깅 서버활성화를 참조하십시오.

  • 커널 모드 디버거에서 사용자 모드 디버거를 제어하려는 경우 -d 옵션을 사용하여 NTSD를 지정합니다. 예를 들어:

    ntsd -iaec -d -y SymbolPath 
    

    이 메서드를 선택하고 기호 서버에서 사용자 모드 기호에 액세스하려는 경우 이 메서드를 원격 디버깅과 결합해야 합니다. 이 경우 -ddefer 옵션을 사용하여 NTSD를 지정합니다. TCP 또는 NPIPE와 같은 사용자 모드 서비스와 상호 작용하지 않고 Windows 커널에서 구현되는 전송 프로토콜을 선택합니다. -server 매개 변수를 포함하는 사후 디버깅 디버거를 설치하려면 레지스트리를 수동으로 편집해야 합니다. 자세한 내용은 사후 디버깅 사용 가능을(를) 참조하세요. 예를 들어 AeDebug 키의 디버거 값은 다음과 같습니다.

    ntsd -server npipe:pipe=myproc%x -ddefer -p %ld -e %ld -g -y SymbolPath 
    

    자세한 내용은 커널 디버거에서 User-Mode 디버거 제어를 참조하세요.

이러한 명령 중 하나를 실행하면 포스트모템 디버거가 등록됩니다. 이 디버거는 서비스 애플리케이션을 포함한 모든 사용자 모드 프로그램에서 예외가 발생하거나 DebugBreak 함수를 실행할 때마다 시작됩니다.

서비스 애플리케이션 시간 제한 조정

서비스가 시작되거나 예외가 발생할 때 디버거를 자동으로 시작하려는 경우 이 준비 단계가 필요합니다.

다음 레지스트리 키를 찾으세요.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

이 키 하단에서 ServicesPipeTimeout라는 이름으로 DWORD 데이터 값을 찾거나 만듭니다. 이 항목을 시간이 초과되기 전에 서비스가 대기할 시간(밀리초)으로 설정합니다. 예를 들어 값 60,000은 1분이고 86,400,000의 값은 24시간입니다. 이 레지스트리 값을 설정하지 않으면 기본 시간 제한은 약 30초입니다.

이 값의 중요성은 각 서비스가 시작될 때 클록이 실행되기 시작하고 시간 제한 값에 도달하면 서비스에 연결된 모든 디버거가 종료된다는 것입니다. 따라서 선택한 값은 서비스 시작과 디버깅 세션 완료 사이에 경과되는 총 시간보다 길어야 합니다.

이 설정은 레지스트리 편집이 완료된 후 시작되거나 다시 시작되는 모든 서비스에 적용됩니다. 일부 서비스가 충돌하거나 중단되고 이 설정이 계속 적용되는 경우 Windows에서 문제를 검색하지 않습니다. 따라서 디버깅하는 동안에만 이 설정을 사용하고 디버깅이 완료된 후 레지스트리 키를 원래 값으로 반환해야 합니다.

서비스를 격리하기

Svchost(단일 서비스 호스트) 프로세스에서 여러 서비스가 결합되는 경우도 있습니다. 이러한 서비스를 디버그하려면 먼저 별도의 Svchost 프로세스로 격리해야 합니다.

서비스를 격리할 수 있는 세 가지 방법이 있습니다. 다음과 같이 서비스를 자체 그룹 메서드로 이동하는 것이 좋습니다. 대체 메서드(서비스 유형 변경 및 SvcHost 이진 복제)는 디버깅을 위해 임시로 사용할 수 있지만 서비스가 실행되는 방식을 변경하기 때문에 첫 번째 메서드만큼 신뢰할 수 없습니다.

선호 방법: 서비스를 자체 그룹으로 이동

  1. 다음 Service Configuration 도구(Sc.exe) 명령을 실행합니다. 여기서 ServiceName 서비스의 이름입니다.

    sc qc ServiceName 
    

    서비스에 대한 현재 구성 값이 표시됩니다. 관심 있는 값은 서비스 제어 프로그램을 시작하기 위해 명령줄을 지정하는 BINARY_PATH_NAME입니다. 이 시나리오에서는 서비스가 아직 격리되지 않았기 때문에 이 명령줄에는 디렉터리 경로, Svchost.exe및 -k 스위치를 포함한 일부 SvcHost 매개 변수와 그룹 이름이 포함됩니다. 예를 들어 다음과 같이 표시할 수 있습니다.

    %SystemRoot%\System32\svchost.exe -k LocalServiceNoNetwork 
    

    이 경로와 그룹 이름을 기억하십시오. 5단계와 6단계에서 사용됩니다.

  2. 다음 레지스트리 키를 찾습니다.

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost 
    

    고유한 이름으로 새 REG_MULTI_SZ 값을 만듭니다(예: TempGrp).

  3. 이 새 값을 격리하려는 서비스의 이름과 동일하게 설정합니다. 디렉터리 경로 또는 파일 이름 확장명을 포함하지 마세요. 예를 들어 새 값 TempGrp을/를 MyService에 설정할 수 있습니다.

  4. 동일한 레지스트리 키 아래에 2단계에서 사용한 것과 동일한 이름의 새 키를 만듭니다. 예를 들어:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\TempGrp 
    

    이제 SvcHost 키에는 새 이름의 값이 포함되며 동일한 이름의 하위 키도 있습니다.

  5. 1단계에서 찾은 그룹과 이름이 같은 SvcHost 키에 대한 다른 키 하위 항목을 찾습니다. 이러한 키가 있는 경우 해당 키의 모든 값을 검사하고 4단계에서 만든 새 키에 중복 키를 만듭니다.

    예를 들어 이전 키의 이름은 다음과 같습니다.

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\LocalServiceNoNetwork 
    

    또한 CoInitializeSecurityParam, AuthenticationCapabilities및 기타 값과 같은 값을 포함할 수 있습니다. 새로 만든 키로 이동합니다.

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost\TempGrp 
    

    및 이름, 형식 및 데이터에서 이전 키의 값과 동일한 값을 만듭니다.

    이전 키가 없으면 새 키를 만들 필요가 없습니다.

  6. 다음 서비스 구성 도구 명령을 사용하여 1단계에서 찾은 경로를 수정합니다.

    sc config ServiceName binPath= "RevisedPath" 
    

    이 명령에서 ServiceName은 서비스의 이름이고, RevisedPath은 BINARY_PATH_NAME에 제공할 새 값입니다. RevisedPath경우 해당 줄에 표시된 모든 옵션을 포함하여 1단계에 표시된 것과 정확히 동일한 경로를 사용하여 한 가지 변경만 수행합니다. -k 스위치 다음에 있는 매개 변수를 2단계에서 만든 새 레지스트리 값의 이름으로 바꾸세요. RevisedPath을(를) 따옴표로 묶습니다. 등호 뒤의 공간이 필요합니다.

    예를 들어 명령은 다음과 같이 표시될 수 있습니다.

    sc config MyService binPath= "%SystemRoot%\System32\svchost.exe -k TempGrp" 
    

    sc qc 명령을 다시 사용하여 변경 내용을 검토할 수 있습니다.

이러한 설정은 다음에 서비스가 시작될 때 적용됩니다. 이전 서비스의 효과를 지우려면 서비스를 다시 시작하는 대신 Windows를 다시 시작하는 것이 좋습니다.

디버깅을 완료한 후 이 서비스를 공유 서비스 호스트로 반환하려면 sc config 명령을 다시 사용하여 이진 경로를 원래 값으로 반환하고 만든 새 레지스트리 키와 값을 삭제합니다.

대체 방법: 서비스 유형 변경

  1. 다음 Service Configuration 도구(Sc.exe) 명령을 실행합니다. 여기서 ServiceName 서비스의 이름입니다.

    sc config ServiceName type= own 
    

    등호(=) 기호 뒤에 공백이 필요합니다.

  2. 다음 명령을 사용하여 서비스를 다시 시작합니다.

    net stop ServiceName 
    net start ServiceName 
    

이 대안은 서비스의 동작을 변경할 수 있으므로 권장되는 방법이 아닙니다. 이 메서드를 사용하는 경우 다음 명령을 사용하여 디버깅을 완료한 후 일반 동작으로 되돌려 줍니다.

sc config ServiceName type= share 

대체 방법: SvcHost 바이너리 복제

  1. Svchost.exe 실행 파일은 Windows의 system32 디렉터리에 있습니다. 이 파일의 복사본을 만들어 이름을 svhost2.exe으로 지정한 후, 시스템32 디렉터리에 배치하세요.

  2. 다음 Service Configuration 도구(Sc.exe) 명령을 실행합니다. 여기서 ServiceName 서비스의 이름입니다.

    sc qc ServiceName 
    

    이 명령은 서비스에 대한 현재 구성 값을 표시합니다. BINARY_PATH_NAME은 서비스 제어 프로그램을 시작하는 데 사용되는 명령줄을 지정하는 값입니다. 이 시나리오에서는 서비스가 아직 격리되지 않았기 때문에 이 명령줄에는 디렉터리 경로, Svchost.exe및 일부 SvcHost 매개 변수가 포함됩니다. 예를 들어 다음과 같이 표시할 수 있습니다.

    %SystemRoot%\System32\svchost.exe -k LocalServiceNoNetwork 
    
  3. 이 경로를 수정하려면 다음 명령을 실행합니다.

    sc config ServiceName binPath= "RevisedPath" 
    

    이 명령에서 ServiceName은 서비스의 이름이며, RevisedPath은 BINARY_PATH_NAME에 제공하는 새 값입니다. RevisedPath의 경우, 2단계에 표시된 것과 정확히 동일한 경로를 사용하되, 해당 줄에 나열된 모든 옵션을 포함하고 오직 한 가지 변경만 하십시오: Svchost.exe를 Svchost2.exe으로 바꾸십시오. RevisedPath을 따옴표로 묶으세요. 등호 뒤의 공간이 필요합니다.

    예를 들어 명령은 다음과 같이 표시될 수 있습니다.

    sc config MyService binPath= "%SystemRoot%\System32\svchost2.exe -k LocalServiceNoNetwork" 
    

    sc qc 명령을 다시 사용하여 변경 내용을 검토할 수 있습니다.

  4. 다음 명령을 사용하여 서비스를 다시 시작합니다.

    net stop ServiceName 
    net start ServiceName 
    

이 대안은 서비스의 동작을 변경할 수 있으므로 권장되는 방법이 아닙니다. 이 메서드를 사용하는 경우 sc 구성 명령을 사용하여 디버깅을 완료한 후 경로를 원래 값으로 다시 변경합니다.