Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 9개 있습니다.)
디버깅 기술: 74. x64 콜 스택 인자 추적과 windbg의 Child-SP, RetAddr, Args to Child 값 확인
; https://www.sysnet.pe.kr/2/0/10832

디버깅 기술: 77. windbg의 콜스택 함수 인자를 쉽게 확인하는 방법
; https://www.sysnet.pe.kr/2/0/10934

디버깅 기술: 106. windbg - x64 역어셈블 코드에서 닷넷 메서드 호출의 인자를 확인하는 방법
; https://www.sysnet.pe.kr/2/0/11348

디버깅 기술: 107. windbg - x64 SOS 확장의 !clrstack 명령어가 출력하는 Child SP 값의 의미
; https://www.sysnet.pe.kr/2/0/11349

디버깅 기술: 111. windbg - x86 메모리 덤프 분석 시 닷넷 메서드의 호출 인자 값 확인
; https://www.sysnet.pe.kr/2/0/11451

디버깅 기술: 128. windbg - x64 환경에서 닷넷 예외가 발생한 경우 인자를 확인할 수 없었던 사례
; https://www.sysnet.pe.kr/2/0/11991

디버깅 기술: 139. windbg - x64 덤프 분석 시 메서드의 인자 또는 로컬 변수의 값을 확인하는 방법
; https://www.sysnet.pe.kr/2/0/12069

디버깅 기술: 172. windbg - 파일 열기 시점에 bp를 걸어 파일명 알아내는 방법(Managed/Unmanaged)
; https://www.sysnet.pe.kr/2/0/12377

디버깅 기술: 181. windbg - 콜 스택의 "Call Site" 오프셋 값이 가리키는 위치
; https://www.sysnet.pe.kr/2/0/12750




windbg - x64 덤프 분석 시 메서드의 인자 또는 로컬 변수의 값을 확인하는 방법

전에도 관련 주제로 글을 쓴 적이 있는데요.

x64 콜 스택 인자 추적과 windbg의 Child-SP, RetAddr, Args to Child 값 확인
; https://www.sysnet.pe.kr/2/0/10832

windbg - x64 역어셈블 코드에서 닷넷 메서드 호출의 인자를 확인하는 방법
; https://www.sysnet.pe.kr/2/0/11348

windbg - x64 SOS 확장의 !clrstack 명령어가 출력하는 Child SP 값의 의미
; https://www.sysnet.pe.kr/2/0/11349

그때는 직접 RSP의 값을 구해가면서, 또는 Child-SP 칼럼을 이용하면서 인자 값 추적을 했는데 이번에는 windbg의 ".frame" 명령어를 이용해 간단하게 해결해 보겠습니다. 우선 실습 예제를 정하고,

// x64 + Release 빌드

using System;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        string path = "c:\\temp\\test.txt";
        int argLen = args.Length;

        if (argLen >= 1)
        {
            path = args[0];
        }

        FileProcess(path);
    }

    private static void FileProcess(string filePath)
    {
        FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        Console.WriteLine(fs.Length);
        fs.Close();
    }
}

실행해서 예외가 발생했을 때 비주얼 스튜디오에서 "Call Stack" 창에 열거된 함수 목록 중,

stack_frame_dbg_1.png

예외 발생은 가장 상단의 WinIOError 메서드이지만, 가장 하단의 "Program.Main" 항목을 더블 클릭해서 해당 메서드를 호출한 시점의 문맥으로 전환했기 때문에 우측의 "Watch" 창에 "args", "argLen", "path" 변수가 정상적으로 값을 담게 됩니다.

만약 위의 상태에서 "Call Stack" 창의 "Program.FileProcess" 메서드를 더블 클릭하면 역시 그 호출 스택의 문맥으로 변환하므로,

stack_frame_dbg_2.png

현재 선택된 콜 스택 프레임을 가리키는 화살표가 표시되고 그와 함께 해당 프레임에 속하지 않은 인자, 지역 변수는 Watch 창에서 회색 처리됩니다.

