LINQ와 디버거 개체 사용

LINQ 구문을 디버거 개체와 함께 사용하여 데이터를 검색하고 조작할 수 있습니다. dx 명령과 함께 LINQ 구문을 사용하면 디버거 명령을 사용하는 것에 비해 더 일관된 환경을 사용할 수 있습니다. 출력 및 옵션은 보고 있는 디버거 개체에 관계없이 일관됩니다. LINQ 쿼리를 사용하면 "가장 많은 스레드를 실행하는 상위 5개 프로세스는 무엇인가요?"와 같은 질문을 할 수 있습니다.

디버거 개체는 "디버거"에 루트된 네임스페이스로 프로젝팅됩니다. 프로세스, 모듈, 스레드, 스택, 스택 프레임 및 지역 변수는 모두 LINQ 쿼리에서 사용할 수 있습니다.

LINQ는 개념적으로 데이터베이스를 쿼리하는 데 사용되는 SQL(구조적 쿼리 언어)과 비슷합니다. 여러 LINQ 메서드를 사용하여 디버그 데이터를 검색, 필터링 및 구문 분석할 수 있습니다. LINQ C# 메서드 구문이 사용됩니다. LINQ 및 LINQ C# 구문에 대한 자세한 내용은 C#에서 LINQ를 사용한 시작 참조하세요.

디버거 지원에서 사용되는 LINQ는 "쿼리 구문"이 아닌 LINQ의 "메서드 구문"을 사용합니다. LINQ의 차이점에 대한 자세한 내용을 확인할 수 있습니다 (언어 통합 쿼리).

다음과 같은 LINQ 명령을 디버거 개체와 함께 사용할 수 있습니다. 모든. Any, . 횟수. 첫 번째. 평평. Groupby. 마지막. Orderby. OrderByDescending, . 및 를 선택합니다. 어디. 이러한 메서드는 C# LINQ 메서드 양식을 최대한 가깝게 따릅니다.

네이티브 디버거 개체

네이티브 디버거 개체는 디버거 환경의 다양한 구문과 동작을 나타냅니다. 디버거 개체의 예는 다음과 같습니다.

  • 세션
  • 스레드/스레드
  • 프로세스/프로세스
  • 스택 프레임/스택 프레임
  • 지역 변수
  • 모듈/모듈
  • 유틸리티
  • 시스템 상태
  • 설정

NatVis를 사용하여 디버거 개체로 작업할 수도 있습니다. 자세한 내용은 NatVis의 네이티브 디버거 개체를 참조하세요. JavaScript에서 디버거 개체를 사용하는 방법에 대한 자세한 내용은 JavaScript 확장의 네이티브 디버거 개체를 참조하세요. C++ 및 드라이버 개체 작업에 대한 자세한 내용은 디버거 데이터 모델 C++ 개요를 참조하세요.

Dx 명령

여기에 표시된 예제에서는 dx 명령을 사용합니다. dx 명령 작업에 대한 자세한 내용은 dx(디버거 개체 모델 식 표시)를 참조하세요.

LINQ 쿼리 개발

LINQ 디버거 개체 쿼리를 개발하는 한 가지 방법은 표시되는 DML 링크를 사용하여 데이터 모델을 탐색하여 쿼리에 사용할 디버거 개체를 먼저 찾는 것입니다.

이 예제에서는 커널 디버그 세션의 프로세스 목록과 각 프로세스에 대한 스레드 수를 표시하려고 합니다.

탐색을 시작하려면 dx 명령을 사용하여 최상위 디버거 개체를 표시할 수 있습니다.

0: kd> dx Debugger
Debugger
    Sessions
    Settings
    State
    Utility

최상위 수준 topics 선택한 후 세션이 가장 흥미로운 것으로 확인되므로 DML 링크를 선택하여 프로세스가 포함되어 있음을 표시합니다.

0: kd> dx -r1 Debugger.Sessions[0]
Debugger.Sessions[0]                 : Remote KD: KdSrv:Server=@{<Local>},Trans=@{NET:Port=50005,Key=MyKey}
    Processes
    Id               : 0
    Attributes

그런 다음, 아래를 선택하여 특정 프로세스를 살펴보고 해당 프로세스와 연결된 스레드를 사용할 수 있음을 확인합니다. 프로세스 중 하나에 대해 스레드 를 선택하면 해당 프로세스와 연결된 모든 스레드를 사용할 수 있습니다.

