Microsoft MVP성태의 닷넷 이야기
글쓴 사람
홈페이지
첨부 파일
 

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@outlook.com

비밀번호

댓글 쓴 사람
 




1  2  3  4  5  6  7  8  9  [10]  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
12039정성태10/22/2019670스크립트: 16. cmd.exe의 for 문에서는 ERRORLEVEL이 설정되지 않는 문제
12038정성태10/17/2019541오류 유형: 570. SQL Server 2019 RC1 - SQL Client Connectivity SDK 설치 오류
12037정성태10/15/2019858.NET Framework: 867. C# - Encoding.Default 값을 바꿀 수 있을까요?파일 다운로드1
12036정성태10/21/20191512.NET Framework: 866. C# - 고성능이 필요한 환경에서 GC가 발생하지 않는 네이티브 힙 사용파일 다운로드1
12035정성태10/13/2019737개발 환경 구성: 461. C# 8.0의 #nulable 관련 특성을 .NET Framework 프로젝트에서 사용하는 방법파일 다운로드1
12034정성태1/31/20201009개발 환경 구성: 460. .NET Core 환경에서 (프로젝트가 아닌) C# 코드 파일을 입력으로 컴파일하는 방법 [1]
12033정성태10/11/20191446개발 환경 구성: 459. .NET Framework 프로젝트에서 C# 8.0 컴파일러를 사용하는 방법
12032정성태11/25/2019901.NET Framework: 865. .NET Core 2.2/3.0 웹 프로젝트를 IIS에서 호스팅(Inproc, out-of-proc)하는 방법 - AspNetCoreModuleV2 소개
12031정성태10/7/2019561오류 유형: 569. Azure Site Extension 업그레이드 시 "System.IO.IOException: There is not enough space on the disk" 예외 발생
12030정성태11/12/20192304.NET Framework: 864. .NET Conf 2019 Korea - "닷넷 17년의 변화 정리 및 닷넷 코어 3.0" 발표 자료 [1]파일 다운로드1
12029정성태9/27/2019669제니퍼 .NET: 29. Jennifersoft provides a trial promotion on its APM solution such as JENNIFER, PHP, and .NET in 2019 and shares the examples of their application.
12028정성태9/26/2019810.NET Framework: 863. C# - Thread.Suspend 호출 시 응용 프로그램 hang 현상을 해결하기 위한 시도파일 다운로드1
12027정성태9/26/2019508오류 유형: 568. Consider app.config remapping of assembly "..." from Version "..." [...] to Version "..." [...] to solve conflict and get rid of warning.
12026정성태9/26/2019695.NET Framework: 862. C# - Active Directory의 LDAP 경로 및 정보 조회
12025정성태9/25/2019807제니퍼 .NET: 28. APM 솔루션 제니퍼, PHP, .NET 무료 사용 프로모션 2019 및 적용 사례 (8)
12024정성태9/20/2019923.NET Framework: 861. HttpClient와 HttpClientHandler의 관계
12023정성태9/19/2019861.NET Framework: 860. ServicePointManager.DefaultConnectionLimit와 HttpClient의 관계파일 다운로드1
12022정성태9/12/20191857개발 환경 구성: 458. C# 8.0 (Preview) 신규 문법을 위한 개발 환경 구성 [3]
12021정성태7/1/20204576도서: 시작하세요! C# 8.0 프로그래밍 [3]
12020정성태9/11/2019895VC++: 134. SYSTEMTIME 값 기준으로 특정 시간이 지났는지를 판단하는 함수
12019정성태9/11/2019709Linux: 23. .NET Core + 리눅스 환경에서 Environment.CurrentDirectory 접근 시 주의 사항
12018정성태9/25/2019611오류 유형: 567. IIS - Unrecognized attribute 'targetFramework'. Note that attribute names are case-sensitive. (D:\lowSite4\web.config line 11)
12017정성태9/11/2019988오류 유형: 566. 비주얼 스튜디오 - Failed to register URL "http://localhost:6879/" for site "..." application "/". Error description: Access is denied. (0x80070005)
12016정성태9/5/20191575오류 유형: 565. git fetch - warning: 'C:\ProgramData/Git/config' has a dubious owner: '(unknown)'.
12015정성태9/3/20192368개발 환경 구성: 457. 윈도우 응용 프로그램의 Socket 연결 시 time-out 시간 제어
12014정성태6/23/20201237개발 환경 구성: 456. 명령행에서 AWS, Azure 등의 원격 저장소에 파일 관리하는 방법 - cyberduck/duck 소개
1  2  3  4  5  6  7  8  9  [10]  11  12  13  14  15  ...