바로 이런 식의 프레임 문맥 전환을 할 수 있는 windbg 명령어가 ".frame"입니다. (전환된 문맥을 다시 해제하려면 ".cxr" 명령을 사용합니다.)




그럼 저렇게 예외가 발생했을 때 뜬 덤프를,

C:\temp\ConsoleApp1\bin\Release> procdump -e -ma -x "c:\temp" "C:\temp\ConsoleApp1\bin\Release\ConsoleApp1.exe"

ProcDump v9.0 - Sysinternals process dump utility
Copyright (C) 2009-2017 Mark Russinovich and Andrew Richards
Sysinternals - www.sysinternals.com

Process:               ConsoleApp1.exe (3412)
CPU threshold:         n/a
Performance counter:   n/a
Commit threshold:      n/a
Threshold seconds:     n/a
Hung window check:     Disabled
Log debug strings:     Disabled
Exception monitor:     Unhandled
Exception filter:      [Includes]
                       *
                       [Excludes]
Terminate monitor:     Disabled
Cloning type:          Disabled
Concurrent limit:      n/a
Avoid outage:          n/a
Number of dumps:       1
Dump folder:           c:\temp\
Dump filename/mask:    PROCESSNAME_YYMMDD_HHMMSS
Queue to WER:          Disabled
Kill after dump:       Disabled


Press Ctrl-C to end monitoring without terminating the process.

[10:02:06] Exception: 04242420
[10:02:06] Exception: E0434352.CLR

Unhandled Exception: System.IO.FileNotFoundException: Could not find file 'c:\temp\test.txt'.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access)
   at Program.FileProcess(String filePath) in C:\temp\ConsoleApp1\bin\Release\ConsoleApp1\Program.cs:line 23
   at Program.Main(String[] args) in C:\temp\ConsoleApp1\bin\Release\ConsoleApp1\Program.cs:line 18
[10:02:06] Unhandled: E0434352.CLR
[10:02:06] Dump 1 initiated: c:\temp\ConsoleApp1.exe_191202_100206.dmp
[10:02:07] Dump 1 writing: Estimated dump file size is 96 MB.
[10:02:07] Dump 1 complete: 96 MB written in 0.1 seconds
[10:02:07] Dump count reached.

windbg에서 열어, 덤프 생성 시점의 Native call stack과 Managed call stack을 각각 다음과 같이 구할 수 있습니다.

0:000> k
 # Child-SP          RetAddr           Call Site
00 00000053`6eb3e780 00007ff9`faeba3f1 KERNELBASE!RaiseException+0x69
01 00000053`6eb3e860 00007ff9`faebb864 clr!RaiseTheExceptionInternalOnly+0x31f
02 00000053`6eb3e980 00007ff9`f7bbbeac clr!IL_Throw+0x114
03 00000053`6eb3eb30 00007ff9`f7c0701a mscorlib_ni+0x53beac
04 00000053`6eb3eb80 00007ff9`f7be3f1d mscorlib_ni+0x58701a
05 00000053`6eb3ec50 00007ff9`9b950922 mscorlib_ni+0x563f1d
06 00000053`6eb3ed00 00007ff9`9b9508c4 0x00007ff9`9b950922
07 00000053`6eb3ed40 00007ff9`faea6c53 0x00007ff9`9b9508c4
08 00000053`6eb3ed70 00007ff9`faea6b68 clr!CallDescrWorkerInternal+0x83
09 00000053`6eb3edb0 00007ff9`faea73d0 clr!CallDescrWorkerWithHandler+0x4e
0a 00000053`6eb3edf0 00007ff9`fb027002 clr!MethodDescCallSite::CallTargetWorker+0x102
0b 00000053`6eb3eef0 00007ff9`fb0279c3 clr!RunMain+0x25f
0c 00000053`6eb3f0d0 00007ff9`fb027877 clr!Assembly::ExecuteMainMethod+0xb7
0d 00000053`6eb3f3c0 00007ff9`fb0271c3 clr!SystemDomain::ExecuteMainMethod+0x643
0e 00000053`6eb3f9c0 00007ff9`fb027141 clr!ExecuteEXE+0x3f
0f 00000053`6eb3fa30 00007ff9`fb0285b4 clr!_CorExeMainInternal+0xb2
10 00000053`6eb3fac0 00007ff9`fc278c01 clr!CorExeMain+0x14
11 00000053`6eb3fb00 00007ff9`fd9ea56c mscoreei!CorExeMain+0x112
12 00000053`6eb3fb60 00007ffa`0b0f7bd4 mscoree!CorExeMain_Exported+0x6c
13 00000053`6eb3fb90 00007ffa`0c44ced1 kernel32!BaseThreadInitThunk+0x14
14 00000053`6eb3fbc0 00000000`00000000 ntdll!RtlUserThreadStart+0x21


