성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
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 - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석 - OracleCommand.ExecuteReader에서 OpsSql.Prepare2 PInvoke 호출 분석</h1> <p> 지난 경험을 바탕으로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/12065'>http://www.sysnet.pe.kr/2/0/12065</a> </pre> <br /> PInvoke에서 OpsSql.Prepare2의 경우에도 파악해 단순히 기록 차원으로 남깁니다. 우선 이를 위해 간단한 예제를 만들어,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using Oracle.DataAccess.Client; using System; using System.Reflection; namespace ConsoleApp1 { class Program { static void Main(string[] args) { <a target='tab' href='http://www.sysnet.pe.kr/2/0/828'>SetOdpnetPath();</a> 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..."); <span style='color: blue; font-weight: bold'>Console.ReadLine(); cmd.ExecuteReader();</span> oracleConnection.Close(); } Console.WriteLine(); } } } </pre> <br /> Console.ReadLine 시점에 덤프를 떠서 windbg로 열어 봅니다. Reflection 도구 등으로 Oracle.DataAccess.Client.OracleCommand.ExecuteReader의 소스 코드를 살펴보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public new OracleDataReader ExecuteReader() { if (<span style='color: blue; font-weight: bold'>OraTrace.m_TraceLevel</span> != 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; } </pre> <br /> OraTrace.m_TraceLevel에 따라 앞뒤로 Trace 메서드가 실행되는 것을 볼 수 있습니다. 재미를 위해, m_TraceLevel이 실행 중에 어떤 값을 가지고 있는지 확인해 볼까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > windbg - 닷넷 메모리 덤프에서 정적(static) 필드 값을 조사하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11487'>http://www.sysnet.pe.kr/2/0/11487</a> </pre> <br /> 위의 글에 설명한대로 해당 타입의 EEClass를 먼저 구하고,<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'>!name2ee *!Oracle.DataAccess.Client.OraTrace</span> ...[생략]... Module: 00007ff99b855bc8 Assembly: Oracle.DataAccess.dll Token: 0000000002000109 MethodTable: 00007ff99ba11b98 <span style='color: blue; font-weight: bold'>EEClass: 00007ff99b9f7b50</span> Name: Oracle.DataAccess.Client.OraTrace ...[생략]... </pre> <br /> 덤프하면 출력에 m_TraceLevel의 값을 볼 수 있습니다.<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'>!DumpClass /d 00007ff99b9f7b50</span> 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 <span style='color: blue; font-weight: bold'>00007ff9f7720ab0 4000811 444 System.UInt32 1 static 0 m_TraceLevel</span> 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 </pre> <br /> 보는 바와 같이 0이군요. ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이후 this.ExecuteReader() 내부로 들어가 OpsSql.Prepare2를 호출해 native 코드 내부로 디버깅을 진행해 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ...[생략]... 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; <span style='color: blue; font-weight: bold'>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);</span> } 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); } } } ...[생략]... </pre> <br /> 다음과 같은 callstack 상태까지 옵니다.<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: 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] </pre> <br /> 이 시점에 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/12065'>windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석</a>" 글에서 다룬 것을 그대로 적용해 pinvoke 층의 분석을 할 수 있습니다. 다음은 그 결과이고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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 </pre> <br /> 아래의 코드 분석을 바탕으로 알아낸 것입니다. (<a target='tab' href='https://docs.microsoft.com/ko-kr/dotnet/framework/tools/sos-dll-sos-debugging-extension'>!U 명령은 sos.dll이 제공</a>합니다.)<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 00007ff99b97c99a</span> 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 </pre> <br /> 그리고 다음은 this.ExecuteReader() 측에서 OpsSql.Prepare2를 호출할 당시의 코드와 레지스터의 내용을 정리한 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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 </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
5576
(왼쪽의 숫자를 입력해야 합니다.)