0: kd> dx -r1 Debugger.Sessions[0].Processes[1428].Threads
Debugger.Sessions[0].Processes[1428].Threads
    [0x598]          : <Unable to get stack trace> [Switch To]
    [0x1220]         : <Unable to get stack trace> [Switch To]
    [0x6f8]          : nt!KiSwapContext+0x76 (fffff806`4466a186)  [Switch To]
    [0x128c]         : <Unable to get stack trace> [Switch To]
    [0x27e4]         : nt!KiSwapContext+0x76 (fffff806`4466a186)  [Switch To] 

이제 프로세스와 연결된 스레드 수를 표시하는 데 필요한 데이터는 디버거 개체 모델에서 사용할 수 있습니다.

LINQ 쿼리를 좀 더 짧게 만들려면 이 항목의 뒷부분에 설명된 시스템 정의 변수를 사용하여 현재 세션과 연결된 프로세스를 표시할 수 있습니다.

0: kd> dx @$cursession.Processes
@$cursession.Processes                
    [0x0]            : Idle [Switch To]
    [0x4]            : System [Switch To]
    [0x90]           : Registry [Switch To]
...

다음으로 select 문을 추가합니다. 먼저 이름 필드를 지정할 수 있습니다.

0: kd> dx @$cursession.Processes.Select(p => p.Name)
@$cursession.Processes.Select(p => p.Name)                
    [0x0]            : Idle
    [0x4]            : System
    [0x90]           : Registry
...

이 시나리오에서는 스레드 수도 필요합니다. 두 개의 필드가 있기 때문에 사용자 정의 변수에서 아래에 설명된 C#의 익명 형식 구문과 유사하게 new를 사용하여 익명 형식을 만듭니다.

dx @$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})

이 명령을 사용하면 'dx'가 실제로 이름을 더 이상 출력하지 않으므로 -r2(두 수준 재귀)를 추가하여 이름 및 스레드를 표시합니다.

dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})
@$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})                
    [0x0]           
        Name             : Idle
        Threads         
    [0x4]           
        Name             : System
        Threads         
    [0x90]          
        Name             : Registry
        Threads       

이 시점에서 프로세스의 이름과 스레드 목록을 표시합니다. ThreadCount를 표시하려면 를 사용합니다 . Count() 메서드.

0: kd> dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()})
@$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()})                
    [0x0]           
        Name             : Idle
        ThreadCount      : 0x4
    [0x4]           
        Name             : System
        ThreadCount      : 0xe7
    [0x90]          
        Name             : Registry
        ThreadCount      : 0x4
...

스레드 수가 많은 프로세스를 확인하려면 OrderByDescending을 사용하여 스레드 수별로 목록을 정렬합니다.

0: kd> dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount)
@$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount)                
    [0x4]           
        Name             : System
        ThreadCount      : 0xe7
    [0xa38]         
        Name             : svchost.exe
        ThreadCount      : 0x45
    [0x884]         
        Name             : MemCompression
        ThreadCount      : 0x3e

서식이 지정된 그리드에서 렌더링하려면 '-r2'를 '-g'로 변경합니다. 그리드 옵션이 열을 적절하게 표시하므로 재귀 수준을 지정할 필요가 없습니다. 마지막으로 10진수 값을 출력하는 ',d' 형식 지정자를 추가합니다.

0: kd> dx -g @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount),d
===========================================================================================
=            = Name                                                         = ThreadCount =
===========================================================================================
= [4]        - System                                                       - 231         =
= [2616]     - svchost.exe                                                  - 69          =
= [2180]     - MemCompression                                               - 62          =
= [968]      - explorer.exe                                                 - 61          =

디버거 개체 예제

이 예제에서는 가장 많은 스레드를 실행하는 상위 5개 프로세스를 보여 줍니다.