0:000> .loadby sos clr

0:000> !clrstack
OS Thread Id: 0xa820 (0)
        Child SP               IP Call Site
000000536eb3ea48 00007ffa09f8a839 [HelperMethodFrame: 000000536eb3ea48] 
000000536eb3eb30 00007ff9f7bbbeac System.IO.__Error.WinIOError(Int32, System.String)
000000536eb3eb80 00007ff9f7c0701a System.IO.FileStream.Init(System.String, System.IO.FileMode, System.IO.FileAccess, Int32, Boolean, System.IO.FileShare, Int32, System.IO.FileOptions, SECURITY_ATTRIBUTES, System.String, Boolean, Boolean, Boolean)
000000536eb3ec50 00007ff9f7be3f1d System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess)
000000536eb3ed00 00007ff99b950922 Program.FileProcess(System.String) [c:\temp\ConsoleApp1\Program.cs @ 23]
000000536eb3ed40 00007ff99b9508c4 Program.Main(System.String[]) [c:\temp\ConsoleApp1\Program.cs @ 18]
000000536eb3ef58 00007ff9faea6c53 [GCFrame: 000000536eb3ef58] 

.frame 명령어는 native call stack의 '#' 칼럼 값을 필요로 하기 때문에 닷넷 메서드의 경우 k 명령어의 "RetAddr" 칼럼과 "!clrstack"의 "IP" 값을 이용해 적절하게 매칭해 구해야 합니다. (또는 간단하게 windbg가 자동으로 구해서 보여주는 Child-SP 값을 비교하면 됩니다.)

 # Child-SP          RetAddr           Call Site
...[생략]...
02 00000053`6eb3e980 00007ff9`f7bbbeac clr!IL_Throw+0x114
03 00000053`6eb3eb30 00007ff9`f7c0701a mscorlib_ni+0x53beac  ==>   System.IO.__Error.WinIOError(Int32, System.String))
04 00000053`6eb3eb80 00007ff9`f7be3f1d mscorlib_ni+0x58701a  ==>   System.IO.FileStream.Init
05 00000053`6eb3ec50 00007ff9`9b950922 mscorlib_ni+0x563f1d  ==>   System.IO.FileStream..ctor
06 00000053`6eb3ed00 00007ff9`9b9508c4 0x00007ff9`9b950922   ==>   Program.FileProcess
07 00000053`6eb3ed40 00007ff9`faea6c53 0x00007ff9`9b9508c4   ==>   Program.Main

따라서, Program.FileProcess 메서드의 문맥으로 전환하고 싶다면 다음과 같이 명령어를 수행하면 됩니다.

0:000> .frame /c /r 6
06 00000053`6eb3ed00 00007ff9`9b9508c4 0x00007ff9`9b950922
rax=0000000000000005 rbx=000000536eb3ee88 rcx=0000000000000050
rdx=000000536eb3e400 rsi=00000167136c2e20 rdi=00000167136c6008
rip=00007ff99b950922 rsp=000000536eb3ed00 rbp=000000536eb3ed90
 r8=00007ff9fb06197a  r9=0000000000000000 r10=0000000000000000
r11=0000000011a81750 r12=000000536eb3f110 r13=000000536eb3ee10
r14=000000536eb3ee88 r15=0000000000000004
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000200
00007ff9`9b950922 488bcf          mov     rcx,rdi

