Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1315338
  • 博文数量: 554
  • 博客积分: 10425
  • 博客等级: 上将
  • 技术积分: 7555
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-09 09:49
文章分类

全部博文(554)

文章存档

2012年(1)

2011年(1)

2009年(8)

2008年(544)

分类:

2008-04-11 16:00:02


第20 章• fbt 提供器227
0 -> strcopyout
0 -> copyout
0 <- copyout
0 <- strcopyout
0 <- strioctl
0 <- sock_ioctl
0 <- fop_ioctl
0 -> releasef
0 -> clear_active_fd
0 <- clear_active_fd
0 -> cv_broadcast
0 <- cv_broadcast
0 <- releasef
0 <- ioctl
0 <= ioctl
此输出说明,在看上去与套接字关联的文件说明符中,xclock 进程调用了ioctl()。
尝试了解内核驱动程序时,也可以使用FBT。例如,ssd(7D) 驱动程序有很多代码路径,通
过这些路径可以返回EIO。使用FBT 可以轻松地确定导致错误的准确代码路径,如下例所
示:
fbt:ssd::return
/arg1 == EIO/
{
printf("%s+%x returned EIO.", probefunc, arg0);
}
示例
228 Solaris 动态跟踪指南• 2006 年7 月
为了获取所返回的任何一个EIO 的更多信息,您可能希望随机跟踪所有fbt 探测器,然后根
据特定函数的返回值执行commit()(或discard())函数。有关随机跟踪的详细信息,请参
见第13 章。
或者,您可以使用FBT 来了解指定模块中调用的函数。以下示例列出了UFS 中调用的所有
函数。
# dtrace -n fbt:ufs::entry’{@a[probefunc] = count()}’
dtrace: description ’fbt:ufs::entry’ matched 353 probes
^C
ufs_ioctl 1
ufs_statvfs 1
ufs_readlink 1
ufs_trans_touch 1
wrip 1
ufs_dirlook 1
bmap_write 1
ufs_fsync 1
ufs_iget 1
ufs_trans_push_inode 1
ufs_putpages 1
ufs_putpage 1
ufs_syncip 1
ufs_write 1
ufs_trans_write_resv 1
ufs_log_amt 1
ufs_getpage_miss 1
ufs_trans_syncip 1
示例
第20 章• fbt 提供器229
getinoquota 1
ufs_inode_cache_constructor 1
ufs_alloc_inode 1
ufs_iget_alloced 1
ufs_iget_internal 2
ufs_reset_vnode 2
ufs_notclean 2
ufs_iupdat 2
blkatoff 3
ufs_close 5
ufs_open 5
ufs_access 6
ufs_map 8
ufs_seek 11
ufs_addmap 15
rdip 15
ufs_read 15
ufs_rwunlock 16
ufs_rwlock 16
ufs_delmap 18
ufs_getattr 19
ufs_getpage_ra 24
bmap_read 25
findextent 25
示例
230 Solaris 动态跟踪指南• 2006 年7 月
ufs_lockfs_begin 27
ufs_lookup 46
ufs_iaccess 51
ufs_imark 92
ufs_lockfs_begin_getpage 102
bmap_has_holes 102
ufs_getpage 102
ufs_itimes_nolock 107
ufs_lockfs_end 125
dirmangled 498
dirbadname 498
如果您知道内核函数的用途或参数,可以使用FBT 来了解调用函数的方式或原因。例
如,putnext(9F) 接受指向queue(9S) 结构的指针作为其第一个成员。queue 结构的q_qinfo
成员是指向qinit(9S) 结构的指针。qinit 结构的qi_minfo 成员具有一个指向
module_info(9S) 结构(其mi_idname 成员中包含模块名称)的指针。以下示例在putnext 中
使用FBT 探测器将这些信息收集到一起,以便根据模块名称跟踪putnext(9F) 调用:
fbt::putnext:entry
{
@calls[stringof(args[0]->q_qinfo->qi_minfo->mi_idname)] = count();
}
运行上面的脚本将会生成与以下示例类似的输出:
# dtrace -s ./putnext.d
^C
iprb 1
示例
第20 章• fbt 提供器231
rpcmod 1
pfmod 1
timod 2
vpnmod 2
pts 40
conskbd 42
kb8042 42
tl 58
arp 108
tcp 126
ptm 249
ip 313
ptem 340
vuid2ps2 361
ttcompat 412
ldterm 413
udp 569
strwhead 624
mouse8042 726
也可以使用FBT 确定特定函数花费的时间。以下示例说明了如何确定DDI 延迟例程
drv_usecwait(9F) 和delay(9F) 的调用方。
fbt::delay:entry,
fbt::drv_usecwait:entry
{
self->in = timestamp
示例
232 Solaris 动态跟踪指南• 2006 年7 月
}
fbt::delay:return,
fbt::drv_usecwait:return
/self->in/
{
@snoozers[stack()] = quantize(timestamp - self->in);
self->in = 0;
}
在引导期间运行此示例脚本特别有意义。第36 章介绍了在系统引导期间执行匿名跟踪的过
程。重新引导时,您可能会看到与以下示例类似的输出:
# dtrace -ae
ata‘ata_wait+0x34
ata‘ata_id_common+0xf5
ata‘ata_disk_id+0x20
ata‘ata_drive_type+0x9a
ata‘ata_init_drive+0xa2
ata‘ata_attach+0x50
genunix‘devi_attach+0x75
genunix‘attach_node+0xb2
genunix‘i_ndi_config_node+0x97
genunix‘i_ddi_attachchild+0x4b
genunix‘devi_attach_node+0x3d
示例
第20 章• fbt 提供器233
genunix‘devi_config_one+0x1d0
genunix‘ndi_devi_config_one+0xb0
devfs‘dv_find+0x125
devfs‘devfs_lookup+0x40
genunix‘fop_lookup+0x21
genunix‘lookuppnvp+0x236
genunix‘lookuppnat+0xe7
genunix‘lookupnameat+0x87
genunix‘cstatat_getvp+0x134
value ------------- Distribution ------------- count
2048 | 0
4096 |@@@@@@@@@@@@@@@@@@@@@ 4105
8192 |@@@@ 783
16384 |@@@@@@@@@@@@@@ 2793
32768 | 16
65536 | 0
kb8042‘kb8042_wait_poweron+0x29
kb8042‘kb8042_init+0x22
kb8042‘kb8042_attach+0xd6
genunix‘devi_attach+0x75
genunix‘attach_node+0xb2
示例
234 Solaris 动态跟踪指南• 2006 年7 月
genunix‘i_ndi_config_node+0x97
genunix‘i_ddi_attachchild+0x4b
genunix‘devi_attach_node+0x3d
genunix‘devi_config_one+0x1d0
genunix‘ndi_devi_config_one+0xb0
genunix‘resolve_pathname+0xa5
genunix‘ddi_pathname_to_dev_t+0x16
consconfig_dacf‘consconfig_load_drivers+0x14
consconfig_dacf‘dynamic_console_config+0x6c
consconfig‘consconfig+0x8
unix‘stubs_common_code+0x3b
value ------------- Distribution ------------- count
262144 | 0
524288 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 221
1048576 |@@@@ 29
2097152 | 0
usba‘hubd_enable_all_port_power+0xed
usba‘hubd_check_ports+0x8e
usba‘usba_hubdi_attach+0x275
usba‘usba_hubdi_bind_root_hub+0x168
uhci‘uhci_attach+0x191
示例
第20 章• fbt 提供器235
genunix‘devi_attach+0x75
genunix‘attach_node+0xb2
genunix‘i_ndi_config_node+0x97
genunix‘i_ddi_attachchild+0x4b
genunix‘i_ddi_attach_node_hierarchy+0x49
genunix‘attach_driver_nodes+0x49
genunix‘ddi_hold_installed_driver+0xe3
genunix‘attach_drivers+0x28
value ------------- Distribution ------------- count
33554432 | 0
67108864 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
134217728 | 0
尾部调用优化
当一个函数以调用另一个函数而结束时,编译器可能会进行尾部调用优化,优化后,被调
用的函数将重用调用方的栈帧。此过程通常用于SPARC 体系结构中,在此情况下,编译器
在被调用的函数中重用调用方的注册窗口,以便使注册窗口的压力降到最低。
进行此优化会使调用函数的return 探测器在被调用函数的entry 探测器之前触发。这种触
发顺序会导致比较严重的混乱情况。例如,如果要记录从某个特定函数调用的所有函数,
以及此函数调用的所有函数,则可以使用以下脚本:
fbt::foo:entry
{
self->traceme = 1;
}
尾部调用优化
236 Solaris 动态跟踪指南• 2006 年7 月
fbt:::entry
/self->traceme/
{
printf("called %s", probefunc);
}
fbt::foo:return
/self->traceme/
{
self->traceme = 0;
}
但是,如果foo() 以优化的尾部调用结束,那么,在尾部调用的函数以及它调用的任何函数
都不会被捕获。不能即时动态取消内核优化,DTrace 不希望总是考虑如何虚构代码结构。
所以,应清楚什么时候可以使用尾部调用优化。
可以在类似以下示例的源代码中使用尾部调用优化:
return (bar());
或者在类似以下示例的源代码中使用尾部调用优化:
(void) bar();
return;
相反地,结尾方式与以下示例类似的函数源代码不能优化对bar() 的调用,因为对bar() 的
调用不是尾部调用:
bar();
return (rval);
可以使用以下方法确定是否已对某个调用进行了尾部调用优化:
 在运行DTrace 时,跟踪所考虑的return 探测器的arg0。arg0 包含函数中返回指令的偏
