全部分类 | General | Music | Solaris

« Previous month (Apr 2005) | Main | Next month (Jun 2005) »
 20050621 星期二 2005年06月21日

How to Write a KMOD

How to write a kmod module

This is a re-post, because I deleted this article by accident.

Writing a KMDB module is slightly different from writing a MDB one, especially in building the binary file, now I'm trying to illustrate the difference between them. Here's a simple kmod that contains only one dcmd:

$ cat simple_trace.c
#include <sys/mdb_modapi.h>

static int
simple_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
        /* do nothing */
        mdb_printf("Hello KMDB");
        return DCMD_OK;
}

static const mdb_dcmd_t dcmds[] = {
        {"simple_trace", "wait...", "Hello world", simple_trace },
        { NULL }
};

static const mdb_modinfo_t modinfo = {
        MDB_API_VERSION, dcmds, NULL
};

const mdb_modinfo_t *
_mdb_init(void)
{
        return &modinfo;
}

When running this dcmd, it does nothing but print "Hello KMDB" on the console, but this is a good start point to write a real kmod.

As you can see, the source code looks no difference from a MDB module, but the Makefile is different:

$ cat Makefile
OBJS = simple_trace.o
KMODULE = simple_trace

CFLAGS +=  -D_KERNEL -D_KMDB

CC=cc
LD=ld

all: $(OBJS)
        $(LD) -dy -r -Nmisc/kmdbmod -o $(KMODULE) $(OBJS)

.KEEP_STATE:

%.o: %.c
        $(CC) $(CFLAGS) -c $<

clean:
        rm -f $(OBJS)

It modifies the .dynamic section of the binary file, and make it loadable to KMDB. You can now load this module into KMDB:

# mdb -K

Welcome to kmdb
Loaded modules: [ crypto ptm ufs unix krtld sppp nca uhci lofs genunix ip
logindmux usba specfs nfs random sctp ]
[1]> ::load /tmp/simple_trace
Loaded modules: [ simple_trace ]
[0]> ::simple_trace
Hello KMDB
[0]>

and check what ld did to the binary file:

$ elfdump simple_trace
......
Dynamic Section:  .dynamic
     index  tag            value
       [0]  NEEDED         0x1             misc/kmdbmod
       [1]  FLAGS          0x4             [ TEXTREL ]
       [2]  FLAGS_1        0               0
Technorati Tag:
Technorati Tag:
Technorati Tag: 发表于 yu [Solaris] ( 六月 21, 2005 09:08 上午 ) Permalink | 评论 [0]
 20050614 星期二 2005年06月14日

OpenSolaris is alive!

That's Great! Technorati Tag:
Technorati Tag:
发表于 yu [Solaris] ( 六月 14, 2005 11:00 下午 ) Permalink | 评论 [0]

 20050608 星期三 2005年06月08日

Hello World in KMDB module

最近用KMDB跟踪FireEngine的代码时,总觉得不方便,但究竟是哪里不方便,我自己也说不清楚。第一反应是也许可以写一个kmod来让某些复杂的调试步骤简单化一点。出于这个目的,开始着手写kmod。

然而网上资料虽然很丰富,竟然Google不到kmod的资料!就算能找到的也只是关于MDB的——Google上没有的,我就认为它不存在了——因此我把编写kmod的基本步骤写在这里,当作一个小小的Hello World教程。

程序的代码如下,它只提供了一个很简单的dcmd,因为我的目的在于演示如何编译生成kmod:

$ cat simple_trace.c
#include <sys/mdb_modapi.h>

static int
simple_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
        /* do nothing */
        mdb_printf("Hello KMDB");
        return DCMD_OK;
}

static const mdb_dcmd_t dcmds[] = {
        {"simple_trace", "wait...", "Hello world", simple_trace },
        { NULL }
};

static const mdb_modinfo_t modinfo = {
        MDB_API_VERSION, dcmds, NULL
};

const mdb_modinfo_t *
_mdb_init(void)
{
        return &modinfo;
}

通过下面的Makefile来编译:

$ cat Makefile
OBJS = simple_trace.o
KMODULE = simple_trace

CFLAGS += -D_KERNEL -D_KMDB

CC=cc
LD=ld

