WinDbg - 타임라인
TTD(시간 이동 디버깅)를 사용하면 사용자가 프로그램 실행 기록을 기록하는 추적을 기록할 수 있습니다. 타임라인은 실행 중에 발생하는 이벤트의 시각적 표현입니다. 이러한 이벤트는 중단점, 메모리 읽기/쓰기, 함수 호출 및 반환 및 예외의 위치일 수 있습니다.
타임라인 창을 사용하여 중요한 이벤트를 빠르게 보고, 상대 위치를 이해하고, TTD 추적 파일에서 해당 위치로 쉽게 이동할 수 있습니다. 여러 타임라인 사용하여 시간 이동 추적에서 이벤트를 시각적으로 탐색하고 이벤트 상관 관계를 검색합니다.
타임라인 창은 TTD 추적 파일을 열 때 표시되며 데이터 모델 쿼리를 수동으로 만들 필요 없이 주요 이벤트를 표시합니다. 동시에 더 복잡한 데이터 쿼리를 허용하기 위해 모든 시간 이동 개체를 사용할 수 있습니다.
시간 이동 추적 파일을 만들고 사용하는 방법에 대한 자세한 내용은 시간 이동 디버깅 - 개요를 참조하세요.
타임라인 유형
타임라인 창에는 다음 이벤트가 표시 될 수 있습니다.
- 예외(특정 예외 코드를 추가로 필터링할 수 있습니다).
- 중단점
- 함수 호출(module!function 형식으로 검색)
- 메모리 액세스(두 메모리 주소 간에 읽기/쓰기/실행)
도구 설명을 통해 자세한 정보를 얻으려면 각 이벤트를 마우스로 가리킵니다. 이벤트를 클릭하면 이벤트에 대한 쿼리가 실행되고 자세한 정보가 표시됩니다. 이벤트를 두 번 클릭하면 TTD 추적 파일의 해당 위치로 이동합니다.
예외
추적 파일을 로드하고 타임라인 활성 상태이면 기록에서 예외가 자동으로 표시됩니다.
예외 유형 및 예외 코드와 같은 중단점 정보를 마우스로 가리키면 표시됩니다.
선택적 예외 코드 필드를 사용하여 특정 예외 코드를 추가로 필터링할 수 있습니다.
특정 예외 유형에 대한 새 타임라인 추가할 수도 있습니다.
중단점
중단점을 추가한 후 중단점이 타임라인 적중되는 시점의 위치를 표시할 수 있습니다. 예를 들어 bp 중단점 설정 명령을 사용하여 이 작업을 수행할 수 있습니다. 중단점 위로 마우스를 가져가면 주소와 중단점과 연결된 명령 포인터가 표시됩니다.
중단점이 지워지면 연결된 중단점 타임라인 자동으로 제거됩니다.
함수 호출
타임라인 함수 호출의 위치를 표시할 수 있습니다. 이렇게 하려면 검색 형식(예: TimelineTestCode!multiplyTwo
/a0>)을 제공합니다. 예를 들어 TimelineTestCode!m*
wild카드를 지정할 수도 있습니다.
함수를 마우스로 가리키면 함수 이름, 입력 매개 변수, 해당 값 및 반환 값이 표시됩니다. 이 예제에서는 DisplayGreeting의 매개 변수이므로 버퍼와 크기를 보여 드립니다. GetCppConGreeting.
메모리 액세스
메모리 액세스 타임라인 사용하여 특정 메모리 범위를 읽거나 쓸 때 또는 코드 실행이 발생한 위치를 표시합니다. 시작 및 중지 주소는 두 메모리 주소 사이의 범위를 정의하는 데 사용됩니다.
메모리 액세스 항목 위로 마우스를 가져가면 값과 명령 포인터가 표시됩니다.
타임라인 작업
세로 회색 선은 타임라인 마우스로 가리키면 커서를 따릅니다. 세로 파란색 선은 추적의 현재 위치를 나타냅니다.
돋보기 아이콘을 클릭하여 타임라인 확대 및 축소합니다.
위쪽 타임라인 컨트롤 영역에서 사각형을 사용하여 타임라인 보기를 이동합니다. 사각형의 외부 구분 기호를 끌어 현재 타임라인 보기의 크기를 조정합니다.
마우스 이동
Ctrl + 스크롤 휠을 사용하여 확대 및 축소합니다.
Shift + 스크롤 휠을 사용하여 좌우로 이동합니다.
타임라인 디버깅 기술
디버깅 타임라인 기법을 보여주기 위해 시간 이동 디버깅 연습은 여기에서 다시 사용됩니다. 이 데모에서는 샘플 코드를 빌드하기 위해 처음 두 단계를 완료하고 여기서 설명한 처음 두 단계를 사용하여 TTD 녹음을 만들었다고 가정합니다.
섹션 2: "DisplayGreeting" 샘플의 추적 기록
이 시나리오에서 첫 번째 단계는 시간 이동 추적에서 예외를 찾는 것입니다. 이 작업은 타임라인 유일한 예외를 두 번 클릭하여 수행할 수 있습니다.
명령 창을 보면 예외를 클릭할 때 다음 명령이 실행된 것을 볼 수 있습니다.
(2dcc.6600): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: CC:0
@$curprocess.TTD.Events.Where(t => t.Type == "Exception")[0x0].Position.SeekTo()
레지스터 보기를>>선택하여 타임라인 이 시점에서 레지스터를 표시하여 조사를 시작합니다.
명령 출력에서 스택(esp) 및 기본 포인터(ebp)는 매우 다른 두 주소를 가리키고 있습니다. 이는 스택 손상(함수가 반환된 다음 스택이 손상되었을 수 있음)을 나타낼 수 있습니다. 유효성을 검사하려면 CPU 상태가 손상되기 전으로 돌아가 스택 손상이 발생한 시기를 확인할 수 있는지 확인해야 합니다.
이렇게 하면 지역 변수 및 스택의 값을 검사합니다.
로컬 뷰>>를 선택하여 로컬 값을 표시합니다.
보기>>스택을 선택하여 코드 실행 스택을 표시합니다.
추적 실패 시점에 오류 처리 코드의 실제 원인 이후 몇 단계를 완료하는 것이 일반적입니다. 시간 이동으로 우리는 진정한 근본 원인을 찾기 위해, 한 번에 지침을 다시 갈 수 있습니다.
홈 리본에서 한 단계씩 뒤로 물러나기 명령을 사용하여 세 가지 지침을 뒤로 밟습니다. 이렇게 하면 스택, 지역 및 등록 창을 계속 검사합니다.
명령 창에는 세 가지 지침을 뒤로 물러나면서 시간 이동 위치와 레지스터가 표시됩니다.
0:000> t-
Time Travel Position: CB:41
eax=00000000 ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=00540020 esp=003cf7d0 ebp=00520055 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
00540020 ?? ???
0:000> t-
Time Travel Position: CB:40
eax=00000000 ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=00061767 esp=003cf7cc ebp=00520055 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
DisplayGreeting!main+0x57:
00061767 c3 ret
0:000> t-
Time Travel Position: CB:3A
eax=0000004c ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=0006175f esp=003cf718 ebp=003cf7c8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
DisplayGreeting!main+0x4f:
0006175f 33c0 xor eax,eax
추적의 이 시점에서 스택 및 기본 포인터에는 더 적합한 값이 있으므로 손상이 발생한 코드의 지점에 가까워지는 것처럼 보입니다.
esp=003cf718 ebp=003cf7c8
또한 로컬 창에 대상 앱의 값이 포함되고 소스 코드 창이 추적의 이 시점에서 소스 코드에서 실행할 준비가 된 코드 줄을 강조 표시하고 있다는 점도 중요합니다.
자세히 조사하기 위해 메모리 창을 열어 스택 포인터(esp) 메모리 주소 근처의 내용을 볼 수 있습니다. 이 예제에서는 값이 003cf7c8입니다. 메모리>>텍스트>>ASCII를 선택하여 해당 주소에 저장된 ASCII 텍스트를 표시합니다.
메모리 액세스 타임라인
관심 있는 메모리 위치를 식별한 후 해당 값을 사용하여 메모리 액세스 타임라인 추가합니다. + 타임라인 추가를 클릭하고 시작 주소를 입력합니다. 4바이트를 살펴보겠습니다. 따라서 003cf7c8의 시작 주소에 추가하면 003cf7cb가 있습니다. 기본값은 모든 메모리 쓰기를 살펴보는 것이지만 해당 주소에서 쓰기 또는 코드 실행만 확인할 수도 있습니다.
이제 타임라인 역방향으로 트래버스하여 이 메모리 위치가 기록된 이동 추적 시점을 검사하여 찾을 수 있는 항목을 확인할 수 있습니다. 타임라인 이 위치를 클릭하면 지역 주민이 복사되는 문자열에 대해 다른 값을 반환하는 것을 볼 수 있습니다. 문자열의 길이가 올바르지 않은 것처럼 대상 값이 완료되지 않은 것처럼 보입니다.
중단점 타임라인
중단점을 사용하는 것은 관심 있는 경우에 코드 실행을 일시 중지하는 일반적인 방법입니다. TTD를 사용하면 추적이 기록된 후 중단점이 적중될 때까지 중단점을 설정하고 시간을 거슬러 이동할 수 있습니다. 문제가 발생한 후 프로세스 상태를 검사하여 중단점에 가장 적합한 위치를 결정하는 기능을 통해 TTD에 고유한 추가 디버깅 워크플로를 사용할 수 있습니다.
대체 타임라인 디버깅 기술을 탐색하려면 타임라인 예외를 클릭하고 홈 리본 메뉴의 한 단계씩 뒤로 이동 명령을 사용하여 다시 3단계 뒤로 이동합니다.
이 아주 작은 샘플에서는 코드를 살펴보는 것이 매우 쉽지만 수백 줄의 코드와 수십 개의 서브루틴이 있는 경우 여기에 설명된 기술을 사용하여 문제를 찾는 데 필요한 시간을 줄일 수 있습니다.
앞에서 멘션 것처럼 명령을 가리키는 대신 기본 포인터(esp)가 메시지 텍스트를 가리키고 있습니다.
ba 명령을 사용하여 메모리 액세스에 중단점을 설정합니다. 이 메모리 영역이 기록되는 시기를 확인하기 위해 w - 쓰기 중단점을 설정합니다.
0:000> ba w4 003cf7c8
간단한 메모리 액세스 중단점을 사용하지만 중단점을 더 복잡한 조건문으로 구성할 수 있습니다. 자세한 내용은 bp, bu, bm(중단점 설정)을 참조하세요.
홈 메뉴에서 [뒤로 이동]을 선택하여 중단점에 도달할 때까지 시간을 거슬러 이동합니다.
이 시점에서 프로그램 스택을 검사하여 활성 코드가 무엇인지 확인할 수 있습니다.
Microsoft에서 제공한 wscpy_s() 함수에 다음과 같은 코드 버그가 있을 가능성은 매우 낮기 때문에 스택에서 자세히 살펴봅니다. 스택은 인사말을 보여줍니다! 기본 인사말을 호출합니다! GetCppConGreeting. 아주 작은 코드 샘플에서는 이 시점에서 코드를 열고 오류를 매우 쉽게 찾을 수 있습니다. 그러나 더 크고 복잡한 프로그램에서 사용할 수 있는 기술을 설명하기 위해 함수 호출 타임라인 추가를 설정합니다.
함수 호출 타임라인
+ 타임라인 추가를 클릭하고 함수 검색 문자열을 DisplayGreeting!GetCppConGreeting
입력합니다.
시작 및 종료 위치 검사 상자는 추적에서 함수 호출의 시작과 끝을 나타냅니다.
dx 명령을 사용하여 함수 호출 개체를 표시하여 함수 호출의 시작 위치 및 끝 위치에 해당하는 연결된 TimeStart 및 TimeEnd 필드를 볼 수 있습니다.
dx @$cursession.TTD.Calls("DisplayGreeting!GetCppConGreeting")[0x0]
EventType : 0x0
ThreadId : 0x6600
UniqueThreadId : 0x2
TimeStart : 6D:BD [Time Travel]
SystemTimeStart : Thursday, October 31, 2019 23:36:05
TimeEnd : 6D:742 [Time Travel]
SystemTimeEnd : Thursday, October 31, 2019 23:36:05
Function : DisplayGreeting!GetCppConGreeting
FunctionAddress : 0x615a0
ReturnAddress : 0x61746
Parameters
시작 또는 종료 또는 시작 및 종료 위치 상자 둘 다 검사 합니다.
코드는 재귀적이거나 재입력되지 않으므로 GetCppConGreeting 메서드가 호출될 때 시간줄에서 쉽게 찾을 수 있습니다. GetCppConGreeting에 대한 호출은 중단점과 정의한 메모리 액세스 이벤트와 동시에 발생합니다. 따라서 애플리케이션 충돌의 근본 원인을 주의 깊게 살펴보기 위해 코드 영역에서 범위를 좁혀본 것 같습니다.
여러 타임라인 확인하여 코드 실행 탐색
코드 샘플은 작지만 여러 타임라인 사용하는 기술을 통해 시간 이동 추적을 시각적으로 탐색할 수 있습니다. 추적 파일에서 "중단점이 적중되기 전에 액세스되는 메모리 영역은 언제인가요?"와 같은 질문을 할 수 있습니다.
추가 상관 관계를 확인하고 예상하지 못한 항목을 찾는 기능은 타임라인 도구가 명령줄 명령을 사용하여 시간 이동 추적과 상호 작용하는 것을 구분합니다.
타임라인 책갈피
위치 붙여넣기를 메모장에 수동으로 복사하는 대신 WinDbg에서 중요한 시간 이동 위치에 책갈피를 지정합니다. 책갈피를 사용하면 추적에서 다른 이벤트를 기준으로 다른 위치를 한눈에 보고 주석을 달기 쉽습니다.
책갈피에 대한 설명이 포함된 이름을 제공할 수 있습니다.
타임라인 보기>에서 사용할 수 있는 타임라인 창을 통해 책갈피에 액세스합니다. 책갈피를 마우스로 가리키면 책갈피 이름이 표시됩니다.
책갈피를 마우스 오른쪽 단추로 클릭하여 해당 위치로 이동하거나 책갈피의 이름을 바꾸거나 삭제할 수 있습니다.
참고 항목
디버거 버전 1.2402.24001.0에서는 책갈피 기능을 사용할 수 없습니다.