Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석 - OracleCommand.ExecuteReader에서 OpsSql.Prepare2 PInvoke 호출 분석

지난 경험을 바탕으로,

windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석
; https://www.sysnet.pe.kr/2/0/12065

PInvoke에서 OpsSql.Prepare2의 경우에도 파악해 단순히 기록 차원으로 남깁니다. 우선 이를 위해 간단한 예제를 만들어,

using Oracle.DataAccess.Client;
using System;
using System.Reflection;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            SetOdpnetPath();

            string connectionString = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=testsrv)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE)));User Id=hrtest;Password=hrtest;";

            using (OracleConnection oracleConnection = new OracleConnection(connectionString))
            {
                oracleConnection.Open();

                OracleCommand cmd = new OracleCommand();
                cmd.Connection = oracleConnection;
                cmd.CommandText = "SELECT * FROM mytable WHERE NAME = :NAME";
                cmd.CommandTimeout = 30;
                cmd.BindByName = true;

                cmd.Parameters.Add(":NAME", "test");
                Console.WriteLine("Debug...");
                Console.ReadLine();

                cmd.ExecuteReader();

                oracleConnection.Close();
            }

            Console.WriteLine();
        }
    }
}

Console.ReadLine 시점에 덤프를 떠서 windbg로 열어 봅니다. Reflection 도구 등으로 Oracle.DataAccess.Client.OracleCommand.ExecuteReader의 소스 코드를 살펴보면,

public new OracleDataReader ExecuteReader()
{
    if (OraTrace.m_TraceLevel != 0u)
    {
        OraTrace.Trace(1u, new string[]
        {
            " (ENTRY) OracleCommand::ExecuteReader()\n"
        });
    }
    OracleDataReader result = this.ExecuteReader(true, false, CommandBehavior.Default);
    if (OraTrace.m_TraceLevel != 0u)
    {
        OraTrace.Trace(1u, new string[]
        {
            " (EXIT)  OracleCommand::ExecuteReader()\n"
        });
    }
    return result;
}

OraTrace.m_TraceLevel에 따라 앞뒤로 Trace 메서드가 실행되는 것을 볼 수 있습니다. 재미를 위해, m_TraceLevel이 실행 중에 어떤 값을 가지고 있는지 확인해 볼까요?

windbg - 닷넷 메모리 덤프에서 정적(static) 필드 값을 조사하는 방법
; https://www.sysnet.pe.kr/2/0/11487

위의 글에 설명한대로 해당 타입의 EEClass를 먼저 구하고,

0:000> !name2ee *!Oracle.DataAccess.Client.OraTrace
...[생략]...
Module:      00007ff99b855bc8
Assembly:    Oracle.DataAccess.dll
Token:       0000000002000109
MethodTable: 00007ff99ba11b98
EEClass:     00007ff99b9f7b50
Name:        Oracle.DataAccess.Client.OraTrace
...[생략]...

덤프하면 출력에 m_TraceLevel의 값을 볼 수 있습니다.

0:000> !DumpClass /d 00007ff99b9f7b50
Class Name:      Oracle.DataAccess.Client.OraTrace
mdToken:         0000000002000109
File:            C:\temp\ConsoleApp1\ConsoleApp1\bin\Debug\Oracle.DataAccess.dll
Parent Class:    00007ff9f7682f68
Module:          00007ff99b855bc8
Method Table:    00007ff99ba11b98
Vtable Slots:    4
Total Method Slots:  6
Class Attributes:    100000  
Transparency:        Transparent
NumInstanceFields:   0
NumStaticFields:     1f
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ff9f76ab698  400080f      49c       System.Boolean  1   static                0 m_RegistryRead
00007ff9f76a59c0  4000810      4a0        System.String  0   static 0000025919a41420 m_oraOpsDllPath
00007ff9f7720ab0  4000811      444        System.UInt32  1   static                0 m_TraceLevel
00007ff9f7720ab0  4000812      448        System.UInt32  1   static                0 m_TraceOption
00007ff9f7720ab0  4000813      44c        System.UInt32  1   static             4096 m_udtCacheSize
00007ff9f76a85a0  4000814      450         System.Int32  1   static                0 m_StmtCacheSize
00007ff9f7720ab0  4000815      454        System.UInt32  1   static                1 m_checkConStatus
00007ff9f7720ab0  4000816      458        System.UInt32  1   static                0 m_dynamicEnlist
00007ff9f76a85a0  4000817      45c         System.Int32  1   static           131072 m_FetchSize
00007ff9f76a85a0  4000818      460         System.Int32  1   static                0 m_ociEvents
00007ff9f76a85a0  4000819      464         System.Int32  1   static                1 m_stmtCacheWithUdts
...[생략]...
00007ff9f76a85a0  400082b      498         System.Int32  1   static                1 m_fetchArrayPooling
00007ff9f76ab698  400082c      49e       System.Boolean  1   static                0 m_configSectionRead
00007ff9f76a5dd8  400082d      4c8        System.Object  0   static 0000025919a4c968 m_regReadSync

