国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

CLR 調試接口的架構與應用 [2] 調試框架

2024-07-21 02:17:14
字體:
來源:轉載
供稿:網友
如 don box 在《.net本質論 第1卷:公共語言運行庫》一書的第10章中介紹, clr 調試框架是一個由 clr 提供的,面向工具開發商的,支持調試功能的最小功能集。與 jvm 的 jdi (java debug interface)不同,clr 調試框架不僅僅關注于虛擬機一級的調試,同時也提供了 native 一級調試的統一接口。使得現有工具開發商能夠以最小代價移植并支持 clr 調試功能。而對 clr 調試更高層次或更細粒度的支持,則是由前面提到的 profiling api 完成。
clr 調試接口主要通過 mscordbi.dll 提供的 icordebug 接口,讓調試器通過進程內或進程外方式,對被調試 clr 進行監控。而 icordebug 接口可以通過 .net framework sdk 中 includecordebug.idl 或 includecordebug.h 直接使用。對 c#/delphi 也可以直接 reference/import 在 sdk 的 lib 目錄下的 cordebug.tlb 類型庫,獲得調用包裝類。下面示例將都使用 c# 作為描述語言。
在使用時,可以直接獲取icordebug接口,并調用其initialize/terminate方法進行初始化和析構操作,框架代碼如下:


以下為引用:

using cordblib;

namespace cordbg
{
public class debugger : idisposable
{
private icordebug _dbg;

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

try
{
_dbg.initialize();

// 構造調試環境

// 處理調試事件
}
finally
{
_dbg.terminate();
}
}
...
}
[mtathread]
static void main(string[] args)
{
using(debugger dbg = new debugger())
{
dbg.run();
}
}
}





注意 clr 調試環境必須在 mta 的線程套間上下文(thread apartment context)中運行,因此必須將入口函數的 stathread 屬性改成 mtathread,否則會在調試接口調用回調函數時出現異常。對應于 com 中的 coinitializeex(null, coinit_multithreaded) 調用。
在創建了 icordebug 調試接口后,需要針對托管和非托管調試事件,提供調試事件回調接口。可以將實現了調試事件接口 icordebugmanagedcallback/icordebugunmanagedcallback 的實例,使用 icordebug 接口的 setmanagedhandler/setunmanagedhandler 方法,掛接到調試系統上,在適當的時候由調試系統回調,通知調試器有調試事件發生。實現上可以通過 managedeventhandler/unmanagedeventhandler 兩個單獨的類,抽象出對托管和非托管調試事件的處理機制,將之掛接到調試器上,如:

以下為引用:

namespace cordbg
{
public class debugeventhandler
{
protected debugger _dbg;

public debugeventhandler(debugger dbg)
{
this._dbg = dbg;
}
}

public class managedeventhandler : debugeventhandler, icordebugmanagedcallback
{
public managedeventhandler(debugger dbg) : base(dbg)
{
}

// 實現 icordebugmanagedcallback 接口
}

public class unmanagedeventhandler : debugeventhandler, icordebugunmanagedcallback
{
public unmanagedeventhandler(debugger dbg) : base(dbg)
{
}

// 實現 icordebugunmanagedcallback 接口
}

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

_dbg.setmanagedhandler(new managedeventhandler(this));
_dbg.setunmanagedhandler(new unmanagedeventhandler(this));

//...
}
}
}





在準備好了調試事件處理器后,就可以根據需要,創建或者附加到目標調試進程上。icordebug 提供了 createprocess 方法對 win32 api 中 createprocess 函數進行了包裝。

以下為引用:

public abstract interface icordebug
{
public abstract new void createprocess (
string lpapplicationname,
string lpcommandline,
_security_attributes lpprocessattributes,
_security_attributes lpthreadattributes,
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
);





可以看到這兩個函數的參數基本上是一一對應的,只不過icordebug.createprocess函數多了一個輸入debuggingflags參數指定調試標志和一個輸出ppprocess參數返回創建進程的控制接口。
兩個 _security_attributes 類型的安全屬性,一般來說可以設置為空,使用缺省設置。

以下為引用:

_security_attributes sa = new _security_attributes();

sa.nlength = (uint)marshal.sizeof(sa);
sa.binherithandle = win32.bool.false;
sa.lpsecuritydescriptor = intptr.zero;





值得注意的是 dwcreationflags 指定了創建進程是否支持 native 模式的調試,也就是前面 setunmanagedhandler 方法調用的接口是否起作用。可以根據情況如命令行選項決定是否支持 native 調試模式,如

以下為引用:

namespace win32
{
public struct creationflag
{
public const uint debug_process = 0x00000001;
public const uint debug_only_this_process = 0x00000002;

public const uint 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 run()
{
//...

uint dwcreationflag = creationflag.create_new_console;

if(options.nativemode)
{
dwcreationflag |= creationflag.debug_only_this_process | creationflag.debug_process;
}

//...
}
}
}





比較麻煩的是指定啟動參數的 lpstartupinfo 參數和返回進程信息的 lpprocessinformation 參數。c# 在導入 cordebug.tlb 類型庫時,都沒有處理這兩個類型,必須自己定義之:

以下為引用:

[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 hprocess;
public intptr hthread;
public uint dwprocessid;
public uint dwthreadid;
}





使用的時候則需要先在堆棧中構造此結構的值類型對象,然后通過 unsafe 形式指針,或者 marshal 手工處理將之轉換為地址。這里為了避免使用較為 dirty 的 unsafe 方式,通過 marshal.allochglobal 分配全局內存;然后調用 marshal.structuretoptr 將結構復制到內存中;調用 createprocess 時使用此內存的地址;調用返回后使用 marshal.ptrtostructure 從內存中獲得結構的內容;最后調用 marshal.freehglobal 釋放全局內存。簡要代碼如下:

以下為引用:

//...

startupinfo si = new startupinfo(); // 構造時所有字段已清零

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);

//...





而將調試器附加到現有進程上則相對簡單得多,接口方法如下:

以下為引用:

public abstract interface icordebug
{
public abstract new void debugactiveprocess(uint id, int win32attach, icordebugprocess ppprocess)
}

bool debugactiveprocess(
dword dwprocessid
);





與 win32 api 的 debugactiveprocess 相比,icordebug.debugactiveprocess 增加的 win32attach 指定是否允許 native 模式調試,ppprocess 返回目標調試進程的控制接口。

以上簡要介紹了 clr 調試接口在使用時如何構造調試環境,以及對調試目標進程的創建和附加的方法。下一節將整體上對托管和非托管的各種調試事件做一個介紹,然后再針對不同的調試功能開始詳細介紹。
菜鳥學堂:
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 绥德县| 墨竹工卡县| 桃园市| 新巴尔虎左旗| 合山市| 渭南市| 错那县| 武穴市| 色达县| 湖口县| 大名县| 武乡县| 峨山| 内丘县| 宜君县| 长岛县| 元朗区| 宜昌市| 体育| 栾城县| 临泽县| 嵊州市| 隆子县| 常德市| 定南县| 西和县| 平陆县| 琼中| 堆龙德庆县| 海阳市| 平罗县| 安平县| 齐齐哈尔市| 双流县| 天等县| 岐山县| 通化县| 林芝县| 志丹县| 惠东县| 旌德县|