您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

读《软件调试》第九章

2024/12/19 9:05:30发布15次查看
今日读了张银奎老师的《软件调试》,前面的cpu和硬件相关的部分离得比较远,所以从第九章操作系统读起,今天的读书笔记: 9.2采集调试消息 调试事件分为8种 typedef enum _dbgkm_apinumber { dbgkmexceptionapi = 0, // 异常 dbgkmcreatethreadapi = 1, //
今日读了张银奎老师的《软件调试》,前面的cpu和硬件相关的部分离得比较远,所以从第九章操作系统读起,今天的读书笔记:
9.2采集调试消息
调试事件分为8种
typedef enum _dbgkm_apinumber
{
dbgkmexceptionapi = 0, // 异常
dbgkmcreatethreadapi = 1, // 创建线程
dbgkmcreateprocessapi = 2, // 创建进程
dbgkmexitthreadapi = 3, // 退出线程
dbgkmexitprocessapi = 4, // 进程退出
dbgkmloaddllapi = 5, // 映射dll
dbgkmunloaddllapi = 6, // 反映射dll
dbgkmerrorreportapi = 7, // 内部错误
dbgkmmaxapinumber = 8, // 这组常量的最大值
} dbgkm_apinumber;
9.2.2 进程和线程创建消息
操作系统就支持向调试系统发送消息,这个我是没有想到的,具体过程如下:
创建用户态windows线程时,首先为线程建立必要的内核对象和数据结构,并分配栈(stack)空间,这些工作完成后,
该线程处于挂起状态(create_suspend), 而后进程管理器会通知环境子系统,环境子系统会作必要的设置和登记,最后
进程管理器会调用pspuserthreadstartup例程,准备启动该线程。
为了支持调试,pspuserthreadstartup总是会调用调试子系统的内核函数dbgkcreatethread,以便让调试子系统得到处理机会。
dbgkcreatethread会检查新创建线程所在的进程是否正在被调试(根据debugport是否为空),如果不是,便立即返回,
如果是,则会继续检查该进程的用户态运行时间(usertime)是否为0,目的是判断该线程是否是进程中的第一个线程,如果是,
则通过dbgksendapimessage()函数向debugport发送dbgkmcreateprocessapi消息,如果不是,
则发送dbgkmcreatethreadapi消息。
调试器收到的进程创建(create_process_debug_event,值为3)和线程创建(create_thread_debug_event,值为2)事件就是源于这两个消息。
9.2.3 进程和线程退出消息 --- 与上面类似
9.2.4 模块映射和反映射消息
dll(dynamic-link library)是windows中使用最多的技术之一。如:
windows内核文件ntoskrnl.exe虽然是exe后缀,其实质是一个dll;
ntdll.dll是连接用户态和操作系统内核的桥梁,用户态代码通过它访问内核服务;
windows子系统dll(kernel32.dll,advapi32.dll,user32.dll,gdi32.dll)是windows api的载体;
观察进程中的dll:
1.运行notepad.exe
2.启动vc6,通过build>start debug>attatch to process...菜单弹出attach process对话框,然后选择notepad.
3. 通过debug>modules...菜单弹出模块列表,便可以看到notepad进程中的dll了。
第二列是该模块在进程空间中的地址(虚拟地址,均小于0x80000000),可见这些模块都是位于用户空间中的。
存在于多个进程空间中的dll,是否会重复占用内存?
否!当loadlibrary()和loadlibraryex() api加载一个dll时,会首先判断该dll是否已经加载过,如果是,则不会重复加载,
只是将该dll对应的内存页面映射(map)到目标进程的内存空间,并把该dll的引用次数加1.
当进程退出或调用freelibrary() api要卸载一个dll时,windows会从进程的虚拟内存空间中把该dll的映射删除(unmap),
并递减该dll的引用次数,如果引用次数变为0,那么该dll会被彻底移出内存。
9.2.5 异常消息
为了支持调试,系统会把被调试程序中发生的所有异常发送给调试器。
内核中kidispatchexception函数是分发异常的枢纽,它会给每个异常安排最多两轮被处理的机会,
对于每一轮处理机会,它都会调用调试子系统的dbgkforwardexception函数来通知调试子系统。
总结:
系统的进程管理器、内存管理器和异常分发函数会调用调试子系统的dbgk采集例程,来向调试子系统通报调试消息,
这些例程被调用后会根据当前进程的debugport字段来判断当前进程是否处于被调试状态。
如果不是,便忽略这次调用,直接返回;
如果是,便产生一个dbgkm_apimsg结构,然后调用下一节将介绍的dbgksendapimessage函数来发送调试消息。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product