보는 바와 같이 0이군요. ^^




이후 this.ExecuteReader() 내부로 들어가 OpsSql.Prepare2를 호출해 native 코드 내부로 디버깅을 진행해 보면,

// ...[생략]...
if (this.m_addParam && this.m_parameters != null)
{
    num5 = this.m_parameters.Count;
    if (num5 > 0 && (this.m_addToStmtCache || this.m_pOpoPrmCtx == null || this.m_pOpoPrmCtx->NumValCtxElems < num5))
    {
        IntPtr zero2 = IntPtr.Zero;

        // 최초 호출에는 ptr == null이어서, 6번째 인자 m_pooledCmdText 전달
        // 이후에는 pNewCommandText != null이어서, null 전달
        try
        {
            bool flag3 = ptr != null && ptr->pNewCommandText != IntPtr.Zero;
            num4 = OpsSql.Prepare2(this.m_opsConCtx, ref this.m_opsErrCtx, ref this.m_opsSqlCtx, ref this.m_opsDacCtx, ref this.m_pOpoSqlValCtx, flag3 ? null : this.m_pooledCmdText, ref zero2, ref ptr, num5);
        }
        catch (Exception ex)
        {
            if (OraTrace.m_TraceLevel != 0u)
            {
                OraTrace.TraceExceptionInfo(ex);
            }
            num4 = ErrRes.INT_ERR;
            throw;
        }
        finally
        {
            this.m_executeScalar = false;
            if (zero2 != IntPtr.Zero)
            {
                try
                {
                    Marshal.FreeCoTaskMem(zero2);
                }
                catch (Exception ex2)
                {
                    if (OraTrace.m_TraceLevel != 0u)
                    {
                        OraTrace.TraceExceptionInfo(ex2);
                    }
                }
            }
...[생략]...

다음과 같은 callstack 상태까지 옵니다.

0:000> !clrstack
OS Thread Id: 0x5e58 (0)
        Child SP               IP Call Site
000000759992eac8 00000001800237a0 [InlinedCallFrame: 000000759992eac8] Oracle.DataAccess.Client.OpsSql.Prepare2(IntPtr, IntPtr ByRef, IntPtr ByRef, IntPtr ByRef, Oracle.DataAccess.Client.OpoSqlValCtx* ByRef, System.String, IntPtr ByRef, Oracle.DataAccess.Client.OpoMetValCtx* ByRef, Int32)
                  == OraOps11w!OpsSqlPrepare2
000000759992eac8 00007ff99b97c99a [InlinedCallFrame: 000000759992eac8] Oracle.DataAccess.Client.OpsSql.Prepare2(IntPtr, IntPtr ByRef, IntPtr ByRef, IntPtr ByRef, Oracle.DataAccess.Client.OpoSqlValCtx* ByRef, System.String, IntPtr ByRef, Oracle.DataAccess.Client.OpoMetValCtx* ByRef, Int32)
000000759992ea70 00007ff99b97c99a DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr, IntPtr ByRef, IntPtr ByRef, IntPtr ByRef, Oracle.DataAccess.Client.OpoSqlValCtx* ByRef, System.String, IntPtr ByRef, Oracle.DataAccess.Client.OpoMetValCtx* ByRef, Int32)
000000759992eb90 00007ff99b979fbe Oracle.DataAccess.Client.OracleCommand.ExecuteReader(Boolean, Boolean, System.Data.CommandBehavior)
000000759992ed50 00007ff99b97933b Oracle.DataAccess.Client.OracleCommand.ExecuteReader()
000000759992ed90 00007ff99b9616b9 ConsoleApp1.Program.Main(System.String[]) [C:\temp\ConsoleApp1\ConsoleApp1\Program.cs @ 55]
000000759992f048 00007ff9faea6c53 [GCFrame: 000000759992f048] 

이 시점에 "windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석" 글에서 다룬 것을 그대로 적용해 pinvoke 층의 분석을 할 수 있습니다. 다음은 그 결과이고,

00000075`9992ea68 00007ff99b97c99a return to PInvoke frame of OraOps11w!OpsSqlPrepare2
00000075`9992ea70 0000025919addbe0 // [rsp + 0h] 4개 IntPtr == garbage
00000075`9992ea78 0023025917fe3460 // IntPtr ByRef == garbage
00000075`9992ea80 000000759992ef00 // IntPtr ByRef == garbage
00000075`9992ea88 000000759992ef78 // IntPtr ByRef == garbage
00000075`9992ea90 0000025919addbe8 // [rsp + 20h] == Oracle.DataAccess.Client.OpoSqlValCtx* ByRef
00000075`9992ea98 0000000000000000 // [rsp + 28h] == System.String
00000075`9992eaa0 000000759992ec90 // [rsp + 30h] == IntPtr ByRef
00000075`9992eaa8 000000759992ec98 // [rsp + 38h] == Oracle.DataAccess.Client.OpoMetValCtx* ByRef
00000075`9992eab0 0000000000000001 // [rsp + 40h] == Int32
00000075`9992eab8 000000759992f200 
00000075`9992eac0 00002b6d7a3108bc 
00000075`9992eac8 00007ff9fb66e9f0 clr!InlinedCallFrame::`vftable'
00000075`9992ead0 000000759992f048 
00000075`9992ead8 00007ff99ba1f920 // [rbp - a8h] == [rbp - 80h] == 00007ff99ba1f920
00000075`9992eae0 00007ff99ba1f920 // [rbp - a0h]
00000075`9992eae8 000000759992ea70 // [rbp - 98h] == rsp 
00000075`9992eaf0 00007ff99b97c99a // [rbp - 90h] return of OraOps11w!OpsSqlPrepare2
00000075`9992eaf8 000000759992eb80 // [rbp - 88h] == rbp
00000075`9992eb00 00007ff99ba1f920 // [rbp - 80h] == [rbp - a8h]
00000075`9992eb08 0000025918022140 // [rbp - 78h]  
00000075`9992eb10 000000759992ec98 // [rbp - 70h] == pinvoke frame에 전달된 8번째 변수
00000075`9992eb18 000000759992ec90 // [rbp - 68h] == pinvoke frame에 전달된 7번째 변수
00000075`9992eb20 0000000000000000 // [rbp - 60h] == pinvoke frame에 전달된 6번째 변수
00000075`9992eb28 0000025919addbe8 // [rbp - 58h] == pinvoke frame에 전달된 5번째 변수
00000075`9992eb30 0000025919addbe0 // [rbp - 50h] // pinvoke frame의 4번째 인자
00000075`9992eb38 0000025919addbd8 // [rbp - 48h] // pinvoke frame의 3번째 인자
00000075`9992eb40 0000025919addbf0 // [rbp - 40h] // pinvoke frame의 2번째 인자 백업 이후 OpsSqlPrepare2의 두 번째 인자(rdx)로 전달
00000075`9992eb48 000000759992ef78 // push rbx [rbp - 38h]
00000075`9992eb50 0000000000000000 // push rsi [rbp - 30h]
00000075`9992eb58 000000759992ed08 // push rdi [rbp - 28h]
00000075`9992eb60 000000759992f200 // push r12 [rbp - 20h]
00000075`9992eb68 000000759992ef00 // push r13 [rbp - 18h]
00000075`9992eb70 000000759992ef78 // push r14 [rbp - 10h]
00000075`9992eb78 0000000000000004 // push r15 [rbp - 8h]
00000075`9992eb80 000000759992ed40 // push rbp == [pinvoke rbp + 0]
00000075`9992eb88 00007ff99b979fbe // return to Oracle.DataAccess.Client.OracleCommand.ExecuteReader
                                   // Pinvoke 층 호출 후 rsp 위치
00000075`9992eb90 0000025919addc50 // [pinvoke rbp + 10h] == [ExecuteReader rsp + 0h]  == garbage
                                   // Pinvoke 층 호출 전 rsp 위치
00000075`9992eb98 00000259324e0420 // [pinvoke rbp + 18h] == [ExecuteReader rsp + 8h]  == garbage
00000075`9992eba0 0000000007ffffff // [pinvoke rbp + 20h] == [ExecuteReader rsp + 10h] == garbage
00000075`9992eba8 00007ff99b8594e0 // [pinvoke rbp + 28h] == [ExecuteReader rsp + 18h] == garbage
00000075`9992ebb0 0000025919addbe8 // [pinvoke rbp + 30h] == [ExecuteReader rsp + 20h] pinvoke frame에 전달되는 5번째 변수
00000075`9992ebb8 0000000000000000 // [pinvoke rbp + 38h] == [ExecuteReader rsp + 28h] pinvoke frame에 전달되는 6번째 변수
00000075`9992ebc0 000000759992ec90 // [pinvoke rbp + 40h] == [ExecuteReader rsp + 30h] pinvoke frame에 전달되는 7번째 변수
00000075`9992ebc8 000000759992ec98 // [pinvoke rbp + 48h] == [ExecuteReader rsp + 38h] pinvoke frame에 전달되는 8번째 변수
00000075`9992ebd0 0000007500000001 // [pinvoke rbp + 50h] == [ExecuteReader rsp + 40h] pinvoke frame에 전달되는 9번째 변수
00000075`9992ebd8 0000025919adde38
00000075`9992ebe0 0000000000000000 
00000075`9992ebe8 000000759992f200 
00000075`9992ebf0 000000759992ef00 
00000075`9992ebf8 000000759992ef78 
00000075`9992ec00 0000025918022140 
00000075`9992ec08 00007ff9f7c12977 
00000075`9992ec10 00002b6d7a3108bc 
00000075`9992ec18 000000759992eb90 
00000075`9992ec20 00002b6d7a3108bc 
00000075`9992ec28 00007ff9fb66e9f0 
00000075`9992ec30 000000759992f048 
00000075`9992ec38 0000000000000000 
00000075`9992ec40 00007ff4b8ca0018 
00000075`9992ec48 000000759992eb90 
00000075`9992ec50 0000000000000000 
00000075`9992ec58 000000759992ed40 
00000075`9992ec60 0000000000000000 
00000075`9992ec68 0000000000000000 
00000075`9992ec70 0000000000000000 
00000075`9992ec78 0000000000000000 
00000075`9992ec80 0000000000000000 
00000075`9992ec88 0000025918022140 
00000075`9992ec90 0000000000000000 
00000075`9992ec98 00000259324e0260 // ptr [rbp-0A8h]
00000075`9992eca0 0000000100000000 
00000075`9992eca8 0000000100000001 
00000075`9992ecb0 0000000000000000 
00000075`9992ecb8 0000000000000000 
00000075`9992ecc0 0000000000000000 
00000075`9992ecc8 0000000000000000 
00000075`9992ecd0 0000000000000001 
00000075`9992ecd8 0000000000000000 
00000075`9992ece0 0000000000000000 
00000075`9992ece8 0000000000000000 
00000075`9992ecf0 0000000000000000 
00000075`9992ecf8 0000000000000000 
00000075`9992ed00 0000000000000000 
00000075`9992ed08 000000759992ef78 // push rbx
00000075`9992ed10 0000025919addb50 // push rsi
00000075`9992ed18 000000759992ee40 // push rdi
00000075`9992ed20 000000759992f200 // push r12
00000075`9992ed28 000000759992ef00 // push r13
00000075`9992ed30 000000759992ef78 // push r14  == [rbp - 10h]
00000075`9992ed38 0000000000000004 // push r15
00000075`9992ed40 000000759992ee50 // push rbp  == [rbp + 0h]
00000075`9992ed48 00007ff99b97933b // return to ExecuteReader() 
00000075`9992ed50 0000025919addb50 // [rbp + 10h] == Oracle.DataAccess.Client.OracleCommand
00000075`9992ed58 00007ff900000001 
00000075`9992ed60 0000025919addb50 
00000075`9992ed68 0000007500000000 

아래의 코드 분석을 바탕으로 알아낸 것입니다. (!U 명령은 sos.dll이 제공합니다.)

0:000> !U /d 00007ff99b97c99a
Normal JIT generated code
DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr, IntPtr ByRef, IntPtr ByRef, IntPtr ByRef, Oracle.DataAccess.Client.OpoSqlValCtx* ByRef, System.String, IntPtr ByRef, Oracle.DataAccess.Client.OpoMetValCtx* ByRef, Int32)
Begin 00007ff99b97c890, size 141
00007ff9`9b97c890 55              push    rbp
00007ff9`9b97c891 4157            push    r15
00007ff9`9b97c893 4156            push    r14
00007ff9`9b97c895 4155            push    r13
00007ff9`9b97c897 4154            push    r12
00007ff9`9b97c899 57              push    rdi
00007ff9`9b97c89a 56              push    rsi
00007ff9`9b97c89b 53              push    rbx
00007ff9`9b97c89c 4881ecd8000000  sub     rsp,0D8h
00007ff9`9b97c8a3 488dac2410010000 lea     rbp,[rsp+110h]  // rsp == 00000075`9992ea70 + 0x110 == 00000075`9992eb80
00007ff9`9b97c8ab 4c895580        mov     qword ptr [rbp-80h],r10
00007ff9`9b97c8af 488bf1          mov     rsi,rcx
00007ff9`9b97c8b2 488d7d90        lea     rdi,[rbp-70h]
00007ff9`9b97c8b6 b90e000000      mov     ecx,0Eh
00007ff9`9b97c8bb 33c0            xor     eax,eax
00007ff9`9b97c8bd f3ab            rep stos dword ptr [rdi]
00007ff9`9b97c8bf 488bce          mov     rcx,rsi
00007ff9`9b97c8c2 4c8bf1          mov     r14,rcx
00007ff9`9b97c8c5 488bf2          mov     rsi,rdx
00007ff9`9b97c8c8 498bf8          mov     rdi,r8
00007ff9`9b97c8cb 498bd9          mov     rbx,r9
00007ff9`9b97c8ce 4c8b7d38        mov     r15,qword ptr [rbp+38h] // == pinvoke frame에 전달된 6번째 변수
00007ff9`9b97c8d2 4c8b6540        mov     r12,qword ptr [rbp+40h] // == pinvoke frame에 전달된 7번째 변수
00007ff9`9b97c8d6 4c8b6d48        mov     r13,qword ptr [rbp+48h] // == pinvoke frame에 전달된 8번째 변수
00007ff9`9b97c8da 488d8d48ffffff  lea     rcx,[rbp-0B8h]
00007ff9`9b97c8e1 498bd2          mov     rdx,r10
00007ff9`9b97c8e4 e85785525f      call    clr!JIT_InitPInvokeFrame (00007ff9`faea4e40)
00007ff9`9b97c8e9 488bcc          mov     rcx,rsp
00007ff9`9b97c8ec 48898d68ffffff  mov     qword ptr [rbp-98h],rcx
00007ff9`9b97c8f3 488bcd          mov     rcx,rbp
00007ff9`9b97c8f6 48898d78ffffff  mov     qword ptr [rbp-88h],rcx
00007ff9`9b97c8fd 488d8d48ffffff  lea     rcx,[rbp-0B8h]
00007ff9`9b97c904 48894810        mov     qword ptr [rax+10h],rcx
00007ff9`9b97c908 498bce          mov     rcx,r14 // OraOps11w!OpsSqlPrepare2 전달할 인자
00007ff9`9b97c90b 488975c0        mov     qword ptr [rbp-40h],rsi
00007ff9`9b97c90f 48897db8        mov     qword ptr [rbp-48h],rdi
00007ff9`9b97c913 48895db0        mov     qword ptr [rbp-50h],rbx
00007ff9`9b97c917 488b7530        mov     rsi,qword ptr [rbp+30h]
00007ff9`9b97c91b 488975a8        mov     qword ptr [rbp-58h],rsi
00007ff9`9b97c91f 33d2            xor     edx,edx
00007ff9`9b97c921 4d85ff          test    r15,r15
00007ff9`9b97c924 7408            je      00007ff9`9b97c92e
00007ff9`9b97c926 4c897da0        mov     qword ptr [rbp-60h],r15
00007ff9`9b97c92a 498d570c        lea     rdx,[r15+0Ch]
00007ff9`9b97c92e 4c896598        mov     qword ptr [rbp-68h],r12
00007ff9`9b97c932 4c896d90        mov     qword ptr [rbp-70h],r13
00007ff9`9b97c936 8b7550          mov     esi,dword ptr [rbp+50h]
00007ff9`9b97c939 4c63c6          movsxd  r8,esi
00007ff9`9b97c93c 4c8b4d80        mov     r9,qword ptr [rbp-80h]
00007ff9`9b97c940 4d8b4920        mov     r9,qword ptr [r9+20h]
00007ff9`9b97c944 4d8b11          mov     r10,qword ptr [r9]
00007ff9`9b97c947 4c8b4da8        mov     r9,qword ptr [rbp-58h]
00007ff9`9b97c94b 4c894c2420      mov     qword ptr [rsp+20h],r9
00007ff9`9b97c950 4889542428      mov     qword ptr [rsp+28h],rdx
00007ff9`9b97c955 4c89642430      mov     qword ptr [rsp+30h],r12
00007ff9`9b97c95a 4c896c2438      mov     qword ptr [rsp+38h],r13
00007ff9`9b97c95f 4c89442440      mov     qword ptr [rsp+40h],r8
00007ff9`9b97c964 488b55c0        mov     rdx,qword ptr [rbp-40h] // OraOps11w!OpsSqlPrepare2 전달할 인자
00007ff9`9b97c968 4c8b45b8        mov     r8,qword ptr [rbp-48h] // OraOps11w!OpsSqlPrepare2 전달할 인자
00007ff9`9b97c96c 4c8b4db0        mov     r9,qword ptr [rbp-50h] // OraOps11w!OpsSqlPrepare2 전달할 인자
00007ff9`9b97c970 41bb28000000    mov     r11d,28h
00007ff9`9b97c976 488b7580        mov     rsi,qword ptr [rbp-80h]
00007ff9`9b97c97a 4889b558ffffff  mov     qword ptr [rbp-0A8h],rsi
00007ff9`9b97c981 488d3512000000  lea     rsi,[00007ff9`9b97c99a]
00007ff9`9b97c988 4889b570ffffff  mov     qword ptr [rbp-90h],rsi  // 00007ff99b97c99a: return of OraOps11w!OpsSqlPrepare2
00007ff9`9b97c98f 48894588        mov     qword ptr [rbp-78h],rax  // rbp-78, == rax == 0000025918022140
00007ff9`9b97c993 c6400c00        mov     byte ptr [rax+0Ch],0
00007ff9`9b97c997 41ffd2          call    r10
>>> 00007ff9`9b97c99a 488b7588        mov     rsi,qword ptr [rbp-78h]
00007ff9`9b97c99e c6460c01        mov     byte ptr [rsi+0Ch],1
00007ff9`9b97c9a2 833db396f35f00  cmp     dword ptr [clr!g_TrapReturningThreads (00007ff9`fb8b605c)],0
00007ff9`9b97c9a9 7406            je      00007ff9`9b97c9b1
00007ff9`9b97c9ab ff1587a1f35f    call    qword ptr [clr!hlpDynamicFuncTable+0x68 (00007ff9`fb8b6b38)] (JitHelp: CORINFO_HELP_STOP_FOR_GC)
00007ff9`9b97c9b1 c6460c01        mov     byte ptr [rsi+0Ch],1
00007ff9`9b97c9b5 488b9550ffffff  mov     rdx,qword ptr [rbp-0B0h]
00007ff9`9b97c9bc 48895610        mov     qword ptr [rsi+10h],rdx
00007ff9`9b97c9c0 488d65c8        lea     rsp,[rbp-38h]
00007ff9`9b97c9c4 5b              pop     rbx
00007ff9`9b97c9c5 5e              pop     rsi
00007ff9`9b97c9c6 5f              pop     rdi
00007ff9`9b97c9c7 415c            pop     r12
00007ff9`9b97c9c9 415d            pop     r13
00007ff9`9b97c9cb 415e            pop     r14
00007ff9`9b97c9cd 415f            pop     r15
00007ff9`9b97c9cf 5d              pop     rbp
00007ff9`9b97c9d0 c3              ret

그리고 다음은 this.ExecuteReader() 측에서 OpsSql.Prepare2를 호출할 당시의 코드와 레지스터의 내용을 정리한 것입니다.

00007ff9`9b979eea 4883b9b000000000 cmp     qword ptr [rcx+0B0h],0
00007ff9`9b979ef2 7417            je      00007ff9`9b979f0b
00007ff9`9b979ef4 488b4d10        mov     rcx,qword ptr [rbp+10h]
00007ff9`9b979ef8 488b89b0000000  mov     rcx,qword ptr [rcx+0B0h]
00007ff9`9b979eff 8b4904          mov     ecx,dword ptr [rcx+4]
00007ff9`9b979f02 3b4d90          cmp     ecx,dword ptr [rbp-70h]
00007ff9`9b979f05 0f8df4000000    jge     00007ff9`9b979fff
00007ff9`9b979f0b 33c9            xor     ecx,ecx
00007ff9`9b979f0d 48898d50ffffff  mov     qword ptr [rbp-0B0h],rcx
00007ff9`9b979f14 4883bd58ffffff00 cmp     qword ptr [rbp-0A8h],0
00007ff9`9b979f1c 7417            je      00007ff9`9b979f35
00007ff9`9b979f1e 488b8d58ffffff  mov     rcx,qword ptr [rbp-0A8h] // rcx == 00000259324e0260
00007ff9`9b979f25 488b4940        mov     rcx,qword ptr [rcx+40h]  // rcx offset 40h == [00000259`324e02a0] == 00000259324fddb0
00007ff9`9b979f29 33d2            xor     edx,edx
00007ff9`9b979f2b e8b0fe295c      call    mscorlib_ni+0x599de0 (00007ff9`f7c19de0) (System.IntPtr.op_Inequality(IntPtr, IntPtr), mdToken: 0000000006000f9b)
00007ff9`9b979f30 0fb6c8          movzx   ecx,al
00007ff9`9b979f33 eb02            jmp     00007ff9`9b979f37
00007ff9`9b979f35 33c9            xor     ecx,ecx
00007ff9`9b979f37 0fb6c9          movzx   ecx,cl
00007ff9`9b979f3a 488b5510        mov     rdx,qword ptr [rbp+10h]] // rdx == [rbp + 10h] Oracle.DataAccess.Client.OracleCommand
00007ff9`9b979f3e 488b9280000000  mov     rdx,qword ptr [rdx+80h]   // OracleCommand offset 0x80 == m_opsConCtx
00007ff9`9b979f45 4c8b4510        mov     r8,qword ptr [rbp+10h]
00007ff9`9b979f49 4981c0a0000000  add     r8,0A0h                   // r8 == m_opsErrCtx
00007ff9`9b979f50 4c8b4d10        mov     r9,qword ptr [rbp+10h] 
00007ff9`9b979f54 4981c188000000  add     r9,88h
00007ff9`9b979f5b 488b4510        mov     rax,qword ptr [rbp+10h]
00007ff9`9b979f5f 480590000000    add     rax,90h
00007ff9`9b979f65 4c8b5510        mov     r10,qword ptr [rbp+10h]
00007ff9`9b979f69 4981c298000000  add     r10,98h
00007ff9`9b979f70 85c9            test    ecx,ecx
00007ff9`9b979f72 750d            jne     00007ff9`9b979f81
00007ff9`9b979f74 488bca          mov     rcx,rdx  // 
00007ff9`9b979f77 488b5510        mov     rdx,qword ptr [rbp+10h] // rdx == [rbp + 10h] Oracle.DataAccess.Client.OracleCommand
00007ff9`9b979f7b 4c8b5a48        mov     r11,qword ptr [rdx+48h] // OracleCommand + offset 0x48 == m_poooledCmdText
00007ff9`9b979f7f eb06            jmp     00007ff9`9b979f87
00007ff9`9b979f81 488bca          mov     rcx,rdx
00007ff9`9b979f84 4533db          xor     r11d,r11d
00007ff9`9b979f87 4c89542420      mov     qword ptr [rsp+20h],r10
00007ff9`9b979f8c 4c895c2428      mov     qword ptr [rsp+28h],r11
00007ff9`9b979f91 488d9550ffffff  lea     rdx,[rbp-0B0h]
00007ff9`9b979f98 4889542430      mov     qword ptr [rsp+30h],rdx
00007ff9`9b979f9d 488d9558ffffff  lea     rdx,[rbp-0A8h]
00007ff9`9b979fa4 4889542438      mov     qword ptr [rsp+38h],rdx
00007ff9`9b979fa9 8b5590          mov     edx,dword ptr [rbp-70h]
00007ff9`9b979fac 89542440        mov     dword ptr [rsp+40h],edx
00007ff9`9b979fb0 498bd0          mov     rdx,r8
00007ff9`9b979fb3 4d8bc1          mov     r8,r9
00007ff9`9b979fb6 4c8bc8          mov     r9,rax
00007ff9`9b979fb9 e87adaffff      call    00007ff9`9b977a38 (Oracle.DataAccess.Client.OpsSql.Prepare2(IntPtr, IntPtr ByRef, IntPtr ByRef, IntPtr ByRef, Oracle.DataAccess.Client.OpoSqlValCtx* ByRef, System.String, IntPtr ByRef, Oracle.DataAccess.Client.OpoMetValCtx* ByRef, Int32), mdToken: 00000000060002ee)
>>> 00007ff9`9b979fbe 894594          mov     dword ptr [rbp-6Ch],eax




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







[최초 등록일: ]
[최종 수정일: 11/27/2019]

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

비밀번호

댓글 작성자
 




... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
1755정성태9/22/201434182오류 유형: 241. Unity Web Player를 설치해도 여전히 설치하라는 화면이 나오는 경우 [4]
1754정성태9/22/201424524VC++: 80. 내 컴퓨터에서 C++ AMP 코드가 실행이 될까요? [1]
1753정성태9/22/201420537오류 유형: 240. Lync로 세미나 참여 시 소리만 들리지 않는 경우 [1]
1752정성태9/21/201440985Windows: 100. 윈도우 8 - RDP 연결을 이용해 VNC처럼 사용자 로그온 화면을 공유하는 방법 [5]
1751정성태9/20/201438876.NET Framework: 464. 프로세스 간 통신 시 소켓 필요 없이 간단하게 Pipe를 열어 통신하는 방법 [1]파일 다운로드1
1750정성태9/20/201423805.NET Framework: 463. PInvoke 호출을 이용한 비동기 파일 작업파일 다운로드1
1749정성태9/20/201423715.NET Framework: 462. 커널 객체를 위한 null DACL 생성 방법파일 다운로드1
1748정성태9/19/201425339개발 환경 구성: 238. [Synergy] 여러 컴퓨터에서 키보드, 마우스 공유
1747정성태9/19/201428359오류 유형: 239. psexec 실행 오류 - The system cannot find the file specified.
1746정성태9/18/201425994.NET Framework: 461. .NET EXE 파일을 닷넷 프레임워크 버전에 상관없이 실행할 수 있을까요? - 두 번째 이야기 [6]파일 다운로드1
1745정성태9/17/201422960개발 환경 구성: 237. 리눅스 Integration Services 버전 업그레이드 하는 방법 [1]
1744정성태9/17/201430971.NET Framework: 460. GetTickCount / GetTickCount64와 0x7FFE0000 주솟값 [4]파일 다운로드1
1743정성태9/16/201420917오류 유형: 238. 설치 오류 - Failed to get size of pseudo bundle
1742정성태8/27/201426909개발 환경 구성: 236. Hyper-V에 설치한 리눅스 VM의 VHD 크기 늘리는 방법 [2]
1741정성태8/26/201421283.NET Framework: 459. GetModuleHandleEx로 알아보는 .NET 메서드의 DLL 모듈 관계파일 다운로드1
1740정성태8/25/201432460.NET Framework: 458. 닷넷 GC가 순환 참조를 해제할 수 있을까요? [2]파일 다운로드1
1739정성태8/24/201426459.NET Framework: 457. 교착상태(Dead-lock) 해결 방법 - Lock Leveling [2]파일 다운로드1
1738정성태8/23/201421999.NET Framework: 456. C# - CAS를 이용한 Lock 래퍼 클래스파일 다운로드1
1737정성태8/20/201419689VS.NET IDE: 93. Visual Studio 2013 동기화 문제
1736정성태8/19/201425535VC++: 79. [부연] CAS Lock 알고리즘은 과연 빠른가? [2]파일 다운로드1
1735정성태8/19/201418126.NET Framework: 455. 닷넷 사용자 정의 예외 클래스의 최소 구현 코드 - 두 번째 이야기
1734정성태8/13/201419778오류 유형: 237. Windows Media Player cannot access the file. The file might be in use, you might not have access to the computer where the file is stored, or your proxy settings might not be correct.
1733정성태8/13/201426255.NET Framework: 454. EmptyWorkingSet Win32 API를 사용하는 C# 예제파일 다운로드1
1732정성태8/13/201434373Windows: 99. INetCache 폴더가 다르게 보이는 이유
1731정성태8/11/201426962개발 환경 구성: 235. 점(.)으로 시작하는 파일명을 탐색기에서 만드는 방법
1730정성태8/11/201422075개발 환경 구성: 234. Royal TS의 터미널(Terminal) 연결에서 한글이 깨지는 현상 해결 방법
... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...