Vous pouvez utiliserFBT pour explorer facilement l'implémentation du noyau. Le script suivant, donné à titre d'exemple, enregistre le premier ioctl(2) d'un processus xclock quelconque puis vient après le chemin de code suivant dans le noyau :
/*
* To make the output more readable, we want to indent every function entry
* (and unindent every function return). This is done by setting the
* "flowindent" option.
*/
#pragma D option flowindent
syscall::ioctl:entry
/execname == "xclock" && guard++ == 0/
{
self->traceme = 1;
printf("fd: %d", arg0);
}
fbt:::
/self->traceme/
{}
syscall::ioctl:return
/self->traceme/
{
self->traceme = 0;
exit(0);
}
Exécuter ce script engendre une sortie identique à l'exemple suivant :
# dtrace -s ./xioctl.d dtrace: script './xioctl.d' matched 26254 probes CPU FUNCTION 0 => ioctl fd: 3 0 -> ioctl 0 -> getf 0 -> set_active_fd 0 <- set_active_fd 0 <- getf 0 -> fop_ioctl 0 -> sock_ioctl 0 -> strioctl 0 -> job_control_type 0 <- job_control_type 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 |
La sortie montre qu'un processus xclock a appelé ioctl() sur un descripteur de fichier qui semble être associé à un socket.
Vous pouvez également utiliser FBT pour comprendre les pilotes de noyau. Par exemple, le pilote ssd(7D) dispose de nombreux chemins de code par l'intermédiaire desquels EIO est susceptible d'être renvoyé. FBT peut facilement être utilisé pour déterminer le chemin de code précis ayant engendré une condition d'erreur, comme illustré dans l'exemple suivant :
fbt:ssd::return
/arg1 == EIO/
{
printf("%s+%x returned EIO.", probefunc, arg0);
}
Pour plus d'informations sur les retours de EIO, il est possible de procéder au suivi spéculatif des sondesfbt puis d'exécuter commit()(ou discard()) en fonction de la valeur de retour d'une fonction spécifique. Pour de plus amples informations sur le suivi spéculatif, reportez-vous au Chapitre13Suivi spéculatif.
Sinon, vous pouvez utiliser FBT pour comprendre les fonctions appelées au sein d'un module spécifié. L'exemple suivant répertorie toutes les fonctions appelées dans 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
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
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
|
Si vous connaissez l'objectif ou les arguments d'une fonction de noyau, vous pouvez utiliser FBT pour comprendre de quelle manière et pour quelle raison la fonction est appelée. Par exemple, putnext(9F) prend un pointeur dans une structure queue(9S) comme premier membre. Le membre q_qinfo de la structure queue est un pointeur sur une structure qinit(9S). Le membre qi_minfo de la structure qinit dispose d'un pointeur sur une structure module_info(9S), qui contient le nom du module dans son membre mi_idname. L'exemple suivant rassemble ces informations en utilisant la sonde FBT dans putnext pour procéder au suivi des appels putnext(9F) par nom de module :
fbt::putnext:entry
{
@calls[stringof(args[0]->q_qinfo->qi_minfo->mi_idname)] = count();
}
Exécuter le script ci-dessus engendre une sortie similaire à l'exemple suivant :
# dtrace -s ./putnext.d ^C iprb 1 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 |
Vous pouvez également utiliser FBT pour déterminer le temps écoulé dans une fonction donnée. L'exemple suivant montre comment déterminer les programmes appelants des routines de délai DDI drv_usecwait(9F) et delay(9F).
fbt::delay:entry,
fbt::drv_usecwait:entry
{
self->in = timestamp
}
fbt::delay:return,
fbt::drv_usecwait:return
/self->in/
{
@snoozers[stack()] = quantize(timestamp - self->in);
self->in = 0;
}
Il est particulièrement intéressant d'exécuter ce script, donné à titre d'exemple, pendant l'initialisation. Le Chapitre36Suivi anonyme décrit la procédure permettant de réaliser un suivi anonyme pendant l'initialisation du système. Lors de la réinitialisation, une sortie similaire à l'exemple suivant s'affichera vraisemblablement :
# 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
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
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
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
|