이렇게 문맥 전환이 되었을 때 가장 도움이 되는 값은 바로 rsp와 rip입니다. rip의 경우 sos.dll의 "!u" 명령어와 결합하면,

0:000> !u 00007ff99b950922
Normal JIT generated code
Program.FileProcess(System.String)
Begin 00007ff99b9508f0, size 58

c:\temp\ConsoleApp1\Program.cs @ 22:
00007ff9`9b9508f0 57              push    rdi
00007ff9`9b9508f1 56              push    rsi
00007ff9`9b9508f2 4883ec28        sub     rsp,28h
00007ff9`9b9508f6 488bf1          mov     rsi,rcx
00007ff9`9b9508f9 48b9384d72f7f97f0000 mov rcx,offset mscorlib_ni+0xa4d38 (00007ff9`f7724d38) (MT: System.IO.FileStream)
00007ff9`9b950903 e868c9565f      call    clr!JIT_NewCrossContext_Portable (00007ff9`faebd270)
00007ff9`9b950908 488bf8          mov     rdi,rax
00007ff9`9b95090b 488bcf          mov     rcx,rdi
00007ff9`9b95090e 488bd6          mov     rdx,rsi
00007ff9`9b950911 41b803000000    mov     r8d,3
00007ff9`9b950917 41b901000000    mov     r9d,1
00007ff9`9b95091d e876f9ffff      call    00007ff9`9b950298

c:\temp\ConsoleApp1\Program.cs @ 23:
>>> 00007ff9`9b950922 488bcf          mov     rcx,rdi
00007ff9`9b950925 e85627eeff      call    00007ff9`9b833080
00007ff9`9b95092a 488bc8          mov     rcx,rax
00007ff9`9b95092d e8ae20b25c      call    mscorlib_ni+0xdf29e0 (00007ff9`f84729e0) (System.Console.WriteLine(Int64), mdToken: 0000000006000b77)

c:\temp\ConsoleApp1\Program.cs @ 24:
00007ff9`9b950932 488bcf          mov     rcx,rdi
00007ff9`9b950935 48b8d030839bf97f0000 mov rax,7FF99B8330D0h
00007ff9`9b95093f 4883c428        add     rsp,28h
00007ff9`9b950943 5e              pop     rsi
00007ff9`9b950944 5f              pop     rdi
00007ff9`9b950945 48ffe0          jmp     rax

보는 바와 같이 해당 메서드의 전체 코드를 덤프하고 예외가 발생한 시점의 명령어(위에서는 call 00007ff9`9b950298) 바로 다음 명령어의 위치를 ">>>" 기호로 친절하게 알려줍니다.

또한 rsp 값(위에서는 000000536eb3ed00)을 통해 해당 메서드가 수행되기까지 쌓인 스택의 내용을 확인할 수 있습니다.

0:000> dq /c1 @rsp 
00000053`6eb3ed00  00000167`136c6008
00000053`6eb3ed08  00000167`136c2e20
00000053`6eb3ed10  00000000`00000003
00000053`6eb3ed18  00000000`00000001
00000053`6eb3ed20  00000053`6eb3ee10
00000053`6eb3ed28  00000167`136c2e08
00000053`6eb3ed30  00000053`6eb3ef58
00000053`6eb3ed38  00007ff9`9b9508c4
00000053`6eb3ed40  00000167`136c2e20
00000053`6eb3ed48  00000000`00000000
00000053`6eb3ed50  00000167`136c38dc
00000053`6eb3ed58  00000053`6eb3eb30
00000053`6eb3ed60  00000053`6eb3ee58
00000053`6eb3ed68  00007ff9`faea6c53
00000053`6eb3ed70  00000167`136c2e08
00000053`6eb3ed78  00007ff9`9b844148