all: $(OBJS)
        $(LD) -dy -r -Nmisc/kmdbmod -o $(KMODULE) $(OBJS)

.KEEP_STATE:

%.o: %.c
        $(CC) $(CFLAGS) -c $<

clean:
        rm -f $(OBJS)

明眼人一看就明白,其实最后的差别很简单,在kmod中对.dynamic做了一些特殊处理。当然,在Solaris内核里还有一些其他的操作,但不是必须的,所以略过了。

$ elfdump simple_trace
......
Dynamic Section:  .dynamic
     index  tag               value
       [0]  NEEDED         0x1             misc/kmdbmod
       [1]  FLAGS            0x4             [ TEXTREL ]
       [2]  FLAGS_1        0                 0

Sign,原来就这么简单,还害得我一直读到了IP kmod的Makefile里才搞明白。好了,废话少说,接着看intern的简历。

Update:运行结果:

# mdb -K

Welcome to kmdb
Loaded modules: [ crypto ptm ufs unix krtld sppp nca uhci lofs genunix ip
logindmux usba specfs nfs random sctp ]
[1]> ::load /tmp/simple_trace
Loaded modules: [ simple_trace ]
[0]> ::simple_trace
Hello KMDB
[0]>

发表于 yu [Solaris] ( 六月 08, 2005 02:24 下午 ) Permalink | 评论 [3]
 20050602 星期四 2005年06月02日

用DTrace跟踪TCP报文

DTrace是Solaris 10提供的一个非常强大的工具,在它的manual里有这么一句话:“use it, learn it, love it”,由此也可以看出它对UNIX程序员的吸引力。在这里提供一小段脚本,是前段时间我在研究FireEngine代码时写来练手的,可以用它来跟踪Solaris在TCP连接建立时的函数调用关系,稍作修改还可以用在很多其它场合。

DTrace的脚本语言叫D语言,它的语法和C语言很类似,但是如果把它和C语言混为一谈那就大错特错了。和其他脚本语言一样,要在文本的第一行加上执行的程序:

#! /usr/sbin/dtrace -s

这句话的意思表示运行结果采用缩进显示方式,语法很像C语言中的#pragma语句:

#pragma D option flowindent

BEGIN表示在进行DTrace probe之前需要执行的语句,如果对awk(1)比较熟悉的话,要理解它很容易。

BEGIN
{
PROTO_TCP = 6;
IP_HEADER = 20;
TH_SYN = 2;
}

这里初始化了几个常量,非别表示的是TCP在IP报文头中的协议号,IP报文头的长度,以及TCP SYN标志位的值。

再花一两句话时间介绍一下DTrace的程序结构。在一个DTrace的脚本中可以定义一个或多个probe description,它的结构如下:predicate,用谓词逻辑中的predicate(断言)来理解它挺合适,另外在C++的boost库中也有predicate,概念也很类似但是形式上很遥远。在一个probe description上,当断言的条件满足时,就会执行{}之间的语句。

probe descriptions
/ predicate /
{
action statements
}

显然,在下面这段probe中,表示在ip_rput函数的入口处开始跟踪,直到ip_rput函数结束。条件比较复杂,判断报文是不是设置了TCP SYN标记。

fbt::ip_rput:entry
/((ipha_t*)args[1]->b_rptr)->ipha_protocol == PROTO_TCP &&
(((tcph_t*)&args[1]->b_rptr[IP_HEADER])->th_flags[0] & TH_SYN) == TH_SYN/
{
self->traceme = 1;
printf("%s(%d, %x, %d)\n", probefunc, arg0, arg1, arg2);
}
fbt::ip_rput:return
/self->traceme/
{
self->traceme = 0;
exit(0);
}

fbt:::
/self->traceme/
{}

在机器上运行这个脚本,然后telnet过去,立刻就能看到运行结果,几乎是全部的函数调用关系。

值得指出的是,虽然DTrace很强大,但是由于DTrace只能跟踪函数的调用,对于更细节的跟踪...当然还得用mdb,在下一次有时间的时候我可能会写一点怎么用mdb来做跟踪的例子。

发表于 yu [Solaris] ( 六月 02, 2005 04:33 下午 ) Permalink | 评论 [0]