0: kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new { Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.ThreadCount),5
Debugger.Sessions.First().Processes.Select(p => new { Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.ThreadCount),5 

: 
    [0x4]            : 
        Name             : <Unknown Image>
        ThreadCount      : 0x73
    [0x708]          : 
        Name             : explorer.exe
        ThreadCount      : 0x2d
    [0x37c]          : 
        Name             : svchost.exe
        ThreadCount      : 0x2c
    [0x6b0]          : 
        Name             : MsMpEng.exe
        ThreadCount      : 0x22
    [0x57c]          : 
        Name             : svchost.exe
        ThreadCount      : 0x15
    [...]       

이 예제에서는 플러그 앤 플레이 디바이스 트리의 디바이스를 실제 디바이스 개체의 드라이버 이름으로 그룹화하여 보여 니다. 모든 출력이 표시되지는 않습니다.

kd> dx -r2 Debugger.Sessions.First().Devices.DeviceTree.Flatten(n => n.Children).GroupBy(n => n.PhysicalDeviceObject->Driver->DriverName.ToDisplayString())
Debugger.Sessions.First().Devices.DeviceTree.Flatten(n => n.Children).GroupBy(n => n.PhysicalDeviceObject->Driver->DriverName.ToDisplayString()) 

: 
    ["\"\\Driver\\PnpManager\""] : 
        [0x0]            : HTREE\ROOT\0
        [0x1]            : ROOT\volmgr\0000 (volmgr)
        [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
        [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
        [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
         ...  

Dx 명령 탭 자동 완성

상황별 TAB 키 자동 완성은 LINQ 쿼리 메서드를 인식하며 람다의 매개 변수에 대해 작동합니다.

예를 들어 다음 텍스트를 디버거에 입력(또는 복사하여 붙여넣기)합니다. 그런 다음 TAB 키를 여러 번 눌러 잠재적인 완료를 순환합니다.

dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.

"까지 TAB 키를 누릅니다. 이름"이 나타납니다. 닫는 괄호 ")"를 추가하고 Enter 키를 눌러 명령을 실행합니다.

kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name)
Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name) : 
    [0x274]          : 
        Name             : winlogon.exe
        ThreadCount      : 0x4
    [0x204]          : 
        Name             : wininit.exe
        ThreadCount      : 0x2
    [0x6c4]          : 
        Name             : taskhostex.exe
        ThreadCount      : 0x8
         ...  

이 예제에서는 키 비교자 메서드를 사용하여 완료를 보여줍니다. 키가 문자열이므로 대체에 문자열 메서드가 표시됩니다.

dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.

"까지 TAB 키를 누릅니다. 길이"가 나타납니다. 닫는 괄호 ")"를 추가하고 Enter 키를 눌러 명령을 실행합니다.

kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.Length)
Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.Length) : 
    [0x544]          : 
        Name             : spoolsv.exe
        ThreadCount      : 0xc
    [0x4d4]          : 
        Name             : svchost.exe
        ThreadCount      : 0xa
    [0x438]          : 
        Name             : svchost.exe

사용자 정의 변수

변수 이름을 @$로 접두사로 지정하여 사용자 정의 변수를 정의할 수 있습니다. 사용자 정의 변수는 dx에서 활용할 수 있는 모든 항목(예: 람다, LINQ 쿼리 결과 등)에 할당할 수 있습니다.

다음과 같이 사용자 변수의 값을 만들고 설정할 수 있습니다.

kd> dx @$String1="Test String"

Debugger.State.UserVariables 또는 @$vars 사용하여 정의된 사용자 변수를 표시할 수 있습니다.

kd> dx Debugger.State.UserVariables
Debugger.State.UserVariables : 
    mySessionVar     : 
    String1          : Test String

를 사용하여 변수를 제거할 수 있습니다. 제거.

kd> dx @$vars.Remove("String1")

이 예제에서는 Debugger.Sesssions를 참조하는 사용자 변수를 정의하는 방법을 보여 줍니다.

kd> dx @$mySessionVar = Debugger.Sessions

그런 다음, 아래와 같이 사용자 정의 변수를 사용할 수 있습니다.

kd> dx -r2 @$mySessionVar 
@$mySessionVar   : 
    [0x0]            : Remote KD: KdSrv:Server=@{<Local>},Trans=@{COM:Port=\\.\com3,Baud=115200,Timeout=4000}
        Processes        : 
        Devices     

시스템 정의 변수

다음 시스템 정의 변수는 LINQ dx 쿼리에서 사용할 수 있습니다.

  • @$cursession - 현재 세션

  • @$curprocess - 현재 프로세스

  • @$curthread - 현재 스레드

이 예제에서는 시스템 정의 변수의 사용을 보여 줍니다.

kd> dx @$curprocess.Threads.Count()
@$curprocess.Threads.Count() : 0x4
kd> dx -r1 @$curprocess.Threads
@$curprocess.Threads : 
    [0x4adc]         : 
    [0x1ee8]         : 
    [0x51c8]         : 
    [0x62d8]         : 
     ...