재미있는 것은, sos.dll의 "!dso" 확장 명령어는 (현재 문맥의 rsp를 인지하지 않고) 덤프 시점의 rsp를 기준으로 닷넷 관련 객체를 덤프한다는 것입니다.

0:000> !dso
OS Thread Id: 0xa820 (0)
RSP/REG          Object           Name
rsi              00000167136c2e20 System.String    c:\temp\test.txt
rdi              00000167136c6008 System.IO.FileStream
000000536EB3E798 00000167136cc240 System.RuntimeType
000000536EB3E870 00000167136c7c58 System.IO.FileNotFoundException
000000536EB3E888 00000167136cc1b0 System.Text.StringBuilder
000000536EB3E898 00000167136cc1b0 System.Text.StringBuilder
000000536EB3E8D8 00000167136c50b8 System.Globalization.CultureInfo
000000536EB3E8E0 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3E908 00000167136c7c58 System.IO.FileNotFoundException
000000536EB3E960 00000167136c7c58 System.IO.FileNotFoundException
000000536EB3E968 00000167136c7c38 System.Object[]    (System.Object[])
000000536EB3E970 00000167136c7c58 System.IO.FileNotFoundException
000000536EB3E980 00000167136c50b8 System.Globalization.CultureInfo
000000536EB3E988 00000167136cc240 System.RuntimeType
000000536EB3E9A0 00000167136c7c58 System.IO.FileNotFoundException
000000536EB3E9C0 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3E9D8 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3EA10 00000167136c7c58 System.IO.FileNotFoundException
000000536EB3EA28 00000167136c50b8 System.Globalization.CultureInfo
000000536EB3EA30 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3EA88 00000167136c7c58 System.IO.FileNotFoundException
000000536EB3EA90 00000167136c7c38 System.Object[]    (System.Object[])
000000536EB3EA98 00000167136c7c58 System.IO.FileNotFoundException
000000536EB3EAA0 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3EB30 00000167136c50b8 System.Globalization.CultureInfo
000000536EB3EB38 00000167136cc070 System.String    Could not find file '{0}'.
000000536EB3EB40 00000167136c7c38 System.Object[]    (System.Object[])
000000536EB3EB70 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3EB88 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3EC10 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3EC18 00000167136c6008 System.IO.FileStream
000000536EB3EC38 00000167136c7690 System.String    test.txt
000000536EB3EC50 00000167136c6008 System.IO.FileStream
000000536EB3EC58 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3ECA0 00000167136c7690 System.String    test.txt
000000536EB3ECC0 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3ECD0 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3ECD8 00000167136c6008 System.IO.FileStream
000000536EB3ED00 00000167136c6008 System.IO.FileStream
000000536EB3ED08 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3ED28 00000167136c2e08 System.String[]
000000536EB3ED40 00000167136c2e20 System.String    c:\temp\test.txt
000000536EB3ED70 00000167136c2e08 System.String[]
000000536EB3EE58 00000167136c2e08 System.String[]
000000536EB3F0E0 00000167136c2e08 System.String[]
000000536EB3F0E8 00000167136c2e08 System.String[]

보는 바와 같이 .frame 명령어로 인해 rsp == "000000536EB3ED00"로 전환이 되었지만, !dso는 그것에 상관없이 스택 덤프를 하고 있으므로 중간에 "FileNotFoundException"이나 파일 경로를 담고 있는 System.String 객체등을 보여주게 됩니다.




아쉽게도 Program.FileProcess 메서드의 경우 rsp를 통해 직접적으로 알 수 있는 인자나 로컬 변수가 없습니다. 반면 운이 좋다면 System.IO.FileStream의 생성자처럼,

