성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
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 - x64 SOS 확장의 !clrstack 명령어가 출력하는 Child SP 값의 의미</h1> <p> 예전에 windbg의 kv 명령어의 출력에 보이는 Child-SP 값에 대한 설명을 했었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > x64 콜 스택 인자 추적과 windbg의 Child-SP, RetAddr, Args to Child 값 확인 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/10832'>http://www.sysnet.pe.kr/2/0/10832</a> </pre> <br /> kv는 부모 함수에서 자식 함수를 call하고 나서의 (반환값이 적재된) RSP 값을 Child-SP로 출력한다고 했는데요. 이게 저 함수를 분석할 때의 상황에서만 맞을 뿐 다른 경우에는 자식의 SP 레지스터가 변경된 것도 포함합니다. 그런데, 디버거는 이런 정보를 (PDB가 없는 상황에서도) 어떻게 알고 Child SP 값을 계산할 수 있을까요? 이에 대해서는 다음의 글에서 설명하는 UNWIND_CODE 정보를 보시면 자세하게 나옵니다. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > X64 에 푹 빠져보기 (X64 Deep Dive) ; <a target='tab' href='http://kuaaan.tistory.com/403'>http://kuaaan.tistory.com/403</a> Unwind Data for Exception Handling, Debugger Support ; <a target='tab' href='https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64'>https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64</a> X64 Deep Dive ; <a target='tab' href='https://codemachine.com/articles/x64_deep_dive.html'>https://codemachine.com/articles/x64_deep_dive.html</a> </pre> <br /> 자, 그럼 !clrstack의 Child SP 값을 한번 실습해 보겠습니다. ^^<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;' > using System; using System.Text; namespace ConsoleApp1 { class Program { static void Main(string[] args) { <span style='color: blue; font-weight: bold'>Console.ReadLine();</span> Console.WriteLine(Encoding.UTF8.GetString(TestIt())); } private static byte[] TestIt() { try { string str = typeof(Program).ToString(); byte[] buffer = Encoding.UTF8.GetBytes(string.Format("ClassName: {1}(len={0})", str.Length, str)); Console.ReadLine(); return buffer; } catch { } return null; } } } </pre> <br /> 실행 후 windbg로 연결합니다. 연결 시점에 첫 번째 Console.ReadLine으로 인해 중지된 상태이므로 다음과 같이 TestIt 메서드에 BP를 걸고,<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'>!bpmd ConsoleApp1 ConsoleApp1.Program.TestIt</span> Found 1 methods in module 00007ffb70605108... MethodDesc = 00007ffb706059d0 Adding pending breakpoints... </pre> <br /> 실행을 계속하면 TestIt 시작 지점에서 BP가 걸립니다.<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'>g</span> ModLoad: 00007ffb`cd470000 00007ffb`cd584000 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clrjit.dll (1170.65a8): CLR notification exception - code e0444143 (first chance) *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\System32\KERNELBASE.dll - JITTED ConsoleApp1!ConsoleApp1.Program.TestIt() <span style='color: blue; font-weight: bold'>Setting breakpoint: bp 00007FFB70710556 [ConsoleApp1.Program.TestIt()]</span> Breakpoint 1 hit 00007ffb`70710556 90 nop </pre> <br /> 이 상태에서 !clrstack을 실행하면 다음과 같이 TestIt 메서드에 대해 Child SP 값을 확인할 수 있습니다.<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'>!clrstack</span> OS Thread Id: 0x65a8 (0) Child SP IP Call Site <span style='color: blue; font-weight: bold'>0000003d97fcefa0</span> 00007ffb70710556 ConsoleApp1.Program.TestIt() [E:\ConsoleApp1\ConsoleApp1\Program.cs @ 19] 0000003d97fcf060 00007ffb707104c0 ConsoleApp1.Program.Main(System.String[]) [E:\ConsoleApp1\ConsoleApp1\Program.cs @ 13] 0000003d97fcf2f0 00007ffbcfd26793 [GCFrame: 0000003d97fcf2f0] </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ConsoleApp1.Program.TestIt child sp 0000003d97fcefa0 ip 00007ffb70710556 </pre> <br /> 그리고 IP 값을 통해 역어셈블을 하면 prologue 코드를 확인할 수 있습니다.<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'>!U /d 00007ffb70710556</span> Normal JIT generated code ConsoleApp1.Program.TestIt() Begin 00007ffb70710520, size 15b E:\ConsoleApp1\ConsoleApp1\Program.cs @ 19: <span style='color: blue; font-weight: bold'>00007ffb`70710520 55 push rbp 00007ffb`70710521 57 push rdi 00007ffb`70710522 4881eca8000000 sub rsp,0A8h</span> 00007ffb`70710529 488dac24b0000000 lea rbp,[rsp+0B0h] 00007ffb`70710531 488dbd78ffffff lea rdi,[rbp-88h] 00007ffb`70710538 b920000000 mov ecx,20h 00007ffb`7071053d 33c0 xor eax,eax 00007ffb`7071053f f3ab rep stos dword ptr [rdi] 00007ffb`70710541 4889a570ffffff mov qword ptr [rbp-90h],rsp 00007ffb`70710548 833d3950efff00 cmp dword ptr [00007ffb`70605588],0 00007ffb`7071054f 7405 je 00007ffb`70710556 00007ffb`70710551 e80abfaa5f call clr!JIT_DbgIsJustMyCode (00007ffb`d01bc460) <span style='color: blue; font-weight: bold'>>>> 00007ffb`70710556 90 nop</span> ...[생략]... </pre> <br /> 그러니까, "<a target='tab' href='http://kuaaan.tistory.com/403'>X64 에 푹 빠져보기 (X64 Deep Dive)</a>" 글에 의하면 TestIt 함수에 대한 UNWIND_INFO는 다음과 같이 구성되어 있는 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > UNWIND_INFO ALLOC_SMALL, size=0xa8 PUSH_NONVOL, register=rdi PUSH_NONVOL, register=rbp </pre> <br /> 현재 windbg로 막 진입했는데 IP 주솟값은 00007ffb`70710556을 가리킵니다. 따라서 RSP 레지스터의 현재 값은 이미 prologue를 모두 지난 상태입니다. 그럼 레지스터의 값들을 볼까요?<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'>r</span> rax=0000000000000000 rbx=0000003d97fcf1d8 rcx=0000000000000000 rdx=000001e13dc73e18 rsi=000001e13dc73e00 rdi=0000003d97fcf048 rip=00007ffb70710556 rsp=<span style='color: blue; font-weight: bold'>0000003d97fcefa0</span> rbp=<span style='color: blue; font-weight: bold'>0000003d97fcf050</span> r8=0000000000000000 r9=00007ffb00000000 r10=0000000000000000 r11=0000003d97fceaf0 r12=0000000000000000 r13=0000003d97fcf160 r14=0000003d97fcf1d8 r15=0000000000000004 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 00007ffb`70710556 90 nop </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > RSP = 0000003d97fcefa0 RBP = 0000003d97fcf050 </pre> <br /> 그렇군요. Child SP였던 0000003d97fcefa0 값이 RSP 레지스터의 값과 일치합니다. 따라서 UNWIND_INFO에 있던 스택의 변경이 모두 반영된 값을 Child SP가 가리키고 있는 것입니다.<br /> <br /> 반면 RBP 값은 prologue 코드 바로 다음에 이어지는 코드를 통해서도 확인할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 00007ffb`70710520 55 push rbp 00007ffb`70710521 57 push rdi 00007ffb`70710522 4881eca8000000 sub rsp,0A8h <span style='color: blue; font-weight: bold'>00007ffb`70710529 488dac24b0000000 lea rbp,[rsp+0B0h]</span> </pre> <br /> 즉, RSP 값의 + 0xb0이므로 다음과 같이 간단하게 계산됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > RBP = [Child SP + 0xb0] = 0000003d`97fcf050 </pre> <br /> 물론 저 값은 r 명령어를 통해 구한 RBP의 값과 일치합니다.<br /> <br /> <hr style='width: 50%' /><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;' > windbg - x64 역어셈블 코드에서 닷넷 메서드 호출의 인자를 확인하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11348'>http://www.sysnet.pe.kr/2/0/11348</a> </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1609
(왼쪽의 숫자를 입력해야 합니다.)