사용자 정의 변수 - 익명 형식

이 동적 개체 만들기는 C# 익명 형식 구문(새 { ... })을 사용하여 수행됩니다. 익명 형식에 대한 자세한 내용은 익명 형식(C# 프로그래밍 가이드)을 참조하세요. 이 예제에서는 정수 및 문자열 값을 사용하여 익명 형식을 만듭니다.

kd> dx -r1 new { MyInt = 42, MyString = "Hello World" }
new { MyInt = 42, MyString = "Hello World" } : 
    MyInt            : 42
    MyString         : Hello World

함수 개체(람다 식)

데이터를 쿼리하는 데 사용되는 대부분의 메서드는 컬렉션의 개체에서 사용자가 제공한 함수를 반복적으로 실행하는 개념을 기반으로 합니다. 디버거에서 데이터를 쿼리하고 조작하는 기능을 지원하기 위해 dx 명령은 해당하는 C# 구문을 사용하여 람다 식을 지원합니다. 람다 식은 다음과 같이 => 연산자를 사용하여 정의됩니다.

(arguments) => (result)

LINQ가 dx와 함께 사용되는 방법을 확인하려면 이 간단한 예제를 사용하여 5와 7을 함께 추가합니다.

kd> dx ((x, y) => (x + y))(5, 7) 

dx 명령은 람다 식을 다시 에코하고 12의 결과를 표시합니다.

((x, y) => (x + y))(5, 7)  : 12

이 예제 람다 식은 문자열 "Hello" 및 "World"를 결합합니다.

kd> dx ((x, y) => (x + y))("Hello", "World")
((x, y) => (x + y))("Hello", "World") : HelloWorld

지원되는 LINQ 구문 - 쿼리 메서드

dx가 반복 가능으로 정의하는 모든 개체(네이티브 배열, 컨테이너로 설명하는 NatVis가 작성된 형식 또는 디버거 확장 개체)에는 일련의 LINQ(또는 LINQ와 동등한) 메서드가 프로젝션됩니다. 이러한 쿼리 메서드는 아래에 설명되어 있습니다. 쿼리 메서드에 대한 인수의 서명은 모든 쿼리 메서드 다음에 나열됩니다.

필터링 메서드

. Where ( PredicateMethod ): 조건자 메서드가 true를 반환한 입력 컬렉션의 모든 개체를 포함하는 개체의 새 컬렉션을 반환합니다.

프로젝션 메서드

. Flatten( [KeyProjectorMethod] ): 컨테이너(트리)의 입력 컨테이너를 가져와 트리의 모든 요소가 있는 단일 컨테이너로 평면화합니다. 선택적 키 프로젝터 메서드를 제공하는 경우 트리는 자체 컨테이너인 키의 컨테이너로 간주되며 해당 키는 프로젝션 메서드 호출에 의해 결정됩니다.

. Select ( KeyProjectorMethod ): 입력 컬렉션의 모든 개체에서 프로젝터 메서드를 호출한 결과를 포함하는 개체의 새 컬렉션을 반환합니다.

그룹화 메서드

. GroupBy( KeyProjectorMethod, [KeyComparatorMethod] ): 키 프로젝터 메서드를 호출하여 결정된 것과 동일한 키를 가진 입력 컬렉션의 모든 개체를 그룹화하여 컬렉션의 새 컬렉션을 반환합니다. 선택적 비교자 메서드를 제공할 수 있습니다.

Join(InnerCollection, 외부 키 선택기 메서드, 내부 키 선택기 메서드, 결과 선택기 메서드, [ComparatorMethod]): 키 선택기 함수를 기반으로 두 시퀀스를 조인하고 값 쌍을 추출합니다. 선택적 비교자 메서드를 지정할 수도 있습니다.

Intersect(InnerCollection, [ComparatorMethod]): 집합 교집합을 반환합니다. 즉, 두 컬렉션 각각에 나타나는 요소를 의미합니다. 선택적 비교자 메서드를 지정할 수도 있습니다.

Union(InnerCollection, [ComparatorMethod]) : 두 컬렉션 중 하나에 나타나는 고유한 요소를 의미하는 집합 공용 구조체를 반환합니다. 선택적 비교자 메서드를 지정할 수도 있습니다.