0:000> !u 00007ff9f7be3f1d
preJIT generated code
System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess)
Begin 00007ff9f7be3ea0, size 8b
00007ff9`f7be3ea0 55              push    rbp
00007ff9`f7be3ea1 4157            push    r15
00007ff9`f7be3ea3 4156            push    r14
00007ff9`f7be3ea5 57              push    rdi
00007ff9`f7be3ea6 56              push    rsi
00007ff9`f7be3ea7 53              push    rbx
00007ff9`f7be3ea8 4883ec78        sub     rsp,78h
00007ff9`f7be3eac 488dac24a0000000 lea     rbp,[rsp+0A0h]
00007ff9`f7be3eb4 488bf9          mov     rdi,rcx
00007ff9`f7be3eb7 488bf2          mov     rsi,rdx
00007ff9`f7be3eba 418bd8          mov     ebx,r8d
00007ff9`f7be3ebd 458bf1          mov     r14d,r9d
00007ff9`f7be3ec0 488bce          mov     rcx,rsi
00007ff9`f7be3ec3 90              nop
00007ff9`f7be3ec4 e8a72b0200      call    mscorlib_ni+0x586a70 (00007ff9`f7c06a70) (System.IO.Path.GetFileName(System.String), mdToken: 000000000600191a)
00007ff9`f7be3ec9 4c8bf8          mov     r15,rax
00007ff9`f7be3ecc b901000000      mov     ecx,1
00007ff9`f7be3ed1 90              nop
00007ff9`f7be3ed2 e8492c0200      call    mscorlib_ni+0x586b20 (00007ff9`f7c06b20) (System.IO.FileStream.GetSecAttrs(System.IO.FileShare), mdToken: 0000000006001854)
00007ff9`f7be3ed7 33c9            xor     ecx,ecx
00007ff9`f7be3ed9 894c2420        mov     dword ptr [rsp+20h],ecx
00007ff9`f7be3edd 894c2428        mov     dword ptr [rsp+28h],ecx
00007ff9`f7be3ee1 c744243001000000 mov     dword ptr [rsp+30h],1
00007ff9`f7be3ee9 c744243800100000 mov     dword ptr [rsp+38h],1000h
00007ff9`f7be3ef1 894c2440        mov     dword ptr [rsp+40h],ecx
00007ff9`f7be3ef5 4889442448      mov     qword ptr [rsp+48h],rax
00007ff9`f7be3efa 4c897c2450      mov     qword ptr [rsp+50h],r15
00007ff9`f7be3eff 894c2458        mov     dword ptr [rsp+58h],ecx
00007ff9`f7be3f03 894c2460        mov     dword ptr [rsp+60h],ecx
00007ff9`f7be3f07 894c2468        mov     dword ptr [rsp+68h],ecx
00007ff9`f7be3f0b 488bcf          mov     rcx,rdi
00007ff9`f7be3f0e 488bd6          mov     rdx,rsi
00007ff9`f7be3f11 448bc3          mov     r8d,ebx
00007ff9`f7be3f14 458bce          mov     r9d,r14d
00007ff9`f7be3f17 ff156310b4ff    call    qword ptr [mscorlib_ni+0xa4f80 (00007ff9`f7724f80)]
>>> 00007ff9`f7be3f1d 90              nop
00007ff9`f7be3f1e 488d65d8        lea     rsp,[rbp-28h]
00007ff9`f7be3f22 5b              pop     rbx
00007ff9`f7be3f23 5e              pop     rsi
00007ff9`f7be3f24 5f              pop     rdi
00007ff9`f7be3f25 415e            pop     r14
00007ff9`f7be3f27 415f            pop     r15
00007ff9`f7be3f29 5d              pop     rbp
00007ff9`f7be3f2a c3              ret

"rsp + [offset]"의 연산을 하고 있는 코드가 있다면 인자 값이나 로컬 변수의 값 추적이 쉬워집니다. 즉, 아래와 같은 식의 연산을 보게 되면,

mov dword ptr [rsp+20h],ecx

우선 저 메서드가 수행될 시점의 rsp 값을 알아야 하는데 바로 이럴 때 ".frame" 명령어를 사용하면 되는 것입니다.

0:000> .cxr
Resetting default scope

0:000> .frame /c /r 5
05 00000053`6eb3ec50 00007ff9`9b950922 mscorlib_ni+0x563f1d
rax=0000000000000005 rbx=0000000000000003 rcx=0000000000000050
rdx=000000536eb3e400 rsi=00000167136c2e20 rdi=00000167136c6008
rip=00007ff9f7be3f1d rsp=000000536eb3ec50 rbp=000000536eb3ecf0
 r8=00007ff9fb06197a  r9=0000000000000000 r10=0000000000000000
r11=0000000011a81750 r12=000000536eb3f110 r13=000000536eb3ee10
r14=0000000000000001 r15=00000167136c7690
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000200
mscorlib_ni+0x563f1d:
00007ff9`f7be3f1d 90              nop