移量。
尾部调用优化
第20 章• fbt 提供器237
 在DTrace 停止后,使用mdb(1) 查看该函数。如果跟踪的偏移量包含对另一个函数的调
用,而不是从函数返回的指令,则说明已对调用进行了尾部调用优化。
由于指令集体系结构,尾部调用优化在SPARC 系统上要比在x86 系统上更常见。以下示例
使用mdb 发现内核的dup() 函数中的尾部调用优化:
# dtrace -q -n fbt::dup:return’{printf("%s+0x%x", probefunc, arg0);}’
运行此命令时,将运行执行dup(2) 的程序(如bash 进程)。上面的命令会提供与以下示例
类似的输出:
dup+0x10
^C
现在使用mdb 检查函数:
# echo "dup::dis" | mdb -k
dup: sra %o0, 0, %o0
dup+4: mov %o7, %g1
dup+8: clr %o2
dup+0xc: clr %o1
dup+0x10: call -0x1278
dup+0x14: mov %g1, %o7
该输出说明,dup+0x10 是对fcntl() 函数的调用而不是ret 指令。所以,fcntl() 就是尾部
调用优化的一个示例。
汇编函数
您可能会发现,有时似乎只进入某些函数但却不返回,或者出现相反的情况。这种函数很
稀少,通常是手动编码的汇编例程,这些例程通常分支到其他手动编码的汇编函数中间。
这些函数不应妨碍分析:分支到的目标函数仍然必须返回到其来源函数的调用方。即,如
果启用所有FBT 探测器,则应看到进入某个函数,同时从相同栈深度的另一个函数返回。
汇编函数
238 Solaris 动态跟踪指南• 2006 年7 月
指令集限制
一些函数无法通过FBT 进行检测。不可检测函数的准确特性特定于指令集体系结构。
x86 限制
在x86 系统上不创建栈帧的函数无法通过FBT 进行检测。因为x86 的寄存器集非常小,大多
数函数必须将数据放入栈中,从而创建栈帧。但是,一些x86 函数不创建栈帧,因此无法
对这些函数进行检测。x86 平台上无法进行检测的函数的实际数量不固定,但通常少于百
分之五。
SPARC 限制
无法通过FBT 对SPARC 系统上以汇编语言进行手动编码的叶例程进行检测。大多数内核用
C 语言编写,所有用C 语言编写的函数都可以通过FBT 进行检测。SPARC 平台上无法进行
检测的函数的实际数量不固定,但通常很少。
断点交互
FBT 通过动态修改内核文本进行工作。由于内核断点也通过修改内核文本进行工作,所以
如果在装入DTrace 之前将内核断点放在入口或返回位置,FBT 将拒绝提供用于函数的探测
器,即使随后删除了内核断点也是如此。如果在装入DTrace 之后放置内核断点,则内核断
点和DTrace 探测器将对应于文本中相同的位置。在此情况下,断点将首先触发,然后在调
试器恢复内核时,探测器将触发。建议不要同时使用内核断点和DTrace。如果必须使用断
点,请改为使用DTrace breakpoint() 操作。
模块装入
Solaris 内核可以动态装入和卸载内核模块。当装入FBT 并动态装入模块时,FBT 将自动提
供与新模块关联的新探测器。如果装入的模块未启用FBT 探测器,则可以卸载模块;卸载
模块时,相应的探测器将被破坏。如果装入的模块已启用FBT 探测器,则该模块将被视为
正忙,无法卸载该模块。
模块装入
第20 章• fbt 提供器239
稳定性
FBT 提供器使用DTrace 的稳定性机制说明其稳定性,如下表所示。有关稳定性机制的更多
信息,请参见第39 章。
元素名称稳定性数据稳定性相关性类
提供器发展中发展中ISA
模块专用专用未知
函数专用专用未知
名称发展中发展中ISA
参数专用专用ISA
FBT 显示内核实现时,所有关于实现的内容都不“稳定”-模块和函数名称以及数据稳定
性都明确地显示为“专用”。提供器和名称的数据稳定性为“发展中”,但是所有其他数
据稳定性都为“专用”: 它们是当前实现的产物。FBT 的相关类为ISA: 虽然在当前的所
有指令集体系结构中都可以使用FBT,但不能保证在将来的任意指令集体系结构中都可以
使用FBT。
稳定性
240 Solaris 动态跟踪指南• 2006 年7 月
syscall 提供器
syscall 提供器可在系统中每个系统调用的入口和返回位置提供探测器。因为系统调用是用
户级应用程序和操作系统内核之间的主要接口,所以syscall 提供器可以对系统相关的应用
程序行为提供全面监测。
探测器
syscall 为每个系统调用都提供一对探测器: 在进入系统调用之前触发的entry 探测器,和
在系统调用完成后,但在将控制传送回用户级之前触发的return 探测器。对于所有
syscall 探测器,函数名称将设置为受检测的系统调用的名称,但对模块名称未定义。
可以在/etc/name_to_sysnum 文件中找到syscall 提供器提供的系统调用的名称。通常,
syscall 提供的系统调用名称对应于手册页的第2 节中的名称。但是,syscall 提供器提供
的一些探测器不直接与任何记录的系统调用对应。本节中对此差异的一般原因作了说明。
系统调用记时错误
在一些情况下,syscall 提供器提供的系统调用的名称实际上是旧的实现详细信息的反映。
例如,因为一些追溯到UNIXTM 的过去的原因,/etc/name_to_sysnum 中exit(2) 的名称为
rexit。类似地,time(2) 的名称为gtime,execle(2) 和execve(2) 的名称为exece。
子编码的系统调用
第2 节中说明的一些系统调用实现为未记录的系统调用的子操作。例如,与System V 信号
(semctl(2)、semget(2)、semids(2)、semop(2) 和semtimedop(2))相关的系统调用实现为单
个系统调用semsys 的子操作。semsys 系统调用将特定于实现的子代码作为其第一个参数,
该子代码表示所需的特定系统调用:SEMCTL、SEMGET、SEMIDS、SEMOP 或SEMTIMEDOP。由于
过载一个系统调用以实现多个系统调用,所以对于System V 信号仅有一对syscall 探测器
:syscall::semsys:entry 和syscall::semsys:return。
21 第2 1 章
241
大文件系统调用
支持大小超过4GB 的大文件的32 位程序必须能够处理64 位文件偏移。因为大文件需要使
用大偏移,所以通过一组并行的系统接口处理大文件,如lf64(5) 中所述。lf64 中记录了这
些接口,但这些接口没有单独的手册页。如表21–1 中所示,每一个大文件系统调用接口都
显示为各自的syscall 探测器。
表21–1 sycall 大文件探测器
大文件syscall 探测器系统调用
creat64 creat(2)
fstat64 fstat(2)
fstatvfs64 fstatvfs(2)
getdents64 getdents(2)
getrlimit64 getrlimit(2)
lstat64 lstat(2)
mmap64 mmap(2)
open64 open(2)
pread64 pread(2)
pwrite64 pwrite(2)
setrlimit64 setrlimit(2)
stat64 stat(2)
statvfs64 statvfs(2)
专用系统调用
一些系统调用为跨越用户内核边界的Solaris 子系统的专用实现详细信息。同样地,这些系
统调用在第2 节中没有手册页。此类别中的系统调用示例包括signotify 系统调用(用作实
现POSIX.4 消息队列的一部分)和utssys 系统调用(用于实现fuser(1M))。
探测器
242 Solaris 动态跟踪指南• 2006 年7 月
参数
对于entry 探测器,参数(arg0 .. argn)是系统调用的参数。对于return 探测器,arg0 和
arg1 包含返回值。D变量errno 中的非零值指示系统调用失败。
稳定性
syscall 提供器使用DTrace 的稳定性机制说明其稳定性,如下表所示。有关稳定性机制的
更多信息,请参阅第39 章。
元素名称稳定性数据稳定性相关性类
提供器发展中发展中公用
模块专用专用未知
函数不稳定不稳定ISA
名称发展中发展中公用
参数不稳定不稳定ISA
稳定性
 
 
以上文章转自于 : http://developers.sun.com.cn/
阅读(564) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~