首页
/
每日頭條
/
科技
/
windows進程管理優缺點
windows進程管理優缺點
更新时间:2024-09-09 16:05:22

根據前面的介紹,NT内核會把操作系統的代碼和數據映射到系統中所有進程的内核空間中。這樣,每個進程内的應用程序代碼便可以很方便地調用内核空間中的系統服務。這裡的“很方便”有多層含義,一方面是内核代碼和用戶代碼在一個地址空間中,應用程序調用系統服務時不需要切換地址空間,另一方面是整個系統中内核空間的地址是統一的,編寫内核空間的代碼時會簡單很多。但是,如此設計也帶來一個很大的問題,那就是用戶空間中的程序指針可以指向内核空間中的數據和代碼,因此必須防止用戶代碼破壞内核空間中的操作系統。怎麼做呢?答案是利用權限控制來實現對内核空間的保護。

2.6.1 訪問模式

Windows定義了兩種訪問模式(access mode)——用戶模式(user mode,也稱為用戶态)和内核模式(kernel mode,也稱為内核态)。應用程序(代碼)運行在用戶模式下,操作系統代碼運行在内核模式下。内核模式對應于處理器的最高權限級别(不考慮虛拟機情況),在内核模式下執行的代碼可以訪問所有系統資源并具有使用所有特權指令的權利。相對而言,用戶模式對應于較低的處理器優先級,在用戶模式下執行的代碼隻可以訪問系統允許其訪問的内存空間,并且沒有使用特權指令的權利。

本書卷1介紹過,IA-32處理器定義了4種特權級别(privilege level),或者稱為環(ring),分别為0、1、2、3,優先級0(環0)的特權級别最高。處理器在硬件一級保證高優先級的數據和代碼不會被低優先級的代碼破壞。Windows系統使用了IA-32處理器所定義的4種優先級中的兩種,優先級3(環3)用于用戶模式,優先級0用于内核模式。之所以隻使用了其中的兩種,主要是因為有些處理器隻支持兩種優先級,比如Compaq Alpha處理器。值得說明的是,對于x86處理器來說,并沒有任何寄存器表明處理器當前處于何種模式(或優先級)下,優先級隻是代碼或數據所在的内存段或頁的一個屬性,參見卷1的2.6節和2.7節。