데이터 집합 메서드

포함(Object, [ComparatorMethod]): 시퀀스에 지정된 요소가 포함되어 있는지 여부를 결정합니다. 요소를 시퀀스의 항목과 비교할 때마다 호출되는 선택적 비교자 메서드를 제공할 수 있습니다.

Distinct([ComparatorMethod]): 컬렉션에서 중복 값을 제거합니다. 컬렉션의 개체를 비교할 때마다 호출되도록 선택적 비교자 메서드를 제공할 수 있습니다.

제외(InnerCollection, [ComparatorMethod]): 집합 차이를 반환합니다. 즉, 두 번째 컬렉션에 표시되지 않는 한 컬렉션의 요소를 의미합니다. 선택적 비교자 메서드를 지정할 수 있습니다.

Concat(InnerCollection): 두 시퀀스를 연결하여 하나의 시퀀스를 구성합니다.

정렬 메서드

. OrderBy( KeyProjectorMethod, [KeyComparatorMethod] ): 입력 컬렉션의 모든 개체에서 키 프로젝션 메서드를 호출하여 제공된 키에 따라 컬렉션을 오름차순으로 정렬합니다. 선택적 비교자 메서드를 제공할 수 있습니다.

. OrderByDescending( KeyProjectorMethod, [KeyComparatorMethod] ): 입력 컬렉션의 모든 개체에서 키 프로젝션 메서드를 호출하여 제공된 키에 따라 컬렉션을 내림차순으로 정렬합니다. 선택적 비교자 메서드를 제공할 수 있습니다.

집계 메서드

Count(): 컬렉션의 요소 수를 반환하는 메서드입니다.

합계([ProjectionMethod]): 컬렉션의 값 합계를 계산합니다. 필요에 따라 합계가 발생하기 전에 요소를 변환하는 프로젝터 메서드를 지정할 수 있습니다.

건너뛰기 메서드

건너뛰기(개수): 시퀀스에서 지정된 위치까지 요소를 건너뜁니다.

SkipWhile(PredicateMethod): 요소가 조건을 충족하지 않을 때까지 조건자 함수를 기반으로 요소를 건너뜁니다.

메서드를 사용합니다.

Take(Count): 요소를 시퀀스에서 지정된 위치까지 사용합니다.

TakeWhile(PredicateMethod): 요소가 조건을 충족하지 않을 때까지 조건자 함수를 기반으로 요소를 사용합니다.

비교 메서드

SequenceEqual(InnerCollection, [ComparatorMethod]) : 쌍 단위로 요소를 비교하여 두 시퀀스가 같은지 여부를 결정합니다. 선택적 비교자를 지정할 수 있습니다.

오류 처리 메서드

AllNonError(PredicateMethod): 컬렉션의 오류가 아닌 모든 요소가 지정된 조건을 충족하는지 여부를 반환합니다.

FirstNonError([PredicateMethod]) : 오류가 아닌 컬렉션의 첫 번째 요소를 반환합니다.

LastNonError([PredicateMethod]): 오류가 아닌 컬렉션의 마지막 요소를 반환합니다.

기타 메서드

. All( PredicateMethod ): 입력 컬렉션의 모든 요소에서 지정된 조건자 메서드를 호출한 결과가 true인지 여부를 반환합니다.

. Any ( PredicateMethod ): 입력 컬렉션의 요소에 대해 지정된 조건자 메서드를 호출한 결과가 true인지 여부를 반환합니다.

. First( [PredicateMethod] ): 컬렉션의 첫 번째 요소를 반환합니다. 선택적 조건자가 전달되면 조건자 호출이 true를 반환하는 컬렉션의 첫 번째 요소를 반환합니다.

. Last( [PredicateMethod] ): 컬렉션의 마지막 요소를 반환합니다. 선택적 조건자가 전달되면 조건자 호출이 true를 반환하는 컬렉션의 마지막 요소를 반환합니다.

Min([KeyProjectorMethod]): 컬렉션의 최소 요소를 반환합니다. 선택적 프로젝터 메서드는 다른 메서드와 비교하기 전에 각 메서드를 프로젝터하도록 지정할 수 있습니다.

Max([KeyProjectorMethod]): 컬렉션의 최대 요소를 반환합니다. 선택적 프로젝터 메서드는 다른 메서드와 비교하기 전에 각 메서드를 프로젝터하도록 지정할 수 있습니다.

