사례 연구: ETW 및 Netmon을 사용하여 알 수 없는 USB 디바이스 문제 해결
이 항목에서는 USB ETW 및 Netmon을 사용하여 Windows에서 인식하지 못하는 USB 디바이스 문제를 해결하는 방법의 예를 제공합니다.
이 예제에서는 디바이스를 연결했고 장치 관리자 및 UI(사용자 인터페이스)의 다른 부분에서 알 수 없는 디바이스로 나타났습니다. 하드웨어 ID가 USB\UNKNOWN이었습니다. 더 진단하기 위해 디바이스를 분리하고 ETW 추적을 시작한 다음 디바이스에 다시 연결했습니다. 디바이스가 알 수 없는 디바이스로 나타난 후 추적을 중지했습니다.
알 수 없는 디바이스 문제 정보
알 수 없는 USB 디바이스 문제를 디버그하려면 사용자가 디바이스를 시스템에 연결할 때 USB 드라이버 스택이 디바이스를 열거하기 위해 수행하는 작업을 이해하는 데 도움이 됩니다. USB 열거형에 대한 자세한 내용은 USB 스택이 디바이스를 열거하는 방법이라는 블로그 게시물을 참조하세요.
일반적으로 USB 드라이버 스택이 디바이스를 열거하지 못하는 경우 허브 드라이버는 여전히 디바이스의 도착을 Windows에 보고하고 USB 디바이스는 장치 관리자 알 수 없는 디바이스로 표시됩니다. 디바이스에는 USB\VID_0000&PID_0000 디바이스 ID와 USB\UNKNOWN의 하드웨어 ID 및 호환 ID가 있습니다. 다음 이벤트로 인해 USB 허브 드라이버가 USB 디바이스를 알 수 없는 디바이스로 열거합니다.
- 열거 중에 포트 재설정 요청 시간이 초과되었습니다.
- USB 디바이스에 대한 주소 설정 요청이 실패했습니다.
- USB 디바이스의 디바이스 설명자에 대한 요청이 실패했습니다.
- USB 디바이스 설명자가 형식이 잘못되어 유효성 검사에 실패했습니다.
- 구성 설명자에 대한 요청이 실패했습니다.
- USB 구성 설명자가 형식이 잘못되어 유효성 검사에 실패했습니다.
Windows 7에서 열거에 실패한 알 수 없는 디바이스는 장치 관리자 오류 코드 43으로 표시됩니다.
장치 관리자 디바이스에 오류 코드 28이 표시되면 디바이스가 성공적으로 열거되었지만 여전히 알 수 없는 디바이스입니다. 이 오류 코드는 디바이스가 열거 중에 제품 ID 문자열을 제공하지 않았고 Windows가 드라이버를 설치할 디바이스에 일치하는 INF를 찾을 수 없음을 나타냅니다.
이벤트 추적 분석 시작
디바이스 오류이므로 USB 파서와 함께 Netmon을 사용하여 로그 파일을 분석하는 것이 좋습니다.
이벤트 추적 로그를 보려면
Netmon을 실행하고 파일 -> 열기 -> 캡처를 클릭한 다음 파일을 선택합니다.
SystemTrace 설명이 있는 프레임 요약 창에서 첫 번째 이벤트를 선택합니다. 이 이미지는 첫 번째 이벤트를 선택할 때 화면의 모양을 보여줍니다.
Netmon이 표시하는 열을 사용자 지정하려면 열 이름을 마우스 오른쪽 단추로 클릭하고 열 선택을 선택합니다.
SystemTrace 형식으로 식별되는 첫 번째 이벤트에는 로그에 대한 일반 정보가 포함됩니다. 프레임 세부 정보 창에서 정보 트리를 확장하여 손실된 이벤트 수 및 추적 시작 시간과 같은 정보를 볼 수 있습니다.
USB 디바이스 요약 이벤트
이벤트 2는 로그의 첫 번째 USB 이벤트입니다. 이 이벤트와 몇 가지 후속 이벤트는 추적을 시작할 때 시스템에 연결된 USB 호스트 컨트롤러, 허브 및 디바이스에 대해 설명합니다. 이 이벤트 그룹을 디바이스 요약 이벤트 또는 요약 이벤트라고 할 수 있습니다. 첫 번째 이벤트와 마찬가지로 요약 이벤트는 드라이버 활동을 설명하지 않습니다. 요약 이벤트는 로깅 세션 시작 시 디바이스의 상태를 기록합니다. 다른 이벤트는 버스에서 발생하는 일, 클라이언트 드라이버 또는 시스템과의 상호 작용 또는 내부 상태 변경을 나타냅니다.
USB 허브와 USB 포트 드라이버는 모두 요약 이벤트를 기록합니다. 이벤트를 기록한 드라이버는 프로토콜 이름 열에서 식별됩니다. 예를 들어 USB 포트 드라이버에 의해 기록되는 이벤트에는 USBPort_MicrosoftWindowsUSBPORT 프로토콜 이름이 있습니다. USB 이벤트 추적에는 일반적으로 포트 요약 이벤트 시퀀스, 허브 요약 이벤트 시퀀스가 포함됩니다. 대부분의 USB 포트 및 USB 허브 요약 이벤트에는 설명에 "정보" 또는 "특성"이라는 단어가 있습니다.
요약 이벤트의 끝을 어떻게 식별할 수 있나요? 로그 시작 시 USB 허브 이벤트 간에 타임스탬프 패턴에 상당한 중단이 있는 경우 해당 중단은 아마도 디바이스 요약의 끝일 수 있습니다. 그렇지 않으면 USB 허브 이벤트 이후의 첫 번째 USB 포트 이벤트는 요약이 아닌 첫 번째 이벤트일 수 있습니다. 다음 페이지의 그림 3에서는 이 샘플 추적의 첫 번째 요약이 아닌 이벤트를 보여 있습니다.
이 예제에서는 추적을 시작할 때 관심 있는 디바이스가 시스템에 연결되지 않았으므로 지금은 디바이스 요약 이벤트를 건너뛸 수 있습니다.
이벤트 설명 및 데이터 페이로드
샘플 로그에서 디바이스 요약 이벤트 이후의 첫 번째 이벤트는 USB Hub Wait Wake IRP Completed 이벤트입니다. 디바이스에 연결했고 호스트 컨트롤러 또는 허브가 응답에서 해제되었습니다. 해제되는 구성 요소를 확인하려면 이벤트의 데이터를 확인합니다. 데이터는 대략 다음 형식의 트리 구조에 표시되는 프레임 세부 정보 창에 있습니다.
Frame information
ETW event header information
ETW event descriptor (Constant information about the event ID such
as error level)
Event payload (Data logged at the time of the event)
Name of a USB-specific structure
Structure members and their values (Types: numbers, strings,
or arrays)
...
USB Hub Wait Wake IRP Completed 이벤트에 대한 페이로드 데이터를 확장하면 이름이 fid_USBHUB_Hub ETW 구조가 표시됩니다. 구조체의 이름에는 다음과 같은 구성 요소가 있습니다.
용어 | Description |
---|---|
Fid_ | USB ETW 구조에 대한 일반적인 접두사입니다. |
USBHUB_ | USB 허브 드라이버가 이벤트를 기록했음을 나타냅니다. |
문자열의 나머지 부분 | 구조체의 데이터가 설명하는 개체의 이름입니다. 이 이벤트의 경우 허브 개체입니다. |
USB 허브 드라이버는 fid_USBHUB_Hub 구조를 사용하여 USB 허브를 설명합니다. 데이터 페이로드에 이 허브 구조가 있는 이벤트는 허브를 참조하며 구조체의 내용을 사용하여 특정 허브를 식별할 수 있습니다. 그림 4는 프레임 세부 정보 창을 보여 줍니다. fid_USBHUB_Hub 구조체가 확장되어 필드가 표시됩니다.
허브 구조는 USB ETW 이벤트:fid_USBHUB_Device 및 fid_USBPORT_Device 일반적으로 나타나는 두 개의 다른 구조와 매우 유사합니다. 다음 중요한 필드는 세 가지 구조 모두에 공통적으로 적용됩니다.
필드 | Description |
---|---|
fid_idVendor | 디바이스의 USB 공급업체 ID(VID) |
fid_idProduct | 디바이스의 USB PID(제품 ID) |
fid_PortPath | USB 디바이스가 연결된 하나의 기반 허브 포트 번호 목록입니다. 목록의 포트 번호 수는 PortPathDepth 필드에 포함됩니다. 루트 허브 디바이스의 경우 이 목록은 모두 0입니다. 루트 허브 포트에 직접 연결된 USB 디바이스의 경우 PortPath[0]의 값은 디바이스가 연결된 포트의 루트 허브 포트 번호입니다. |
하나 이상의 추가 USB 허브를 통해 연결된 USB 디바이스의 경우 허브 포트 번호 목록은 루트 허브 포트에서 시작하여 루트 허브와의 거리 순서대로 추가 허브로 계속됩니다. 0을 무시합니다. 예를 들면 다음과 같습니다.
샘플 값 | 설명 |
---|---|
[0, 0, 0, 0, 0, 0] | 이벤트는 루트 허브(USB 호스트 컨트롤러에서 직접 제어되는 PC의 포트)를 나타냅니다. |
[3, 0, 0, 0, 0, 0] | 이벤트는 루트 허브의 포트 번호 3에 연결된 허브 또는 디바이스를 나타냅니다. |
[3, 1, 0, 0, 0, 0] | 허브는 루트 허브의 포트 3에 연결됩니다. 이벤트는 이 외부 허브의 포트 1에 연결된 허브 또는 디바이스를 나타냅니다. |
관심 있는 디바이스의 포트 경로를 모니터링해야 합니다. 디바이스가 열거되면 VID 및 PID를 알 수 없으며 0으로 기록됩니다. 초기화 및 일시 중단과 같은 일부 하위 수준 디바이스 요청 중에는 VID 및 PID가 표시되지 않습니다. 이러한 요청은 디바이스가 연결된 허브로 전송됩니다.
샘플 로그에서 Wait Wake 완료 이벤트에는 0이 6개인 포트 경로가 있습니다. 이벤트는 루트 허브에서 대기 절전 모드 해제 작업을 나타냅니다. 이는 논리적인 작업입니다. 디바이스를 루트 허브 포트에 연결했으므로 루트 허브가 절전 모드에서 해제됩니다.
USB Netmon 필터
시간이 있는 경우 로그에서 각 이벤트를 시간순으로 검사할 수 있습니다. 경험이 있더라도 이벤트 설명 목록을 검사하여 중요한 이벤트를 신속하게 식별하기가 어렵습니다. 알 수 없는 디바이스의 원인을 더 빠르게 찾으려면 Netmon 필터 기능을 사용할 수 있습니다.
USB 오류 필터
Netmon에서 USB 오류 필터를 활성화하려면 필터 - 디스플레이 필터 -> 부하 필터 -> 표준 필터 -> USB ->> USB 허브 오류를 클릭한 다음 디스플레이 필터 창에서 적용을 클릭합니다.
USB 오류 필터는 다음 표에 표시된 조건을 충족하는 이벤트 목록만 좁혀집니다.
텍스트 필터링 | Description |
---|---|
(USBPort_MicrosoftWindowsUSBUSBPORT AND NetEvent.Header.Descriptor.Opcode == 34) | opcode 34가 있는 USB 포트 이벤트는 포트 오류입니다. |
(USBHub_MicrosoftWindowsUSBUSBHUB AND NetEvent.Header.Descriptor.Opcode == 11) | opcode 11이 있는 USB 허브 이벤트는 허브 오류입니다. |
(NetEvent.Header.Descriptor.Level == 0x2) | 수준 0x2 있는 이벤트는 일반적으로 오류입니다. |
(USBHub_MicrosoftWindowsUSBUSBHUB AND NetEvent.Header.Descriptor.Id == 210) | ID가 210인 USB 허브 이벤트는 "USB 허브 예외 기록" 이벤트입니다. 자세한 내용은 오류 이벤트 및 상태 코드 이해를 참조하세요. |
이 이미지는 샘플 추적 로그에 USB 오류 필터를 적용한 후 프레임 요약 창에 표시되는 더 작은 이벤트 집합을 보여 줍니다.
오류 시퀀스에 대한 개요를 보려면 각 오류 이벤트를 간략하게 볼 수 있습니다. 관찰할 중요한 필드에는 fid_NtStatus, fid_UsbdStatus 및 fid_DebugText 포함됩니다. 자세한 내용은 오류 이벤트 및 상태 코드 이해를 참조하세요. 필터를 끄려면 필터 표시 창에서 제거 단추를 클릭합니다.
사용자 지정 Netmon 필터
Netmon에서 사용자 지정 필터를 만들 수 있습니다. 가장 쉬운 방법은 다음 방법 중 하나로 화면의 데이터에서 필터를 만드는 것입니다.
- 프레임 세부 정보 창에서 필드를 마우스 오른쪽 단추로 클릭하고 선택한 값 추가를 선택하여 필터를 표시합니다.
- 프레임 요약 창에서 필드를 마우스 오른쪽 단추로 클릭하고 필터 표시에 [필드 이름] 추가를 선택합니다.
연산자(예: OR, AND 및 ==)와 필터 값을 변경하여 적절한 필터 식을 작성할 수 있습니다.
오류 이벤트 및 상태 코드 이해
알 수 없는 디바이스 예제에서 대부분의 USB 허브 예외에는 CreateDeviceFailure의 fid_DebugText 데이터가 있습니다. 예외가 얼마나 심각한지는 명확하지 않지만 디버그 텍스트는 원인에 대한 힌트를 제공합니다. 새 디바이스와 관련된 작업이 실패했습니다. 지금은 인접한 디바이스 만들기 실패 이벤트가 중복된다고 가정합니다. 마지막 두 가지 예외는 CreateDeviceFailure_Popup GenErr_UserIoctlFailed. 팝업 예외는 사용자에게 노출된 오류처럼 들리지만 이러한 모든 오류는 알 수 없는 디바이스 문제와 관련이 있을 수 있습니다.
USB 오류 이벤트 및 기타 이벤트에는 문제에 대한 중요한 정보를 제공하는 데이터에 상태 값이 있습니다. 다음 표의 리소스를 사용하여 상태 값에 대한 정보를 찾을 수 있습니다.
상태 유형 | 리소스 |
---|---|
fid_NtStatus | NTSTATUS 값을 참조하세요. |
URB(USB 요청 블록) 또는 fid_UsbdStatus 상태 필드 | 값을 WDK(Windows 드라이버 키트)에서 inc\api\usb.h의 USBD_STATUS 조회합니다. USBD_STATUS 사용할 수도 있습니다. 이 항목에서는 기호화된 이름과 USBD_STATUS 값의 의미를 나열합니다. |
문제 이벤트에서 뒤로 읽기
오류 이벤트 전에 기록된 이벤트는 오류의 원인에 대한 중요한 단서를 제공할 수 있습니다. 알 수 없는 디바이스의 근본 원인을 확인하려면 오류 전에 기록된 이벤트를 확인해야 합니다. 이 예제에서는 두 번째에서 마지막 예외인 CreateDeviceFailure_Popup 이벤트에서 뒤로 살펴보기 시작합니다. USB 오류 필터를 사용하는 동안 이 이벤트를 선택한 다음 디스플레이 필터 창에서 제거를 클릭합니다. USB 오류 필터는 디스플레이 필터 창에 계속 표시되며 나중에 다시 적용할 수 있습니다. 그러나 이제 필터가 비활성화되고 프레임 요약 창에 이 이미지와 같이 모든 이벤트가 표시됩니다.
CreateDeviceFailure_Popup 이벤트 직전에 기록되는 두 이벤트는 디스패치 및 USB 컨트롤 전송 완료입니다. fid_USBPORT_Device 포트 경로 필드는 전송의 대상이 루트 허브임을 나타내는 두 이벤트에 대해 0입니다. 완료 이벤트의 fid_USBPORT_URB_CONTROL_TRANSFER 구조에서 상태 전송에 성공했음을 나타내는 0(USBD_STATUS_SUCCESS)입니다. 이전 이벤트를 계속 검사합니다.
다음 두 개의 이전 이벤트는 앞에서 살펴본 네 번째(최종) 디바이스 만들기 실패 이벤트와 네 번째(최종) CreateDeviceFailure 예외입니다.
다음 이전 이벤트는 엔드포인트 닫기입니다. 이 이벤트는 엔드포인트를 더 이상 사용할 수 없음을 의미합니다. 이벤트 데이터는 해당 디바이스의 디바이스와 엔드포인트를 모두 설명합니다. 디바이스 포트 경로는 [1, 0, 0, 0, 0, 0]입니다. 추적을 실행한 시스템에는 호스트 컨트롤러(루트 허브)와 연결 중인 디바이스만 있으므로 이 포트 경로는 허브를 설명하지 않습니다. 닫힌 엔드포인트는 연결한 단일 디바이스에 있어야 하며 이제 디바이스의 경로가 1임을 알 수 있습니다. 드라이버가 이전에 발생한 문제로 인해 디바이스의 엔드포인트에 액세스할 수 없게 만들었을 가능성이 높습니다. 이전 이벤트를 계속 검사합니다.
다음 이전 이벤트는 완료된 USB 제어 전송입니다. 이벤트 데이터는 전송 대상이 디바이스임을 보여 줍니다(포트 경로는 1). fid_USBPORT_Endpoint_Descriptor 구조는 엔드포인트의 주소가 0임을 나타내므로 USB 정의 기본 제어 엔드포인트입니다. URB 상태 0xC0000004. 상태 0이 아니므로 전송에 성공하지 못할 수 있습니다. 이 USBD_STATUS 값에 대한 자세한 내용은 usb.h 및 오류 이벤트 및 상태 코드 이해를 참조하세요.
#define USBD_STATUS_STALL_PID ((USBD_STATUS)0xC0000004L)
의미: 디바이스가 중단 패킷 식별자를 반환했습니다. 엔드포인트에서 어떤 요청이 중단되었나요? 이벤트에 대해 기록된 다른 데이터는 요청이 표준 디바이스 제어 요청임을 나타냅니다. 구문 분석된 요청은 다음과 같습니다.
Frame: Number = 184, Captured Frame Length = 252, MediaType = NetEvent
+ NetEvent:
- MicrosoftWindowsUSBUSBPORT: Complete Internal URB_FUNCTION_CONTROL_TRANSFER
- USBPORT_ETW_EVENT_COMPLETE_INTERNAL_URB_FUNCTION_CONTROL_TRANSFER: Complete Internal URB_FUNCTION_CONTROL_TRANSFER
+ fid_USBPORT_HC:
+ fid_USBPORT_Device:
+ fid_USBPORT_Endpoint:
+ fid_USBPORT_Endpoint_Descriptor:
+ fid_URB_Ptr: 0x84539008
- ControlTransfer:
+ Urb: Status = 0xc0000004, Flags 0x3, Length = 0
- SetupPacket: GET_DESCRIPTOR
+ bmRequestType: (Standard request) 0x80
bRequest: (6) GET_DESCRIPTOR
Value_DescriptorIndex: 0 (0x0)
Value_DescriptorType: (1) DEVICE
_wIndex: 0 (0x0)
wLength: 64 (0x40)
bRequest(GET_DESCRIPTOR)를 Value_DescriptorType(DEVICE)와 결합하면 요청이 get-device 설명자인지 확인할 수 있습니다.
USB 열거를 계속하려면 디바이스가 해당 디바이스 설명자로 이 요청에 응답해야 합니다. 대신 디바이스가 요청을 중단하여 열거형이 실패했습니다. 따라서 네 가지 디바이스 만들기 오류는 모두 디바이스 설명자에 대한 요청이 중단되어 발생했습니다. 디바이스 설명자에 대한 요청을 완료하지 않아 열거형이 실패하고 열거형이 실패하여 디바이스를 알 수 없음을 확인했습니다.