因為内核模式下的數據和代碼具有較高的優先級,所以用戶模式下的代碼不可以直接訪問内核空間中的數據,也不可以直接調用内核空間中的任何函數或例程。任何這樣的嘗試都會導緻保護性錯誤。也就是說,即使用戶空間中的代碼指針正确指向了要訪問的數據或代碼,但一旦訪問發生,那麼處理器會檢測到該訪問是違法的,會停止該訪問并産生保護性異常(#GP)。

雖然不可以直接訪問,但是用戶程序可以通過調用系統服務來間接訪問内核空間中的數據或間接調用、執行内核空間中的代碼。當調用系統服務時,主調線程會從用戶模式切換到内核模式,調用結束後再返回到用戶模式,也就是所謂的模式切換。在線程的KTHREAD結構中,定義了UserTime和KernelTime兩個字段,分别用來記錄這個線程在用戶模式和内核模式的運行時間(以時鐘中斷次數為單位)。模式切換是通過軟中斷或專門的快速系統調用(fast system call)指令來實現的。下面通過一個例子來分别介紹這兩種切換機制。

2.6.2 使用INT 2E切換到内核模式

圖2-4展示了在Windows 2000中通過INT 2E從應用程序調用ReadFile() API的過程。因為ReadFile() API是從Kernel32.dll導出的,所以我們看到該調用首先轉到Kernel32.dll中的ReadFile()函數,ReadFile()函數在對參數進行簡單檢查後便調用NtDll.dll中的NtReadFile()函數。

windows進程管理優缺點(Windows操作系統管理進程和線程)1

圖2-4 通過INT 2E從應用程序調用ReadFile() API的過程

通過反彙編可以看到,NtDll.dll中的NtReadFile ()函數非常簡短,首先将ReadFile()對應的系統服務号(0xa1,與版本有關)放入EAX寄存器中,将參數指針放入EDX寄存器中,然後便通過INT n指令發出調用。這裡要說明的一點是,雖然每個系統服務都具有唯一的号碼,但微軟公司沒有公開這些服務号,也不保證這些号碼在不同的Windows版本中會保持一緻。

ntdll!NtReadFile: // Windows 2000 77f8fb5d b8a1000000 mov eax,0xa1 77f8fb62 8d542404 lea edx,[esp 0x4] 77f8fb66 cd2e int 2e 77f8fb68 c22400 ret 0x24

在WinDBG下通過!idt 2e命令可以看到2e号向量對應的服務例程是KiSystemService ()。KiSystemService ()是内核态中專門用來分發系統調用的例程。

lkd> !idt 2e Dumping IDT: 2e: 804db1ed nt!KiSystemService

Windows将2e号向量專門用于系統調用,在啟動早期初始化中斷描述符表(Interrupt Descriptor Table,IDT)時(見第11章)便注冊好了合适的服務例程。因此當NTDll.DLL中的NtReadFile()發出INT 2E指令後,CPU便會通過IDT找到KiSystemService ()函數。因為KiSystemService ()函數是位于内核空間的,所以CPU在把執行權交給KiSystemService ()函數前,會做好從用戶模式切換到内核模式的各種工作,包括:

(1)權限檢查,即檢查源位置和目标位置所在的代碼段權限,核實是否可以轉移;

(2)準備内核模式使用的棧,為了保證内核安全,所有線程在内核态執行時都必須使用位于内核空間的内核棧(kernel stack),内核棧的大小一般為8KB或12KB。

KiSystemService ()會根據服務ID從系統服務分發表(System Service Dispatch Table)中查找到要調用的服務函數地址和參數描述,然後将參數從用戶态棧複制到該線程的内核棧中,最後KiSystemService ()調用内核中真正的NtReadFile()函數,執行讀文件的操作,操作結束後會返回到KiSystemService (),KiSystemService ()會将操作結果複制回該線程用戶态棧,最後通過IRET指令将執行權交回給NtDll.dll中的NtReadFile()函數(繼續執行INT 2E後面的那條指令)。

通過INT 2E進行系統調用時,CPU必須從内存中分别加載門描述符和段描述符才能得到KiSystemService ()的地址,即使門描述符和段描述符已經在高速緩存中,CPU也需要通過“内存讀(memory read)”操作從高速緩存中讀出這些數據,然後進行權限檢查。

2.6.3 快速系統調用

因為系統調用是非常頻繁的操作,所以如果能減少這些開銷還是非常有意義的。可以從兩個方面來降低開銷:一是把系統調用服務例程的地址放到寄存器中以避免讀IDT這樣的内存操作,因為讀寄存器的速度比讀内存的速度要快很多;二是避免權限檢查,也就是使用特殊的指令讓CPU省去那些對系統服務調用來說根本不需要的權限檢查。奔騰II處理器引入的SYSENTER/SYSEXIT指令正是按這一思路設計的。AMD K7引入的SYSCALL/SYSRETURN指令也是為這一目的而設計的。相對于INT 2E,使用這些指令可以加快系統調用的速度,因此利用這些指令進行的系統調用稱為快速系統調用。

下面我們介紹Windows系統是如何利用IA-32處理器的SYSENTER/SYSEXIT指令(從奔騰II開始)實現快速系統調用的[2]。首先,Windows 2000或之前的Windows系統不支持快速系統調用,它們隻能使用前面介紹的INT 2E方式進行系統調用。Windows XP和Windows Server 2003或更新的版本在啟動過程中會通過CPUID指令檢測CPU是否支持快速系統調用指令(EDX寄存器的SEP标志位)。如果CPU不支持這些指令,那麼仍使用INT 2E方式。如果CPU支持這些指令,那麼Windows系統便會決定使用新的方式進行系統調用,并做好如下準備工作。

(1)在全局描述符表(GDT)中建立4個段描述符,分别用來描述供SYSENTER指令進入内核模式時使用的代碼段(CS)和棧段(SS),以及SYSEXIT指令從内核模式返回用戶模式時使用的代碼段和棧段。這4個段描述符在GDT中的排列應該嚴格按照以上順序,隻要指定一個段描述符的位置便能計算出其他的。

(2)設置表2-1中專門用于系統調用的MSR(關于MSR的詳細介紹見卷1的2.4.3節),SYSENTER_EIP_MSR用于指定新的程序指針,也就是SYSENTER指令要跳轉到的目标例程地址。Windows系統會将其設置為KiFastCallEntry的地址,因為KiFastCallEntry例程是Windows内核中專門用來受理快速系統調用的。SYSENTER_CS_MSR用來指定新的代碼段,也就是KiFastCallEntry所在的代碼段。SYSENTER_ESP_MSR用于指定新的棧指針(ESP)。新的棧段是由SYSENTER_CS_MSR的值加8得來的。

(3)将一小段名為SystemCallStub的代碼複制到SharedUserData内存區,該内存區會被映射到每個Win32進程的進程空間中。這樣當應用程序每次進行系統調用時,NTDll.DLL中的殘根(stub)函數便調用這段SystemCallStub代碼。SystemCallStub的内容因系統硬件的不同而不同,對于IA-32處理器,該代碼使用SYSENTER指令,對于AMD處理器,該代碼使用SYSCALL指令。

表2-1 供SYSENTER指令使用的MSR(略)

例如在配有Pentium M CPU的Windows XP系統上,以上3個寄存器的值分别為:

lkd> rdmsr 174 msr[174] = 00000000`00000008 lkd> rdmsr 175 msr[175] = 00000000`bacd8000 lkd> rdmsr 176 msr[176] = 00000000`8053cad0

其中SYSENTER_CS_MSR的值為8,這是Windows系統的内核代碼段的選擇子,即常量KGDT_R0_CODE的值。WinDBG幫助文件中關于dg命令的說明中列出了這個常量。SYSENTER_EIP_MSR的值是8053cad0,檢查nt内核中KiFastCallEntry函數的地址。

lkd> x nt!KiFastCallEntry 8053cad0 nt!KiFastCallEntry = <no type information>

可見,Windows把快速系統調用的目标指向内核代碼段中的KiFastCallEntry函數。

通過反彙編Windows XP下NTDll.DLL中的NtReadFile ()函數,可以看到SystemCallStub被映射到進程的0x7ffe0300位置。與前面Windows 2000下的版本相比,容易看到該服務的系統服務号碼在這兩個版本間是不同的。

kd> u ntdll... ntdll!NtReadFile: // Windows XP 77f5bfa8 b8b7000000 mov eax,0xb7 77f5bfad ba0003fe7f mov edx,0x7ffe0300 77f5bfb2 ffd2 call edx {SharedUserData!SystemCallStub (7ffe0300)} 77f5bfb4 c22400 ret 0x24 77f5bfb7 90 nop

觀察本段下面反彙編SystemCallStub的結果,它隻包含3條指令,分别用于将棧指針(ESP寄存器)放入EDX寄存器中、執行sysenter指令和返回。第一條指令有兩個用途:一是向内核空間傳遞參數;二是指定從内核模式返回時的棧地址。因為筆者使用的是英特爾奔騰M處理器,所以此處是sysenter指令,對于AMD處理器,此處應該是syscall指令。

kd> u... SharedUserData!SystemCallStub: 7ffe0300 8bd4 mov edx,esp 7ffe0302 0f34 sysenter 7ffe0304 c3 ret

下面讓我們看一下KiFastCallEntry例程,其清單如下所示。

kd> u nt!KiFastCallEntry L20 nt!KiFastCallEntry: 804db1bb 368b0d40f0dfff mov ecx,ss:[ffdff040] 804db1c2 368b6104 mov esp,ss:[ecx 0x4] 804db1c6 b90403fe7f mov ecx,0x7ffe0304 804db1cb 3b2504f0dfff cmp esp,[ffdff004] 804db1d1 0f84cc030000 je nt!KiServiceExit2 0x13f (804db5a3) 804db1d7 6a23 push 0x23 804db1d9 52 push edx 804db1da 83c208 add edx,0x8 804db1dd 6802020000 push 0x202 804db1e2 6a02 push 0x2 804db1e4 9d popfd 804db1e5 6a1b push 0x1b 804db1e7 51 push ecx // Fall Through,自然進入KiSystemService函數 nt!KiSystemService: 804db1e8 90 nop 804db1e9 90 nop 804db1ea 90 nop 804db1eb 90 nop 804db1ec 90 nop nt!KiSystemService: 804db1ed 6a00 push 0x0 804db1ef 55 push ebp

顯而易見,KiFastCallEntry在做了些簡單操作後,便下落(fall through)到KiSystemService函數了,也就是說,快速系統調用和使用INT 2E進行的系統調用在内核中的處理絕大部分是一樣的。另外,請注意ecx寄存器,mov ecx,0x7ffe0304将其值設為0x7ffe0304,也就是SharedUserData内存區裡SystemCallStub例程中ret指令的地址(參見上文的SystemCallStub代碼)。在進入nt!KiSystemService之前,ecx連同其他一些參數被壓入棧中。事實上,ecx用來指定SYSEXIT返回用戶模式時的目标地址。當使用INT 2E進行系統調用時,由于INT n指令會自動将中斷發生時的CS和EIP寄存器壓入棧中,當中斷處理例程通過執行iretd返回時,iretd指令會使用棧中保存的CS和EIP值返回合适的位置。因為sysenter指令不會向棧中壓入要返回的位置,所以sysexit指令必須通過其他機制知道要返回的位置。這便是壓入ECX寄存器的原因。通過反彙編KiSystemCallExit2例程,我們可以看到在執行sysexit指令之前,ecx寄存器的值又從棧中恢複出來了。

kd> u nt!KiSystemCallExit l20 nt!KiSystemCallExit: 804db3b4 cf iretd nt!KiSystemCallExit2: 804db3b5 5a pop edx 804db3b6 83c408 add esp,0x8 804db3b9 59 pop ecx 804db3ba fb sti 804db3bb 0f35 sysexit nt!KiSystemCallExit3: 804db3bd 59 pop ecx 804db3be 83c408 add esp,0x8 804db3c1 5c pop esp 804db3c2 0f07 sysret

以上代碼中包含了3個從系統調用返回的例程,即KiSystemCallExit、KiSystemCallExit2和KiSystemCallExit3,它們分别對應于使用INT 2E、sysenter和syscall發起的系統調用,如表2-2所示。

表2-2 系統調用(略)

圖2-5展示了使用sysenter/sysexit指令對進行系統調用的完整過程(以調用ReadFile服務為例)。

windows進程管理優缺點(Windows操作系統管理進程和線程)2

圖2-5 快速系統調用(針對IA-32處理器)


windows進程管理優缺點(Windows操作系統管理進程和線程)3

格物

下面通過一個小的實驗來加深大家對系統調用的理解。首先啟動WinDBG程序,選擇File → Open Crash Dump,然後選擇本書實驗文件中的dumps\w732cf4.dmp文件。在調試會話建立後,先執行.symfix c:\symbols和.reload加載模塊與符号,再執行k命令,便得到清單2-4所示的完美棧回溯。

第22章将詳細講解棧回溯的原理,現在大家隻要知道棧上記錄着函數相互調用時的參數和返回地址等信息。棧回溯是從棧上找到這些信息,然後顯示出來的過程,是追溯線程執行軌迹的一種便捷方法。

清單2-4還顯示了任務管理器程序(taskmgr)調用NtTerminateProcess系統服務時的執行過程。棧回溯的結果包含4列,第一列是序号,第二列是每個函數的棧幀基地址,第三列是返回地址,第四列是使用“函數名 字節偏移量”形式表達的執行位置。以00棧幀為例,它對應的函數是著名的藍屏函數KeBugCheckEx,它的棧幀基地址是9796fb9c,它的返回地址是82b1ab51,翻譯成符号便是PspCatchCriticalBreak 0x71。

清單2-4 完美棧回溯

# ChildEBP RetAddr 00 9796fb9c 82b1ab51 nt!KeBugCheckEx 0x1e 01 9796fbc0 82a6daa8 nt!PspCatchCriticalBreak 0x71 02 9796fbf0 82a605b6 nt!PspTerminateAllThreads 0x2d 03 9796fc24 8287c87a nt!NtTerminateProcess 0x1a2 04 9796fc24 77da7094 nt!KiFastCallEntry 0x12a 05 001df4dc 77da68d4 ntdll!KiFastSystemCallRet 06 001df4e0 76193c82 ntdll!NtTerminateProcess 0xc 07 001df4f0 00bf57b9 KERNELBASE!TerminateProcess 0x2c 08 001df524 00bf67ec taskmgr!CProcPage::KillProcess 0x116 09 001df564 00bebc96 taskmgr!CProcPage::HandleWMCOMMAND 0x10f 0a 001df5d8 76abc4e7 taskmgr!ProcPageProc 0x275 0b 001df604 76ad5b7c USER32!InternalCallWinProc 0x23 0c 001df680 76ad59f3 USER32!UserCallDlgProcCheckWow 0x132 0d 001df6c8 76ad5be3 USER32!DefDlgProcWorker 0xa8 0e 001df6e4 76abc4e7 USER32!DefDlgProcW 0x22 0f 001df710 76abc5e7 USER32!InternalCallWinProc 0x23 10 001df788 76ab5294 USER32!UserCallWinProcCheckWow 0x14b 11 001df7c8 76ab5582 USER32!SendMessageWorker 0x4d0 12 001df7e8 74e94601 USER32!SendMessageW 0x7c 13 001df808 74e94663 COMCTL32!Button_NotifyParent 0x3d 14 001df824 74e944ed COMCTL32!Button_ReleaseCapture 0x113 15 001df884 76abc4e7 COMCTL32!Button_WndProc 0xa18 16 001df8b0 76abc5e7 USER32!InternalCallWinProc 0x23 17 001df928 76abcc19 USER32!UserCallWinProcCheckWow 0x14b 18 001df988 76abcc70 USER32!DispatchMessageWorker 0x35e 19 001df998 76ab41eb USER32!DispatchMessageW 0xf 1a 001df9bc 00be16fc USER32!IsDialogMessageW 0x588 1b 001dfdac 00be5384 taskmgr!wWinMain 0x5d1 1c 001dfe40 76bbed6c taskmgr!_initterm_e 0x1b1 1d 001dfe4c 77dc377b kernel32!BaseThreadInitThunk 0xe 1e 001dfe8c 77dc374e ntdll!__RtlUserThreadStart 0x70 1f 001dfea4 00000000 ntdll!_RtlUserThreadStart 0x1b

仔細觀察清單2-4中的地址部分,很容易看出用戶空間和内核空間的分界,也就是在棧幀04和棧幀05之間。棧幀05中的KiFastSystemCallRet函數屬于ntdll模塊,位于用戶空間。棧幀04中的KiFastCallEntry函數屬于nt模塊,位于内核空間。棧幀04的基地址是9796fc24,屬于内核空間;棧幀05的基地址是001df4dc,屬于用戶空間。它們分别來自這個線程的内核态棧和用戶态棧。WinDBG的k命令穿越兩個空間,遍曆兩個棧,顯示出線程在用戶空間和内核空間執行的完整過程,能産生如此完美的棧回溯顯示了WinDBG的強大。


2.6.4 逆向調用

前文介紹了從用戶模式進入内核模式的兩種方法,通過這兩種方法,用戶模式的代碼可以“調用”位于内核模式的系統服務。那麼内核模式的代碼是否可以主動調用用戶模式的代碼呢?答案是肯定的,這種調用通常稱為逆向調用(reverse call)。

簡單來說,逆向調用的過程是這樣的。首先内核代碼使用内核函數KiCallUserMode發起調用。接下來的執行過程與從系統調用返回(KiServiceExit)類似,不過進入用戶模式時執行的是NTDll.DLL中的KiUserCallbackDispatcher。而後KiUserCallbackDispatcher會調用内核希望調用的用戶态函數。當用戶模式的工作完成後,執行返回動作的函數會執行INT 2B指令,也就是觸發一個0x2B異常。這個異常的處理函數是内核模式的KiCallbackReturn函數。于是,通過INT 2B異常,CPU又跳回内核模式繼續執行了。

lkd> !idt 2b Dumping IDT: 2b: 8053d070 nt!KiCallbackReturn

以上是使用WinDBG的!idt命令觀察到的0x2B異常的處理函數。

2.6.5 實例分析

下面通過一個實際例子來進一步展示系統調用和逆向調用的執行過程。清單2-5顯示了使用WinDBG的内核調試會話捕捉到的記事本進程發起系統調用進入内核和内核函數執行逆向調用的全過程(棧回溯)。

清單2-5 記事本進程從發起系統調用進入内核和内核函數逆向調用的全過程

kd> kn # ChildEBP RetAddr 00 0006fe94 77fb4da6 USER32!XyCallbackReturn 01 0006fe94 8050f8ae ntdll!KiUserCallbackDispatcher 0x13 02 f4fc19b4 80595d2c nt!KiCallUserMode 0x4 03 f4fc1a10 bf871e98 nt!KeUserModeCallback 0x87 04 f4fc1a90 bf8748d4 win32k!SfnDWORD 0xa0 05 f4fc1ad8 bf87148d win32k!xxxSendMessageToClient 0x174 06 f4fc1b24 bf8714d3 win32k!xxxSendMessageTimeout 0x1a6 07 f4fc1b44 bf8635f6 win32k!xxxSendMessage 0x1a 08 f4fc1b74 bf84a620 win32k!xxxMouseActivate 0x22d 09 f4fc1c98 bf87a0c1 win32k!xxxScanSysQueue 0x828 0a f4fc1cec bf87a8ad win32k!xxxRealInternalGetMessage 0x32c 0b f4fc1d4c 804da140 win32k!NtUserGetMessage 0x27 0c f4fc1d4c 7ffe0304 nt!KiSystemService 0xc4 0d 0006feb8 77d43a21 SharedUserData!SystemCallStub 0x2 0e 0006febc 77d43c95 USER32!NtUserGetMessage 0xc 0f 0006fed8 010028e4 USER32!GetMessageW 0x31 10 0006ff1c 01006c54 notepad!WinMain 0xe3 11 0006ffc0 77e814c7 notepad!WinMainCRTStartup 0x174 12 0006fff0 00000000 kernel32!BaseProcessStart 0x23

根據執行的先後順序,最下面一行(幀#12)對應的是進程的啟動函數BaseProcessStart,而後是編譯器生成的進程啟動函數WinMainCRTStartup,以及記事本程序自己的入口函數WinMain。幀#0f表示記事本程序在調用GetMessage API進入消息循環。接下來GetMessage API調用Windows子系統服務的殘根函數NtUserGetMessage。從第2列的棧幀基地址都小于0x800000000可以看出,幀#12~#0d都是在用戶模式執行的。幀#0d執行我們前面分析過的SystemCallStub,而後(幀#0c)便進入了内核模式的KiSystemService。KiSystemService根據系統服務号碼,将調用分發給Windows子系統内核模塊win32k中的NtUserGetMessage函數。

幀#0a~#05表示内核模式的窗口消息函數在工作。幀#07~#05表示要把一個窗口消息發送到用戶态。幀#04的SfnDWORD表示在将消息組織好後調用KeUserModeCallback函數,發起逆向調用。幀#02表明在執行KiCallUserMode函數,幀#01表明已經在用戶模式下執行,這兩行之間的部分過程沒有顯示出來。同樣,幀#01 和幀#00 之間執行用戶模式函數的過程沒有完全體現出來。XyCallbackReturn函數是用于返回内核模式的,它的代碼很簡單,隻有如下幾條指令。

USER32!XyCallbackReturn: 001b:77d44168 8b442404 mov eax,dword ptr [esp 4] ss:0023:0006fe84=00000000 001b:77d4416c cd2b int 2Bh 001b:77d4416e c20400 ret 4

第1行把用戶模式函數的執行結果賦給EAX寄存器,第2行執行INT 2B指令。執行過INT 2B後,CPU便轉去執行異常處理程序KiCallbackReturn,回到了内核模式。

本文摘自《軟件調試(第2版)卷2:Windows平台調試(上、下冊)》

windows進程管理優缺點(Windows操作系統管理進程和線程)4

本書是國内當前集中介紹軟件調試主題的權威著作。本書第2卷分為5篇,共30章,主要圍繞Windows系統展開介紹。第一篇(第1~4章)介紹Windows系統簡史、進程和線程、架構和系統部件,以及Windows系統的啟動過程,既從空間角度講述Windows的軟件世界,也從時間角度描述Windows世界的搭建過程。第二篇(第5~8章)描述特殊的過程調用、墊片、托管世界和Linux子系統。第三篇(第9~19章)深入探讨用戶态調試模型、用戶态調試過程、中斷和異常管理、未處理異常和JIT調試、硬錯誤和藍屏、錯誤報告、日志、事件追蹤、WHEA、内核調試引擎和驗證機制。第四篇(第20~25章)從編譯和編譯期檢查、運行時庫和運行期檢查、棧和函數調用、堆和堆檢查、異常處理代碼的編譯、調試符号等方面概括編譯器的調試支持。第五篇(第26~30章)首先縱覽調試器的發展曆史、工作模型和經典架構,然後分别讨論集成在Visual Studio和Visual Studio(VS)Code中的調試器,最後深度解析WinDBG調試器的曆史、結構和用法。

本書理論與實踐結合,不僅涵蓋了相關的技術背景知識,還深入研讨了大量具有代表性的技術細節,是學習軟件調試技術的珍貴資料。

,
Comments
Welcome to tft每日頭條 comments! Please keep conversations courteous and on-topic. To fosterproductive and respectful conversations, you may see comments from our Community Managers.
Sign up to post
Sort by
Show More Comments
Copyright 2023-2024 - www.tftnews.com All Rights Reserved