Single([PredicateMethod]): 목록에서 유일한 요소를 반환합니다(또는 컬렉션에 둘 이상의 요소가 포함된 경우 오류). 조건자가 지정된 경우 는 해당 조건자를 충족하는 단일 요소를 반환합니다(둘 이상의 요소가 충족하는 경우 함수는 오류를 대신 반환함).

인수의 서명

KeyProjectorMethod : ( obj => 임의 키 ) 컬렉션의 개체를 사용하고 해당 개체에서 키를 반환합니다.
KeyComparatorMethod: ( (a, b) => 정수 값 ) 두 개의 키를 가져와서 반환하는 키를 비교합니다.

-1 if ( a < b )

0 if ( a == b)

1 if ( a > b )

PredicateMethod: ( obj => boolean value ) 컬렉션의 개체를 사용하고 해당 개체가 특정 조건을 충족하는지 여부에 따라 true 또는 false를 반환합니다.

지원되는 LINQ 구문 - 문자열 조작

모든 문자열 개체에는 다음 메서드가 프로젝트되므로 사용할 수 있습니다.

관련 메서드 & 속성 쿼리

. Contains ( OtherString ): 입력 문자열에 OtherString이 포함되어 있는지 여부를 나타내는 부울 값을 반환합니다.

. EndsWith( OtherString ): 입력 문자열이 OtherString으로 끝나는지 여부를 나타내는 부울 값을 반환합니다.

Length: 문자열의 길이를 반환하는 속성입니다.

. StartsWith( OtherString ): 입력 문자열이 OtherString으로 시작하는지 여부를 나타내는 부울 값을 반환합니다.

. 부분 문자열( StartPos, [Length] ): 지정된 시작 위치에서 시작하는 입력 문자열 내의 부분 문자열을 반환합니다. 선택적 길이가 제공되면 반환된 부분 문자열은 지정된 길이가 됩니다. 그렇지 않으면 문자열의 끝으로 이동합니다.

기타 메서드

. IndexOf( OtherString ): 입력 문자열 내에서 처음 발생하는 OtherString의 인덱스입니다.

. LastIndexOf( OtherString ): 입력 문자열 내에서 OtherString이 마지막으로 발생한 인덱스를 반환합니다.

서식 지정 메서드

. PadLeft( TotalWidth ): 문자열의 총 길이를 지정된 너비로 가져오기 위해 필요에 따라 문자열 왼쪽에 공백을 추가합니다.

. PadRight( TotalWidth ): 문자열의 총 길이를 지정된 너비로 가져오기 위해 필요에 따라 문자열의 오른쪽에 공백을 추가합니다.

. Remove ( StartPos, [Length] ): 입력 문자열에서 지정된 시작 위치로 시작하는 문자를 제거합니다. 선택적 길이 매개 변수가 제공되면 해당 문자 수가 제거됩니다. 그렇지 않으면 문자열의 끝에 있는 모든 문자가 제거됩니다.

. Replace( SearchString, ReplaceString ): 입력 문자열 내에서 SearchString이 발생할 때마다 지정된 ReplaceString으로 바꿉니다.

문자열 개체 프로젝션

문자열 개체에 직접 프로젝트되는 메서드 외에도 문자열 변환이 있는 개체에는 다음과 같은 메서드가 프로젝트되어 메서드를 사용할 수 있습니다.

. ToDisplayString( ): 개체의 문자열 변환을 반환합니다. 개체에 대한 dx 호출에 표시되는 문자열 변환입니다. ToDisplayString의 출력에 서식을 지정하는 서식 지정자를 제공할 수 있습니다. 자세한 내용은 Visual Studio 디버거에서 C++에 대한 형식 지정자를 참조하세요.

다음 예제에서는 형식 지정자의 사용을 보여 줍니다.

kd> dx (10).ToDisplayString("d")
(10).ToDisplayString("d") : 10

kd> dx (10).ToDisplayString("x")
(10).ToDisplayString("x") : 0xa

kd> dx (10).ToDisplayString("o")
(10).ToDisplayString("o") : 012

kd> dx (10).ToDisplayString("b") 
(10).ToDisplayString("b")  : 0y1010

kd> dx ("some wchar string here").ToDisplayString("su") 
("some wchar string here").ToDisplayString("su")  : "some wchar string here"

