Luigi Catuogno Dipartimento di Informatica ed Applicazioni Università degli Studi di Salerno [email protected] Cos’è DTrace • Un sofisticato sistema di debugging • Integrato nel sistema operativo • Tracciamento dinamico a run-time dell’esecuzione – Applicazioni – Sistema operativo Dtrace: cenni storici • Sviluppato dalla Sun Microsystem nel novembre 2003 • Distribuito nel 2005 come componente di Solaris 10 • Codice sorgente distribuito, come componente di Open Solaris – licenza Common Development Distribution License (CDDL) – Disponibile su: • NetBSD, FreeBSD, Mac OS X 10.5 “Leopard” – Porting in corso: • Linux, QNX 6 DTrace: cenni storici • Creato da: – Bryan Cantrill, Mike Shapiro, Adam Leventhal • Premi e riconoscimenti: – InfoWorld and Technology Review(2005) – Technical Innovation Awards Competition Wall Street Journal (2006) – USENIX (2008) Cosa fa Dtrace/1 • Attivazione dinamica, a run-time di “sonde” (probes) per la rilevazione di eventi di interesse nell’esecuzione del sistema operativo e nelle applicazioni • Tracing di variabili e strutture dati Cosa fa Dtrace/2 • Definizione di sequenze di “azioni” associate agli eventi di interesse – Linguaggio D, per la definizione delle azioni • Esecuzione, a run time, delle azioni associate agli eventi rilevati dalle sonde attivate Cosa permette DTrace • Può tracciare l’esecuzione di codice – Compilato da terze parti – Senza supporto per il debugging – Sorgenti non disponibili – Senza bisogno di ri-compilare • Già in esecuzione – Senza bisogno di ri-lanciare il processo – Senza alterare significativamente • Comportamento • Prestazioni Linguaggio D • Linguaggio di scripting utilizzato per – identificare la/le probes da attivare • eventi di interesse – Definizione di predicati per ulteriore filtraggio degli eventi – Definizione delle azioni associate all’evento Linguaggio D: clausola probe description /predicate/ { actions } Esempio 1 syscall::write:entry /execname == “bash”/ { printf (“bash (%d) writes something!\n”, pid); } Linguaggio D: • Probe description – nella forma provider:module:function:name pid1234:libc:malloc:entry syscall::read*: sysinfo:::pswitch – module, function e name sono opzionali – sono ammesse wildcards ‘*’ e ‘?’ • Quando un evento si verifica si dice che la sonda corrispondente “spari” (the probe fires) I Provider • Indicano il “livello” al quale viene effettuato il tracing: – syscall: livello interfaccia system calls – io: disk I/O – pid: chiamate a funzioni in un processo – sysinfo: statistiche a livello kernel – proc: informazioni sul ciclo di vita dei processi – sched: informazioni sugli eventi di scheduling Moduli e funzioni • Moduli – componenti (ove presenti) dell’eseguibile tracciato • pid135:libc::entry • pid334:a.out:foo: • Funzioni – funzioni da tracciare: • syscall::open: • pid334::printf:entry Funzioni ed Eventi • La sonda syscall::open:entry – attiva una sonda “sulla system call open” e spara quando la system call viene invocata syscall::open:return – spara quando la system cal restituisce il controllo al chiamante sysinfo:::pswitch – spara ogni volta che un processo viene eseguito dalla CPU Predicati • Valutati se la sonda cui sono associati spara • Restituiscono vero o falso • Le azioni della clausola vengono eseguite se il predicato restituisce vero /execname == “bash”/ /ppid != 0/ /probemod == “sendmail”/ Predicati e variabili built-in pid, ppid process id, parent process id uid, gid execname user id, group id arg0,arg1,… probemod, probefunc argomenti della funzione/system call nome dell’eseguibile nomi del modulo/funzione su cui la sonda è attivata Dtrace: Azioni • descritte in un sottoinsieme del C • utilizzano funzioni e variabili built-in { printf(“Il processo %s(%d) è stato lanciato da %d”, execname, pid, uid); } esempio: primo.c int main(void) { int fd; char cmd[3]; int i=0, r; bzero(cmd,4); while(!i) { fd=open("cmd",O_RDONLY); if(fd<0) { fprintf(stderr,"Impossibile aprire il file"); exit(0); } r=read(fd,cmd,3); if(!strncmp(cmd,"END",3)) i=1; close(fd); } } esempio: primo.d syscall::read:entry /execname == "primo"/ { printf("L'eseguibile %s(%d), ha invocato read\n", execname,pid); } primo.d: ouput >sudo dtrace -s primo.d Password: dtrace: script 'primo-1.d' matched 5 probes CPU ID FUNCTION:NAME 0 13940 read_nocancel:entry L'eseguibile primo(325) ha invocato read 0 13940 read_nocancel:entry L'eseguibile primo(325) ha invocato read ….. Esempio: secondo.c int main(void) { int fd, i=0,r; char cmd[3]; … while(!i) { fd=open("cmd",O_RDONLY); if(fd<0) { …. } r=read(fd,cmd,3); if(!check(cmd)) i=1; close(fd); } } int check(char *cmd) { return strncmp(cmd,"END",3); } Esempio: secondo.d pid392:::entry { printf("L'eseguibile %s(%d) ha invocato %s--%s\n", execname, pid, probemod, probefunc); } secondo.d: output dtrace: script 'secondo-2.d' matched 5739 probes CPU ID FUNCTION:NAME 0 17067 open$UNIX2003:entry L'eseguibile secondo(392) ha invocato libSystem.B.dylib--open$UNIX2003 0 16938 read:entry L'eseguibile secondo(392) ha invocato libSystem.B.dylib--read 0 16778 check:entry L'eseguibile secondo(392) ha invocato secondo--check 0 16993 strncmp:entry L'eseguibile secondo(392) ha invocato libSystem.B.dylib--strncmp 0 16939 close$NOCANCEL$UNIX2003:entry L'eseguibile secondo(392) ha invocato libSystem.B.dylib--close$NOCANCEL$UNIX2003 Alcune domande.. • C’è un browser in esecuzione: – Quali file apre? – A quali server si connette? Esempio: si vuole tracciare il processo execname = firefox-bin pid = 158 esempio: firefox.d pid158::open*:entry { printf("Aperto il file: %s, mode=%o\n", copyinstr(arg0),arg1); } firefox.d: ouput CPU ID FUNCTION:NAME 0 16776 opendir$UNIX2003:entry Aperto il file: /System/Library/PrivateFrameworks/Shortcut.framework, mode=0 0 16774 open$NOCANCEL$UNIX2003:entry Aperto il file: /System/Library/PrivateFrameworks/Shortcut.framework, mode=4000004 0 16776 opendir$UNIX2003:entry Aperto il file: /System/Library/PrivateFrameworks/Shortcut.framework/Resources, mode=0 0 16774 open$NOCANCEL$UNIX2003:entry Aperto il file: /System/Library/PrivateFrameworks/Shortcut.framework/Resources, mode=4000004 0 16775 open$UNIX2003:entry Aperto il file: /dev/autofs_nowait, mode=0 … esempio: firefox-2.d syscall::socket*:entry /execname=="firefox-bin"/ { printf("creato un socket famiglia %d\n",arg0); } syscall::connect*:entry /execname=="firefox-bin"/ { this->sa=(struct sockaddr_in *) copyin(arg1,arg2); printf("Connect: \n"); printf("\t: socket_fd=%d\n",arg0); printf("\t: sa.sin_addr=%x\n", (this->sa->sin_addr.s_addr)); } firefox-2.d: output 0 13342 socket:entry creato un socket famiglia 2 0 13966 connect_nocancel:entry Connect: : socket_f6 : sa.sin_addr=d55c10bf 0 13342 socket:entry creato un socket famiglia 2 0 13966 connect_nocancel:entry Connect: : socket_fd=35 : sa.sin_addr=d55c10bf Esempio: firefox-3.d pid158::malloc:entry { @total=sum(arg0) } firefox-3.d: output >sudo dtrace -s firefox-3.d Password: dtrace: script 'firefox-1.d' matched 2 probes ^C 79749177 Aggregazione dati count() Contatore monotono sum() avg() sommatore min()/max() media aritmetica esempio: firefox-4.d syscall:::entry /execname=="firefox-bin"/ { @[probefunc]=count(); } firefox-4.d: output dtrace: script 'firefox-4.d' matched 427 probes ^C fsync_nocancel 2 ftruncate 2 rename 2 pread 5 access 8 __disable_threadsignal 10 bsdthread_create 10 bsdthread_terminate 10 getdirentriesattr 10 stat 10 close 17 fstat 17 open 17 mprotect 31 Questa presentazione • Luigi Catuogno – [email protected] – (oppure venite a trovarmi…) • Tutti gli esempi sono stati realizzati e testati (per questioni di tempo) su – Mac PowerBook G4 • Mac OS X 10.5.8 FONTI RISORSE WEB http://dtrace.org http://hub.opensolaris.org/bin/view/Community+Group+dtrace/dtracetoolkit http://www.opensource.apple.com/source/dtrace/ http://www.crisp.demon.co.uk/blog/index.html http://sourceware.org/systemtap/ http://video.google.com/videoplay?docid=-8002801113289007228#