Architecture and Application of CLR Debug Interface [2] Debug Framework

zhaozj2021-02-12  182

http://www.blogcn.com/user8/flier_lu/index.html?id=1894812

In the 10th chapter of Don Box in ".NET Natural Nature", the CLR debug framework is a minimum function set by CLR, tool-oriented, support for tool developers. . Unlike JVM's JDI (Java Debug Interface), the CLR debug framework is not only debugging at the virtual machine level, but also provides a unified interface for Native-level debugging. Make existing tool developers to transplant and support CLR debugging in minimum cost. The support for CLR debugging higher or finer granularity is completed by the previously mentioned PROFILING API. The CLR debug interface mainly passes the Icordebug interface provided by Mscordbi.dll, allowing the debugger to monitor the debugged CLR through the process or processes in the process. The icordebug interface can be used directly in includecordebug.IDL or includecordebug.h in .NET Framework SDK. For C # / Delphi, you can also directly Reference / Import's CORDEBUG.TLB type library under the LIB directory of the SDK to get the call packages. The following example will use a C # as a description language. When using, you can directly obtain the IcordeBug interface, and call its initialize / terminate method for initialization and destruction operation, the frame code is as follows:

The following is quoted:

USING CORDBLIB;

Namespace Cordbg {public class debugger: idisposable {private icordebug_dbg;

Public void run () {_dbg = new cordebugclass ();

Try {_dbg.initialize ();

// Construct the debugging environment

// Process debugging event} Finally {_dbg.terminate ();}} ...} [mtathread] static void main (String [] args) {using (debugger dbg = new debugger ()) {dbg.run (); }}}

Note that the CLR debugging environment must be run in the Thread Apartment Context, so you must change the StathRead attribute of the portal function to Mtathread, otherwise an exception occurs when the debug interface calls the callback function. Co-calling corresponds to CoinitializeEx (NULL, COINIT_MULTITITHREADED) in COM.

After the Icordebug debug interface is created, you need to provide a debug event callback interface for managed and unmanaged commissioning events. An instance of debugging event interface IcORDEBUGMANAGEDCALLBACK / ICORDEBUGUGMANAGEDCALLBACK / ICORDEBUGUGMANAGEDCALLBACK can be implemented using the icordebug interface. On the debugging system, the debugging system is called by the debugging system when appropriate. Implementing two separate classes of Managendler / UnmanageDeventhandler, abstract the processing mechanism for managed and non-hosting debugging events, will be huddled on the debugger, such as:

The following is quoted:

Namespace Cordbg

{

Public Class DebugEventHandler

{

protected debugger_dbg;

Public DebugEventHandler (Debugger DBG) {this._dbg = dBG;}}

Public Class ManageDeventHandler: DebugEventHandler, IcordebugManagedCallback {PUBLIC ManageDeventHandler (DBUGER DBG): Base (DBG) {}

// Implement IcordebugManageDCallback interface}

Public class unmanageDeventhandler: debugeventhandler, IcordebugunManagedCallback {public unmanageDeventhandler (DBUGER DBG): Base (DBG) {}

// Implement IcordebugunmanageDcallback interface}

Public class debugger: idisposable {public void run () {// ...

_dbg.setManageDrandler (this)); _dbg.setunmanagedHandler (this)

// ...}}}}

After you are ready to debug the event processor, you can create or attach it to the target debug process as needed. Icordebug provides a CreateProcess method to package the CreateProcess function in Win32 API.

The following is quoted:

Public Abstract Interface Icordebug

{

Public Abstract New Void CreateProcess

String lpapplicationname,

String lpcommandline,

_Security_attributes lpprocessattributes,

_Security_attributes LPTHREADATIADATTRIBUTES,

Int binherithandles,

Uint dwcreationflags,

INTPTR LPENVIRONMENT,

System.string lpcurrentdirectory,

Uint LPStartupinfo,

Uint LPProcessInformation,

CordebugCreateProcessFlags DebuggingFlags,

IcordebugProcess PPPRocess)

}

BOOL CreateProcess (LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);

It can be seen that the parameters of the two functions are basically one, but the icordebug.createprocess function has more input debuggingflags parameters Specify the debug flag and an output PPPRocess parameter returns the control interface for the creation process. Two _security_attributes type security properties, generally set to empty, use default settings.

The following is quoted:

_Security_attributes sa = new _security_attributes ();

Sa.nlength = (uint) Marshal.SizeOf (sa); sa.binherithandle = win32.bool.false; sa.lpsecurityDescriptor = intptr.zero;

It is worth noting that dwcreationFlags specifies whether the creation process supports debugging of Native mode, that is, whether the front setUnmanageDHandler method is called. You can determine if you support Native debugging mode according to the case, if you want to support Native debugging mode, such as

The following is quoted:

Namespace Win32

{

Public struct creeionflag

{

Public const uint debug_process = 0x00000001;

Public const uint debug_only_this_process = 0x00000002;

Public consted create_suspended = 0x00000004;

Public const uint detached_process = 0x00000008;

Public const uint create_new_console = 0x00000010;

public const uint NORMAL_PRIORITY_CLASS = 0x00000020; public const uint IDLE_PRIORITY_CLASS = 0x00000040; public const uint HIGH_PRIORITY_CLASS = 0x00000080; public const uint REALTIME_PRIORITY_CLASS = 0x00000100;

Public const uint create_new_process_group = 0x00000200; public const uint create_unicode_environment = 0x00000400;

Public const uint create_separate_wow_vdm = 0x00000800; Public const uint create_shared_wow_vdm = 0x00001000; public const uint create_forcedos = 0x00002000;

Public const uint below_normal_priority_class = 0x00004000; Public const uint Above_normal_priority_class = 0x00008000;

Public const uint create_breakaway_from_job = 0x01000000;}}

Namespace Cordbg {public class debugger: idisposable {private void () {//...uint dwcreationflag = credglag.create_new_console

IF (options.nativemode) {dwcreationflag | = createflag.debug_only_this_process | creeionflag.debug_process;}

// ...}}}}

It is more troublesome to specify the LPStartupInfo parameter of the startup parameter and the LPPROCESSINFORMATION parameter of the return process information. C # When importing the Cordebug.TLB type library, there is no two types, you must define yourself:

The following is quoted:

[Structlayout (layoutkind.sequential, charset = charset.auto)]

Public struct startupinfo

{

Public uint CB;

Public string lpreserved;

Public string lpdesktop;

Public string lptitle;

Public uint dwx;

Public uint dwy;

Public uint dwxsize;

Public uint dwysize;

Public uint dwxcountchars;

Public uint dwycountchars;

Public uint dwfillattribute;

PUBLIC uint dwflags;

Public ushort wshowwindow;

Public ushort cbreserved2;

Public INTPTR LPRESERVED2;

Public INTPTR HSTDINPUT;

Public INTPTR HSTDOUTPUT;

Public INTPTR HSTDERROR;

}

[Structlayout (layoutkind.sequential)] public struct process_information {public intptr hthread; public uint dwthreadId; public uint dwthreadId;

When using, you need to construct the value type object of this structure in the stack, and then converted to the address by the Unsafe form, or the Marshal manual process is converted to the address. Here, in order to avoid using a more Dirty Unsafe mode, the global memory is allocated by Marshal.allochglobal; then call Marshal.StructureToptr to copy the structure to memory; use this memory to use this memory when calling createProcess; call back to get from memory from memory Structure content; final call Marshal.Freehglobal release global memory. The brief code is as follows:

The following is quoted:

// ...

StartupInfo Si = New Startupinfo (); // All fields have been cleared

Si.cb = (uint) Marshal.SizeOf (Si);

Process_information pi = new process_information ();

IntPtr ppi = Marshal.AllocHGlobal (Marshal.SizeOf (pi)), psi = Marshal.AllocHGlobal (Marshal.SizeOf (si)); Marshal.StructureToPtr (si, psi, true); Marshal.StructureToPtr (pi, ppi, true) ;

_dbg.CreateProcess (Options.FileInfo.FullName, Options.CommandLine, ref sa, ref sa, BOOL.FALSE, dwCreationFlag, IntPtr.Zero, Options.CurrentDirectory, (uint) psi.ToInt32 (), (uint) ppi.ToInt32 ( ), Cordebugcreateprocessflags.debug_no_special_options, out _proc);

PI = (Process_information) Marshal.PTRTOStructure (PPI, Typeof (Process_information));

Marshal.Freehglobal (PPI); Marshal.Freehglobal (PSI);

Native.closeHandle (pi.hprocess);

// ...

It is relatively simple to attach the debugger to the existing process. The interface method is as follows:

The following is quoted:

Public Abstract Interface Icordebug

{

Public Abstract New Void DebugActiveProcess (uint ID, int win32ttach, icordebugprocess ppprocess)

}

Bool DebugActiveProcess (DWORD DWPROCESSID);

Compared to the Win32 API DebugActiveProcess, Icordebug.debugActiveProcess adds Win32ttach specifies whether Native mode debugging, PPPRocess returns the control interface of the target debug process.

The above brief introduction how the CLR debug interface constructs a debug environment when used, and the creation and additional methods of debugging the target process. The next section will introduce a whole to the various commissioning events of managed and unmanaged, and then be introduced in detail for different debugging features.

转载请注明原文地址:https://www.9cbs.com/read-6584.html

New Post(0)