이로 인해 결국 다음의 코드 수행으로 인해 저장된 값들은,

00007ff9`f7be3ed9 894c2420        mov     dword ptr [rsp+20h],ecx
00007ff9`f7be3edd 894c2428        mov     dword ptr [rsp+28h],ecx
00007ff9`f7be3ee1 c744243001000000 mov     dword ptr [rsp+30h],1
00007ff9`f7be3ee9 c744243800100000 mov     dword ptr [rsp+38h],1000h
00007ff9`f7be3ef1 894c2440        mov     dword ptr [rsp+40h],ecx
00007ff9`f7be3ef5 4889442448      mov     qword ptr [rsp+48h],rax
00007ff9`f7be3efa 4c897c2450      mov     qword ptr [rsp+50h],r15
00007ff9`f7be3eff 894c2458        mov     dword ptr [rsp+58h],ecx
00007ff9`f7be3f03 894c2460        mov     dword ptr [rsp+60h],ecx
00007ff9`f7be3f07 894c2468        mov     dword ptr [rsp+68h],ecx

이렇게 간단하게 확인할 수 있습니다.

0:000> dq /c1 rsp+0x20 LA
00000053`6eb3ec70  00000000`00000000
00000053`6eb3ec78  00000000`00000000
00000053`6eb3ec80  00000000`00000001
00000053`6eb3ec88  00000000`00001000
00000053`6eb3ec90  00000000`00000000
00000053`6eb3ec98  00000000`00000000
00000053`6eb3eca0  00000167`136c7690
00000053`6eb3eca8  00000000`00000000
00000053`6eb3ecb0  00000000`00000000
00000053`6eb3ecb8  00000167`00000000

실제로 FileStream 생성자를 .NET Reflector로 보면,

[SecuritySafeCritical]
public FileStream(string path, FileMode mode, FileAccess access)
    : this(path, mode, access, FileShare.Read, 4096, FileOptions.None, Path.GetFileName(path), bFromProxy: false)
{
}

7번째 인자(rsp+48h)가 Path.GetFileName(path)이므로 System.String 참조 객체가 전달되는데, 그렇다면 당연히 sos.dll의 "!do" 확장 명령어로 보면,

