01 2011 档案
摘要: 不要再假装自己写的程序没bug了,不可能的,debug工具你早晚得用上。最常见的debug工具非printf(windows上用OutputDebugString函数)莫属,简单方便易学易用,但局限性也是显而易见的,首先它对debugee的影响很大,某些race condition的bug你要多加几个log它就重现不出来了,然后你把log去了发布给客户,结果又成了必现的bug,这种烂事咱们都碰到过,你懂的。其次log能打印的东西有限,有时候你加log追某个变量的值,追到最后发现是其他变量有问题,这时候你又得加log重新跑。最后分析log的过程及其枯燥无聊,而在debug上敲命令分析则充满了乐趣阅读全文
摘要: IO_STACK_LOCATION很重要,再多聊一点也无妨。上上回我们谈了IO_STACK_LOCATION和那几个重要的函数,当然,我的目的不是扫盲,而是记下一些容易犯错的地方(实际上都是工作中碰到过的钉子)以方便自己回顾。我的记性是如此的差以至于几月不看就会忘记。如果你对这东西没概念,我建议你先多查查WDK文档。上回我们聊了IoCopyCurrentIrpStackLocationToNext和IoSkipCurrentIrpStackLocation的差别(你看我的记性是不是很差,其实是上上回说的),结果把要聊的核心内容给忘了。IO_STACK_LOCATION这坨东西出现的原因很大程度阅读全文
摘要: 今天我们聊一聊CreateFile,这个名字取的不合适但IO的世界里完全绕不过去的东西,以及与之相关的“namespace”这一概念。我们知道Create的意思是创造,创建,上帝创造了这个世界,指的可不是上帝打开了某样存在的东西(唯物主义者,我知道你们有意见,给我闭嘴…),但这个倒霉的函数要做的却是打开。我们也知道File是文件,windows里面也没有“一切都是文件”的概念,但这个倒霉的函数要做的却是打开所有能返回handle的内核对象。Anyway,CreateFile函数是唯一一个能打开内核对象的handle,并让user mode app来访问的方法。将范围缩小到驱动,这个函数也是唯一阅读全文
摘要: 今天我们来聊聊IRQL,这是驱动新手的梦魇,想想看多少BSOD是因为IRQL不对引起的。这也是*NIX类内核开发人员最喜欢的吐槽点之一,你看linux里就没有这个概念,我们还不是活的好好的?我偶尔有时候能得着一些空,也会问一样的问题:为毛?为毛要有这东西存在!后来我想通了。我们先聊passive level和interrupt level。passive level是普通级别,同时也是优先级最低的,所有的用户态线程和大部分的内核态线程都会在这个级别上运行。interrupt level则是中断服务例程的运行级别。这两者有差很好理解,几乎所有os教程里都有告诫我们中断服务例程要尽可能快的完成,并阅读全文
摘要: 如前文所述,nt内核的驱动模型没有完全使用函数调用栈,而是自己山寨出来一个IO_STACK_LOCATION,里面保存了驱动调用序列。我们知道函数调用栈的push和pop都是编译器帮忙弄的,你甚至都可以在完全不了解内幕的前提下写代码,但是驱动开发不一样,调用序列要你自己去关心,何时入栈,何时出栈,栈内保留的什么内容,全部都要照顾好,否则BSOD就在前方不远等你。与IO_STACK_LOCATION有关的函数有以下几个:IoSkipCurrentIrpStackLocation, IoSetNextIrpStackLocation, IoGetNextIrpStackLocation, IoCo阅读全文
摘要: nt内核的IO模型中,IRP有两类:threaded irp和non-threaded irp,顾名思义,前者跟thread绑定,后者跟thread无关。当一个threaded irp被创建时,创建线程会有一个队列保存该irp,直到irp完成之后才释放。当你试图让这条线程退出时,系统会检测队列看里面是否还有irp没完成,如果有,线程会一直等待,直到所有的irp全部完成。而non-thread irp则正好相反,如果该irp已经返回到了创建它的地方你还继续complete它,BSOD将会发生。Threaded IRP如前面所讲,threaded irp和线程绑定在一起。当user mode程序发阅读全文