kd> dx ("some wchar string here").ToDisplayString("sub") 
("some wchar string here").ToDisplayString("sub")  : some wchar string here

디버깅 플러그 앤 플레이 예제

이 섹션에서는 LINQ 쿼리와 함께 사용되는 기본 제공 디버거 개체를 사용하여 플러그 앤 플레이 개체를 디버그하는 방법을 보여 줍니다.

모든 디바이스 보기

디바이스 트리에서 평면화 를 사용하여 모든 디바이스를 봅니다.

 1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ROOT\volmgr\0000 (volmgr)
    [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
    [0x5]            : ROOT\spaceport\0000 (spaceport)
    [0x6]            : ROOT\KDNIC\0000 (kdnic)
    [0x7]            : ROOT\UMBUS\0000 (umbus)
    [0x8]            : ROOT\ACPI_HAL\0000
...

표 형태 창 표시

다른 dx 명령과 마찬가지로 명령이 실행된 후 명령을 선택하고 길게 누르거나 마우스 오른쪽 단추로 클릭하고 "눈금으로 표시"를 선택하거나 명령에 "-g"를 추가하여 결과의 그리드 보기를 가져올 수 있습니다.

# 0: kd> dx -g @$cursession.Devices.DeviceTree.Flatten(n => n.Children)
=====================================================================================================================================================================================================================================================================================================================
# =                                                              = (+) DeviceNodeObject = InstancePath                                                 = ServiceName               = (+) PhysicalDeviceObject                                    = State                          = (+) Resoures = (+) Children       =
=====================================================================================================================================================================================================================================================================================================================
= [0x0] : HTREE\ROOT\0                                         - {...}                - HTREE\ROOT\0                                                 -                           - 0xffffb6075614be40 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x1] : ROOT\volmgr\0000 (volmgr)                            - {...}                - ROOT\volmgr\0000                                             - volmgr                    - 0xffffb607561fbe40 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x2] : ROOT\BasicDisplay\0000 (BasicDisplay)                - {...}                - ROOT\BasicDisplay\0000                                       - BasicDisplay              - 0xffffb607560739b0 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x3] : ROOT\CompositeBus\0000 (CompositeBus)                - {...}                - ROOT\CompositeBus\0000                                       - CompositeBus              - 0xffffb607561f9060 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
...

상태별 디바이스 보기

특정 디바이스 상태를 지정하려면 Where 를 사용합니다.

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State <operator> <state number>)

예를 들어 DeviceNodeStarted 상태에서 디바이스를 보려면 이 명령을 사용합니다.

1: kd>  dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State == 776)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State == 776)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ROOT\volmgr\0000 (volmgr)
    [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
...

시작되지 않은 디바이스 보기

이 명령을 사용하여 DeviceNodeStarted 상태가 아닌 디바이스를 볼 수 있습니다.

1: kd>  dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State != 776)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State != 776)                
    [0x0]            : ACPI\PNP0C01\1
    [0x1]            : ACPI\PNP0000\4&215d0f95&0
    [0x2]            : ACPI\PNP0200\4&215d0f95&0
    [0x3]            : ACPI\PNP0100\4&215d0f95&0
    [0x4]            : ACPI\PNP0800\4&215d0f95&0
    [0x5]            : ACPI\PNP0C04\4&215d0f95&0
    [0x6]            : ACPI\PNP0700\4&215d0f95&0 (fdc)
    [0x7]            : ACPI\PNP0C02\1
    [0x8]            : ACPI\PNP0C02\2

문제 코드별 디바이스 보기

DeviceNodeObject.Problem 개체를 사용하여 특정 문제 코드가 있는 디바이스를 볼 수 있습니다.

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem <operator> <problemCode>)

예를 들어 0이 아닌 문제 코드가 있는 디바이스를 보려면 이 명령을 사용합니다. "!devnode 0 21"에 유사한 정보를 제공합니다.

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem != 0)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem != 0)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ACPI\PNP0700\4&215d0f95&0 (fdc)

문제 없이 모든 디바이스 보기

이 명령을 사용하여 문제 없이 모든 디바이스 보기

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0)                
    [0x0]            : ROOT\volmgr\0000 (volmgr)
    [0x1]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x2]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x3]            : ROOT\vdrvroot\0000 (vdrvroot)
...

특정 문제가 있는 모든 디바이스 보기