0:000> !do 00000167`136c7690
Name:        System.String
MethodTable: 00007ff9f76a59c0
EEClass:     00007ff9f7682ec0
Size:        42(0x2a) bytes
File:        C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:      test.txt
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ff9f76a85a0  4000285        8         System.Int32  1 instance                8 m_stringLength
00007ff9f76a6838  4000286        c          System.Char  1 instance               74 m_firstChar
00007ff9f76a59c0  400028a       e8        System.String  0   shared           static Empty
                                 >> Domain:Value  0000016711a15f20:NotInit  <<

위와 같이 "test.txt" 파일명이 전달된 것을 확인할 수 있습니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 12/19/2019]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 151  152  153  154  155  156  157  [158]  159  160  161  162  163  164  165  ...
NoWriterDateCnt.TitleFile(s)
1099정성태8/15/201128240오류 유형: 132. 어느 순간 갑자기 접속이 안 되는 TFS 서버
1098정성태8/15/201150294웹: 24. 네이버는 어떻게 로그인 처리를 할까요? [2]
1097정성태8/15/201121585.NET Framework: 235. 메서드의 메타 데이터 토큰 값으로 클래스를 찾아내는 방법
1096정성태8/15/201125704디버깅 기술: 42. Watson Bucket 정보를 이용한 CLR 응용 프로그램 예외 분석 - (2)
1095정성태8/14/201126143디버깅 기술: 41. Windbg - 비정상 종료된 닷넷 프로그램의 StackTrace에서 보이는 offset 값 의미
1094정성태8/14/201130548오류 유형: 131. Fiddler가 강제 종료된 경우, 웹 사이트 방문이 안되는 현상
1093정성태7/27/201124146오류 유형: 130. Unable to connect to the Microsoft Visual Studio Remote Debugging Monitor ... Access is denied.
1092정성태7/22/201126573Team Foundation Server: 46. 코드 이외의 파일에 대해 소스 제어에서 제외시키는 방법
1091정성태7/21/201125575개발 환경 구성: 128. WP7 Emulator 실행 시 audiodg.exe의 CPU 소모율 증가 [2]
1089정성태7/18/201131157.NET Framework: 234. 왜? Button 컨트롤에는 MouseDown/MouseUp 이벤트가 발생하지 않을까요?파일 다운로드1
1088정성태7/16/201124235.NET Framework: 233. Entity Framework 4.1 - 윈도우 폰 7에서의 CodeFirst 순환 참조 문제파일 다운로드1
1087정성태7/15/201126898.NET Framework: 232. Entity Framework 4.1 - CodeFirst 개체의 직렬화 시 순환 참조 해결하는 방법 - 두 번째 이야기파일 다운로드1
1086정성태7/14/201128336.NET Framework: 231. Entity Framework 4.1 - CodeFirst 개체의 직렬화 시 순환 참조 해결하는 방법 [1]파일 다운로드1
1085정성태7/14/201128854.NET Framework: 230. Entity Framework 4.1 - Code First + WCF 서비스 시 EndpointNotFoundException 오류 - 두 번째 이야기파일 다운로드1
1084정성태7/11/201134124.NET Framework: 229. SQL 서버 - DB 테이블의 데이터 변경에 대한 알림 처리 [4]파일 다운로드1
1083정성태7/11/201128145.NET Framework: 228. Entity Framework 4.1 - Code First + WCF 서비스 시 EndpointNotFoundException 오류
1082정성태7/10/201127707.NET Framework: 227. basicHttpBinding + 사용자 정의 인증 구현 [2]파일 다운로드1
1081정성태7/9/201127019VC++: 53. Windows 7에서 gcc.exe 실행 시 Access denied 오류 [2]
1080정성태7/8/201125516웹: 23. Sysnet 웹 사이트의 HTML5 변환 기록 - 두 번째 이야기파일 다운로드1
1079정성태7/6/201129957오류 유형: 129. Hyper-V + Realtek 랜카드가 설치된 시스템의 BSOD 현상 [2]
1078정성태7/5/201137461VC++: 52. Chromium 컴파일하는 방법 [2]
1077정성태6/24/201135088.NET Framework: 226. HttpWebRequest 타입의 HaveResponse 속성 이야기파일 다운로드1
1076정성태6/23/201129245오류 유형: 128. SQL Express - User Instance 옵션을 사용한 경우 발생하는 오류 메시지 유형 2가지
1075정성태6/21/201124849VS.NET IDE: 69. 윈폰 프로젝트에서 WCF 서비스 참조할 때 Reference.cs 파일이 비어있는 경우
1074정성태6/20/201124944.NET Framework: 225. 닷넷 네트워크 라이브러리의 트레이스 기능파일 다운로드1
1073정성태6/20/201127169오류 유형: 127. Visual Studio에서 WCF 서비스의 이름 변경 시 발생할 수 있는 오류
... 151  152  153  154  155  156  157  [158]  159  160  161  162  163  164  165  ...