Ok j'ai dû chercher, alors si je peux faire gagner un peu de temps à d'autres âmes perdues comme la mienne! J'avais envie de pouvoir sniffer les i/o sur n'importe quel process avec des filtres genre sur les file descriptors (ou FD), sur le type de FD ou sur le nom du process, etc.. histoire de voir dans les protocoles de communication locaux (genre via socket unix de pute de merde $@#!$!@#) comment un daemon communique avec son environnement ou comment (exemple d'OS/X) un programme peut communiquer avec le kernel, oui oui sous OS/X ça "peut" se passer via une socket() et pas via un /dev/bla, ioctl() etc.. ca existe aussi mais dans mon cas c'était dans mon cul... bref...
Donc j'ai commencé par ecrire un LD_PRELOAD, mais ce n'est pas le sujet, je me suis amusé avec dtrace(1) pour voir; pas mal d'outils sous OS/X utilisent dtrace(1), comme "dtruss(1m)" (fourni par default sous OS/X), je vous laisse chercher pour tous les trouver, mais voila un premier pas:
J'en reviens a mon process, je sais pas ce qu'il fait, j'aimerais voir ses read()/write(), je passe un coup d'"lsof" (aka LiSt Open Files) pour voir les FDs (File Descriptors, je me répète et j'en vois plein... alors je me dis merde, j'aimerais bien voir où il écrit, juste voir ce qui se passe sur ce FD, etc... je cherche un peu et je tombe sur:
Content, je m'en vais essayer, mais deception...:
# rwsnoop -p 377 UID PID CMD D BYTES FILE 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx 501 377 iTerm R 42 ptmx
Beuh il me print pas le contenu du read()/write(), genre un bel hexdump aurait été bien agréable, ensuite je ne peux pas filtrer par file descriptor (genre je veux voir juste le #6, je sais ce que c'est $#@!$@#!) et j'aimerais aussi pouvoir voir (quand ça n'est pas un fichier) le type de socket (vu que le type n'est pas fourni par la variable interne dtrace "fds"), histoire de savoir ce qui se passe vraiment et pas croire que c'est une vnode alors qu'en fait c'est une socket à la noix... bref...
Donc la première étape, c'est de dumper le contenu du read()/write() et le return code, c'est parti... je vais expliquer rapidement:
syscall::read:entry
/<predicate>/
{
self->fd = arg0;
self->rarg1 = arg1;
self->rarg2 = arg2;
[...]
}
En gros à l'entrée de read() je sauve les arguments, oui je veux afficher mon code de retour et le read() n'a pas encore été exécuté donc le buffer est toujours vide... du coup :
syscall::read:return
/<predicate>/
{
buffer = copyin(self->rarg1, arg0);
tracemem(buffer, $opt_dumpsz);
printf(\"\n\");
}
donc la à la fin de l'exec, je prends le code de retour (arg0), je copie tout ca dans un buffer local (oui oui on est dans l'addressage du noyau là...) et j'affiche le contenu de la mémoire avec tracemem() tout joli en fonction du type, mais si comme moi vous préférez TOUJOURS avoir un hexdump, magie, simplicité, élasticité... on rajoute ça au debut de son script:
#pragma D option rawbytes
voilà là on voit le contenu avec ce format:
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
0: 03 4f 42 7e 3b 39 35 3b 63 a8 11 16 01 00 00 00 .OB~;95;c.......
10: 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ................
20: 36 00 18 00 00 00 00 00 f0 f0 52 00 01 00 00 00 6.........R.....
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
autre galère, retrouver le type de FD, apres avoir parcouru, diverses choses, je conseille donc aux gens qui se cassent la tête, de farfouiller dans ces liens:
- DTraceToolkit
- DTrace Examples
- DTrace Examples Encore
- DTraceBook Examples Archive
- les files dans /usr/lib/dtrace sous OS/X (il n'y en a pas bcp mais ils sont instructifs..)
je finis par aller voir si dans les struct du noyau je peux accéder à la struct proc (oui elle contient les FDs du process!!), je resume vite fait et simplement il faut passer par la struct task puis récupérer la struct proc (via bsd_info de la structure task), struct filedesc, blablabla jusqu'à la struct fileglob et on finit par voir que la struct proc est accessible via curproc dans dtrace(1), apres du déréferencement à la main on arrive à ça:
curproc->p_fd->fd_ofiles[<FD_num_as_index_of_this_array>]->f_fglob->fg_type
c'est un int avec pour valeurs possibles:
/* file types */ 145#define DTYPE_VNODE 1 /* file */ 146#define DTYPE_SOCKET 2 /* communications endpoint */ 147#define DTYPE_PSXSHM 3 /* POSIX Shared memory */ 148#define DTYPE_PSXSEM 4 /* POSIX Semaphores */ 149#define DTYPE_KQUEUE 5 /* kqueue */ 150#define DTYPE_PIPE 6 /* pipe */ 151#define DTYPE_FSEVENTS 7 /* fsevents */ 152
And voilà....!! maintenant vous reste plus qu'à faire l'amas de ces informations et hop vous avez vos filtres dans votre gentil script dtrace(1)! :)
Maintenant répétez les operations pour avoir filename, socket endpoint, en fonction du type, etc... vous aurez tout ce que vous voulez.
Bon je suis fatigué d'écrire ce truc... j'espère que ça servira à quelqu'un, je retourne lire mes trucs de glands...

