使用ETW对程序进行监控和分析

ETW(Event Tracing for Windows)是Windows提供的对程序进行事件记录,跟踪,使用的机制。我们可以利用这个机制对程序进行调试和性能分析。从Windows Vista开始,ETW已经非常好的融合在Windows内核之中了,在Windows 7开始,这一个机制更加完善,几乎记录了Windows运行的每一个细节。我个人猜测,从Windows Vista开始到Windows 7直到现在的Windows 8,性能都在不断提高,ETW机制应该是功不可没的。

ETW是Windows提供的机制,我们要使用他还需要工具,这些工具我们可以自己开发,因为Windows提供了调用接口。当然,更惬意的选择就是直接使用Windows提供的工具集WPT(Windows Performance Toolkit)。利用WPT和SDK,我们可以将ETW融入到我们自己的程序中,帮助我们调试程序和提升性能。

以下是我们需要的工具:
SDK:

  1. ECMangen.exe
  2. mc.exe

Windows:
WEVTUtil.exe

WPT:

  1. XPerf.exe
  2. XPerfView.exe

首先我们需要用SDK中的工具ECMangen,生成一个manifest文件,这个文件用来描述记录的事件,如图。
20131117114336
这里,我们首先创建一个Provider,接下来创建一个Event,参数可以随便填下,就像上图所示。作为演示,这里一个Event就够了(FirstEvent)。
然后保存为0CChProvider.man。

接下来我们MC来生成一个头文件,一个资源文件和两个二进制文件。命令行如:
mc -um C:\etw\0CChProvider.man
20131117114801

然后我们可以创建一个工程,加入这个头文件和资源文件。并且在代码中插入写事件的代码,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "stdafx.h"
#include
#include "../../0CChProvider.h"


int _tmain(int argc, _TCHAR* argv[])
{
EventRegisterMy0CChProvider();
EventWriteFirstEvent(L"Hello ETW World!");
Sleep(1000);
EventWriteFirstEvent(L"Bye ETW World!");
EventUnregisterMy0CChProvider();
return 0;
}

在这里,我们利用EventRegisterMy0CChProvider先注册自己的Provider,接下写事件才会发挥作用。记录事件后,我们需要反注册Provider。
好了,演示代码就这么一点,然后编译即可。

接下来我们需要注册这个Provider给系统,需要使用到系统自带的工具WEVTUtil.exe。
wevtutil im C:\etw\0CChProvider.man

注册成功后就可以利用XPerf开启ETW,然后运行程序,查看记录的事件了。

  1. xperf -start 0cch -on My0CChProvider:::’stack’
  2. xperf -on base
  3. Run 0CChProvider.exe
  4. xperf -stop 0cch -stop -d d:\0cch.etl
  5. xperf d:\0cch.etl

XPerfView会生成分析数据如图:
20131117115853

20131117120007

整体来说,想简单的使用ETW也就是这么简单,当然你也可以把他弄得很复杂,这里就不介绍了。话说sysdbg早就让我写点XPerf的东西,但是因为各种懒没写,刚好最近终于有空了,就先写了这么个简单的介绍,就当作一个开篇吧,话说某人的Blog好久没更新了呀。。。

DebuggingNTInternals

Windbg script中获得调试环境的基本信息

今天继续来玩Windbg script。在写复杂的脚本的时候,可能需要根据调试的环境,指定不同的脚本代码来运行。而Windbg貌似没有提供很好的方式,让脚本得知调试环境。还好,我们可以用一些其他的方式获得这些信息,例如:写一个扩展程序来设置这些信息到Aliase上,0cchext就实现了这个功能。另外一个方式就是使用脚本自身来获得一些简单的信息,算是个windbg script中的小把戏吧。脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$$ Initialize script environment
$$ Author: nighxie
$$ Blog: 0cch.net
$$ @#NtMajorVersion @#NtMinorVersion - System version number.
$$ @#DebugMode - 0:kd 1:lkd 2:user

ad /q ${/v:$sharedata}

.catch {
.foreach /pS 2 (${/v:$addr} {!kuser}) {
aS ${/v:$sharedata} ${$addr};
.leave;
}
}

.block {
r @$t0=${$sharedata};
aS /x ${/v:@#NtMajorVersion} @@C++(((nt!_KUSER_SHARED_DATA *)@$t0)->NtMajorVersion);
aS /x ${/v:@#NtMinorVersion} @@C++(((nt!_KUSER_SHARED_DATA *)@$t0)->NtMinorVersion);
}

ad /q ${/v:$sharedata}

.catch {
r @$t0 = 0;
.foreach (${/v:$addr} {lm1m m nt}) {
r @$t0 = ${$addr};
.leave;
}
}

.if ($vvalid(@$t0, 1)) {
aS ${/v:@#DebugMode} 0;
.foreach (${/v:$val} {.catch{? @eax}}) {
.if ($scmp("${$val}", "\'@eax\'")==0) {
aS ${/v:@#DebugMode} 1;
}
}
}
.else {
aS ${/v:@#DebugMode} 2;
}

DebuggingTips