성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Windbg - .foreach 사용법</h1> 다음의 문서에도 나오지만,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Debugger Command Program Examples ; <a target='tab' href='https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-command-program-examples'>https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-command-program-examples</a> Commands Output Using .foreach ; <a target='tab' href='https://blogs.msdn.microsoft.com/debuggingtoolbox/2009/03/11/special-commandparsing-strings-files-and-commands-output-using-foreach/'>https://blogs.msdn.microsoft.com/debuggingtoolbox/2009/03/11/special-commandparsing-strings-files-and-commands-output-using-foreach/</a> </pre> <br /> 그래도 한글 설명을 해볼까 해서 ^^ 기록으로 남깁니다.<br /> <br /> 우선, 다음의 명령어를 볼까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>.foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place L8 }</span> </pre> <br /> 명령어 구조는 이렇습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .foreach ([<i>변수</i>] { <i>명령어1</i> }) { <i>명령어2</i> } // <i>명령어1</i>을 실행하고 그 결과를 공백/개행 기준 split 시킨 후 <i>변수</i>에 담아 <i>명령어2</i>를 루프 돌면서 실행 // 따라서, 변수 == place 명령어1 == { s-[1]w 77000000 L?4000000 5a4d } 명령어2 == { dc place L8 } </pre> <br /> 명령어1의 출력 결과는 다음과 같은 식입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0x77002f96 0x77002f9e 0x77002fa6 0x77002fa8 0x77002faa 0x77002fac 0x77002fae 0x77002fb0 0x77002fb2 0x77002fb4 0x77002fb6 </pre> <br /> place는 변수, 즉 windbg의 s 명령어로 77000000에서 4000000만큼의 메모리 범위 내에 5a4d를 검색한 결과를 토큰별로 place로 변수를 받고, 이후 dc place L8에서 place 부분이 s 검색으로 찾은 토큰으로 대체되는 것입니다. C# 구문으로 변환해 보자면 다음과 같은 의미와 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > foreach (var place in s(77000000, 4000000, "5a4d")) { dc place L8; } </pre> <br /> 다른 사례를 한번 볼까요? 다음은 sos의 !dso 명령어 출력입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>!dso</span> OS Thread Id: 0x70ac (0) ESP/REG Object Name 0133EE30 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE54 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE60 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE88 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle 0133EEB0 035657a8 System.IO.StreamReader 0133EEB4 035657a8 System.IO.StreamReader 0133EECC 03565b2c System.IO.TextReader+SyncTextReader 0133EEE8 03565b2c System.IO.TextReader+SyncTextReader 0133EF14 03563110 System.String[] 0133EF84 03563110 System.String[] 0133F0DC 03563110 System.String[] 0133F0F8 03563110 System.String[] 0133F630 03561238 System.SharedStatics 0133F644 03561238 System.SharedStatics </pre> <br /> 여기서 우리가 관심 있는 것은 "Object" 칼럼에 있는 값들입니다. 그런데 이번엔 이전 예제와는 달리 다른 값들도 섞여 있기 때문에 다른 옵션이 필요합니다. 이를 위해 저 출력 결과를 string.Split 메서드로 공백/개행 문자로 분리했다고 가정하시면 됩니다. 그럼 처음 9개의 토큰을 건너뛰어야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> !dso <span style='color: blue; font-weight: bold'>OS Thread Id: 0x70ac (0) ESP/REG Object Name 0133EE30</span> 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle ...[생략]... 0133F644 03561238 System.SharedStatics </pre> <br /> 그러니까, 다음의 9개 토큰을 그냥 지나가야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 1) OS 2) Thread 3) Id: 4) 0x70ac 5) (0) 6) ESP/REG 7) Object 8) Name 9) 0133EE30 </pre> <br /> 그런 다음, 원하는 토큰이 나오고 이후 다시 2개의 토큰 값들을 건너뛰는 식으로 열람할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> !dso OS Thread Id: 0x70ac (0) ESP/REG Object Name 0133EE30 0356576c <span style='color: blue; font-weight: bold'>Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE54</span> 0356576c <span style='color: blue; font-weight: bold'>Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE60</span> 0356576c <span style='color: blue; font-weight: bold'>Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE88</span> 0356576c <span style='color: blue; font-weight: bold'>Microsoft.Win32.SafeHandles.SafeFileHandle 0133EEB0</span> 035657a8 <span style='color: blue; font-weight: bold'>System.IO.StreamReader 0133EEB4</span> 035657a8 <span style='color: blue; font-weight: bold'>System.IO.StreamReader 0133EECC</span> 03565b2c <span style='color: blue; font-weight: bold'>System.IO.TextReader+SyncTextReader 0133EEE8</span> 03565b2c <span style='color: blue; font-weight: bold'>System.IO.TextReader+SyncTextReader 0133EF14</span> 03563110 <span style='color: blue; font-weight: bold'>System.String[] 0133EF84</span> 03563110 <span style='color: blue; font-weight: bold'>System.String[] 0133F0DC</span> 03563110 <span style='color: blue; font-weight: bold'>System.String[] 0133F0F8</span> 03563110 <span style='color: blue; font-weight: bold'>System.String[] 0133F630</span> 03561238 <span style='color: blue; font-weight: bold'>System.SharedStatics 0133F644</span> 03561238 System.SharedStatics </pre> <br /> 이렇게 처음 토큰들을 건너뛰도록 /pS 옵션이 제공되고, 이후 반복적으로 건너뛸 토큰들을 /ps 옵션으로 제공하면 됩니다. 따라서 다음과 같이 실행하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .foreach <span style='color: blue; font-weight: bold'>/pS 9 /ps 2</span> ( obj { !dso } ){ .echo ${obj} } </pre> <br /> 화면에는 Object 칼럼에 해당하는 값들이 "obj" 변수에 할당되어 .echo 출력으로 전달되고 이런 출력 결과를 얻게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: <p>Consolas, Verdana;' > 0356576c 0356576c 0356576c 0356576c 035657a8 035657a8 03565b2c 03565b2c 03563110 03563110 03563110 03563110 03561238 03561238 </pre> <br /> 그렇습니다. .foreach가 제공하는 루프 문 규칙은 꽤나 원시(?)적인 수준입니다. 그래도, 확장의 여지가 있긴 한데 이를 위해 console 응용 프로그램을 이용할 수 있습니다. 가령 !dso 출력 결과에서 "System."으로 시작하는 행의 Object 칼럼만 반환받고 싶다면, 기존의 /pS, /ps 옵션으로는 불가능한데 shell의 도움을 받으면 가능합니다.<br /> <br /> 이해를 돕기 위해 !dso의 출력 결과를 test.txt 파일로 저장해 보겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > F:\temp><span style='color: blue; font-weight: bold'>type test.txt</span> OS Thread Id: 0x70ac (0) ESP/REG Object Name 0133EE30 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE54 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE60 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle 0133EE88 0356576c Microsoft.Win32.SafeHandles.SafeFileHandle 0133EEB0 035657a8 System.IO.StreamReader 0133EEB4 035657a8 System.IO.StreamReader 0133EECC 03565b2c System.IO.TextReader+SyncTextReader 0133EEE8 03565b2c System.IO.TextReader+SyncTextReader 0133EF14 03563110 System.String[] 0133EF84 03563110 System.String[] 0133F0DC 03563110 System.String[] 0133F0F8 03563110 System.String[] 0133F630 03561238 System.SharedStatics 0133F644 03561238 System.SharedStatics </pre> <br /> 이 출력에서 "System."으로 시작하는 행은 다음과 같이 find 명령어를 이용해서 필터링할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > F:\temp>type test.txt | find "System." 0133EEB0 035657a8 System.IO.StreamReader 0133EEB4 035657a8 System.IO.StreamReader 0133EECC 03565b2c System.IO.TextReader+SyncTextReader 0133EEE8 03565b2c System.IO.TextReader+SyncTextReader 0133EF14 03563110 System.String[] 0133EF84 03563110 System.String[] 0133F0DC 03563110 System.String[] 0133F0F8 03563110 System.String[] 0133F630 03561238 System.SharedStatics 0133F644 03561238 System.SharedStatics </pre> <br /> 위의 출력 결과를 .foreach로 순회한다고 하면 우선 첫 번째 0133EEB0 항목을 건너뛰고, 035657a8 값을 읽은 후 그 이후부터는 2개의 토큰씩 건너뛰면 됩니다. 위와 같은 과정을 다음과 같은 명령어로 실행할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .foreach /pS 1 /ps 2 (obj {.shell -i - -ci "!dso" FIND "System."}){ .echo ${obj}} </pre> <br /> 명령어가 눈에 안 익을 수 있는데 정형화된 패턴이라고 보시면 됩니다. ".shell -i - -ci" 이후에 windbg 명령을 쓰고 그것의 출력 결과물을 이후의 Shell 명령어(FIND "System.")에 전달해 처리한 결과를 얻는 식입니다.<br /> <br /> 참고로 위의 명령어 수행 결과로 얻은 출력은 이렇게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 035657a8 035657a8 03565b2c 03565b2c 03563110 03563110 03563110 03563110 03561238 03561238 Process </pre> <br /> 그런데 마지막 "Process"가 왜 나왔을까요? 그 이유는, windbg의 .shell 명령어는 지정된 명령어를 실행 후 ".shell: Process exited" 출력이 붙기 때문입니다. 따라서 {.shell -i - -ci "!dso" FIND "System."} 명령어의 수행 결과는 실제로 다음과 같이 출력되었던 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0133EEB0 035657a8 System.IO.StreamReader 0133EEB4 035657a8 System.IO.StreamReader 0133EECC 03565b2c System.IO.TextReader+SyncTextReader 0133EEE8 03565b2c System.IO.TextReader+SyncTextReader 0133EF14 03563110 System.String[] 0133EF84 03563110 System.String[] 0133F0DC 03563110 System.String[] 0133F0F8 03563110 System.String[] 0133F630 03561238 System.SharedStatics 0133F644 03561238 System.SharedStatics .shell: Process exited </pre> <br /> 그렇기 때문에 마지막 03561238 토큰을 읽은 후 2개의 토큰(System.SharedStatics, .shell:)을 건너뛰고 "Process"라는 값이 읽혔던 것입니다. 그래도 대개의 경우 마지막에 저렇게 예상치 않은 문자열이 붙는 것은 결과에 크게 영향이 없습니다. 예를 들어, 수행하는 명령어가 ".echo <span class="tex2jax_ignore">$</span>{obj}"가 아니라 "!do <span class="tex2jax_ignore">$</span>{obj}"여도 명령어에서 오류만 발생할 뿐 이미 우리가 원한 객체들의 값은 모두 출력했기 때문에 신경 쓸 필요가 없는 것입니다.<br /> <br /> <br /> 이 정도면, 대충 .foreach 사용법이 눈에 들어오시죠! ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
3354
(왼쪽의 숫자를 입력해야 합니다.)