이 명령을 사용하여 문제 상태가 0x16 디바이스를 볼 수 있습니다.

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0x16)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0x16)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ACPI\PNP0700\4&215d0f95&0 (fdc)

함수 드라이버별 디바이스 보기

이 명령을 사용하여 함수 드라이버로 디바이스를 볼 수 있습니다.

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName <operator> <service name>)

atapi와 같은 특정 함수 드라이버를 사용하여 디바이스를 보려면 이 명령을 사용합니다.

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName == "atapi")
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName == "atapi")                
    [0x0]            : PCIIDE\IDEChannel\4&10bf2f88&0&0 (atapi)
    [0x1]            : PCIIDE\IDEChannel\4&10bf2f88&0&1 (atapi)

부팅 시작 드라이버 목록 보기

부팅 시작 드라이버로 로드된 winload 목록을 보려면 LoaderBlock에 액세스할 수 있고 LoaderBlock이 아직 주변에 있을 만큼 일찍 액세스할 수 있는 컨텍스트에 있어야 합니다. 예를 들어 nt! IopInitializeBootDrivers. 중단점은 이 컨텍스트에서 중지되도록 설정할 수 있습니다.

1: kd> g
Breakpoint 0 hit
nt!IopInitializeBootDrivers:
8225c634 8bff            mov     edi,edi

?? 부팅 드라이버 구조를 표시하는 명령입니다.

1: kd> ?? LoaderBlock->BootDriverListHead
struct _LIST_ENTRY
 [ 0x808c9960 - 0x808c8728 ]
   +0x000 Flink            : 0x808c9960 _LIST_ENTRY [ 0x808c93e8 - 0x808a2e18 ]
   +0x004 Blink            : 0x808c8728 _LIST_ENTRY [ 0x808a2e18 - 0x808c8de0 ]

nt!_LIST_ENTRY 구조체의 시작 주소를 사용하여 Debugger.Utility.Collections.FromListEntry 디버거 개체를 사용하여 데이터를 봅니다.

1: kd> dx Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")
Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")                
    [0x0]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x1]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x2]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x3]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x4]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x5]            [Type: _BOOT_DRIVER_LIST_ENTRY]
...

-g 옵션을 사용하여 데이터의 그리드 뷰를 만듭니다.

dx -r1 -g Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")

기능별 디바이스 보기

DeviceNodeObject.CapabilityFlags 개체를 사용하여 기능별로 디바이스를 봅니다.

dx -r1 @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & <flag>) != 0)

이 표에서는 일반적인 디바이스 기능 플래그와 함께 dx 명령의 사용을 요약합니다.

제거 가능

dbgcmd 0: kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x10) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x10) != 0)
[0x0] : SWD\PRINTENUM{2F8DBBB6-F246-4D84-BB1D-AA8761353885} [0x1] : SWD\PRINTENUM{F210BC77-55A1-4FCA-AA80-013E2B408378} [F210BC77 0x2] : SWD\PRINTENUM{07940A8E-11F4-46C3-B714-7FF9B87738F8} [0x3] : DISPLAY\Default_Monitor\6&1a097cd8&0&UID5527112(모니터)

UniqueID

dbgcmd 0: kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x40) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x40) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : ROOT\volmgr\0000 (volmgr) [0x2] : ROOT\spaceport\0000 (spaceport) ...

SilentInstall

dbgcmd 0: kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x80) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x80) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : ROOT\volmgr\0000 (volmgr) [0x2] : ROOT\spaceport\0000 (spaceport) ...

RawDeviceOk

dbgcmd 0: kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x100) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x100) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : SWD\MMDEVAPI\MicrosoftGSWavetableSynth [0x2] : SWD\IP_TUNNEL_VBUS\IP_TUNNEL_DEVICE_ROOT ...

SurpriseRemovalOK

dbgcmd 0: kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x200) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x200) != 0)
[0x0] : SWD\MMDEVAPI\MicrosoftGSWavetableSynth [0x1] : SWD\IP_TUNNEL_VBUS\IP_TUNNEL_DEVICE_ROOT [0x2] : SWD\PRINTENUM\PrintQueues ...

CapabilityFlags에 대한 자세한 내용은 DEVICE_CAPABILITIES 참조하세요.

참고 항목

dx(디스플레이 디버거 개체 모델 식)

NatVis의 네이티브 디버거 개체

JavaScript 확장의 네이티브 디버거 개체