Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico...

144
Facoltà di Ingegneria Corso di Studi in Ingegneria Informatica tesi di laurea Studio e implementazione di meccanismi di probing del kernel 2.6 di Linux Anno Accademico 2005/2006 relatore Ch.mo Prof. Domenico Cotroneo correlatore Ing. Armando Migliaccio candidato Paolo Guadagnuolo matr. 534/752

Transcript of Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico...

Page 1: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Facoltà di Ingegneria Corso di Studi in Ingegneria Informatica tesi di laurea

Studio e implementazione di meccanismi di probing del kernel 2.6 di Linux Anno Accademico 2005/2006 relatore Ch.mo Prof. Domenico Cotroneo correlatore Ing. Armando Migliaccio candidato Paolo Guadagnuolo matr. 534/752

Page 2: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Indice

1 Introduzione 31.1 Il Software Libero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.1.1 Genesi del Software Libero . . . . . . . . . . . . . . . . . . . . . . . . 31.1.2 Licenze di Software Libero . . . . . . . . . . . . . . . . . . . . . . . . . 41.1.3 Vantaggi e svantaggi . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.2 Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.2.1 Vantaggi e Svantaggi . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.2.2 Diffusione di Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.2.3 Il modello di sviluppo di Linux . . . . . . . . . . . . . . . . . . . . . . 8

1.3 Il kernel di Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101.4 Debugging del kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

1.4.1 Utilizzo di printk() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131.4.2 Altre soluzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141.4.3 KProbes & SystemTAP . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2 KProbes e SystemTAP 172.1 Le interfacce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.1.1 kprobe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.1.2 jprobe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202.1.3 Funzioni di gestione dei probing points . . . . . . . . . . . . . . . . . . 21

2.2 SystemTAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212.2.1 Procedura di processing di SystemTAP . . . . . . . . . . . . . . . . . 212.2.2 Basi del linguaggio di scripting . . . . . . . . . . . . . . . . . . . . . . 222.2.3 Macro e files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

2.3 Esempi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352.3.1 Kprobes - Monitoraggio di kmalloc . . . . . . . . . . . . . . . . . . 352.3.2 Jprobes - Monitoraggio di kmalloc . . . . . . . . . . . . . . . . . . . 382.3.3 SystemTAP - Monitoraggio di kmalloc con statistiche . . . . . . . . 41

2.4 Funzionamento Interno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492.4.1 Il sottosistema di gestione delle Eccezioni Intel IA32 . . . . . . . . . . 502.4.2 Funzionamento interno di Kprobes . . . . . . . . . . . . . . . . . . . . 632.4.3 Funzionamento interno di Jprobes . . . . . . . . . . . . . . . . . . . . 662.4.4 SystemTAP, cenni sulla traduzione . . . . . . . . . . . . . . . . . . . . 67

1

Page 3: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

INDICE INDICE 2

3 Caso di studio 793.1 Confronto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 793.2 Workloads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

3.2.1 UnixBench . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 833.2.2 IOzone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843.2.3 Workload MEMORY bound . . . . . . . . . . . . . . . . . . . . . . . . 85

3.3 Scopo degli esperimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863.3.1 Sottosistema di gestione delle System Call in Linux . . . . . . . . . . . 873.3.2 ISR come handler di System Calls . . . . . . . . . . . . . . . . . . . . 873.3.3 Contesto degli esperimenti . . . . . . . . . . . . . . . . . . . . . . . . . 89

3.4 Preparazione esperimenti con KProbes/SystemTAP . . . . . . . . . . . . . . 893.4.1 Realizzazione dello script . . . . . . . . . . . . . . . . . . . . . . . . . 89

3.5 Preparazione esperimenti con DSKI . . . . . . . . . . . . . . . . . . . . . . . 92

4 Risultati sperimentali 944.1 Risultati KProbes/SystemTAP . . . . . . . . . . . . . . . . . . . . . . . . . . 94

4.1.1 Caso CPU bound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944.1.2 Caso IO bound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 994.1.3 Caso MEMORY bound . . . . . . . . . . . . . . . . . . . . . . . . . . 105

4.2 Risultati DSKI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1104.2.1 Caso CPU bound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1134.2.2 Caso IO bound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1154.2.3 Caso MEMORY bound . . . . . . . . . . . . . . . . . . . . . . . . . . 117

4.3 Conclusioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

A Ulteriori esempi 126A.1 Kprobes - Strumetazione di un character device driver . . . . . . . . . . . . . 126

A.1.1 Strumentazione del character device . . . . . . . . . . . . . . . . . . . 130A.2 SystemTAP - Probing delle operazioni su partizione ext3 . . . . . . . . . . . 133

B Installazione 138B.1 Kprobes e Jprobes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138B.2 SystemTAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

C Codici di errore 141

Page 4: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Capitolo 1

Introduzione

Il Software Libero ed il modello di sviluppo ad esso collegato sono divenuti nel corso degliultimi anni un importante tema di discussione e di dibattito nel mondo delle imprese, dellaricerca, degli utenti di tecnologie informatiche e delle telecomunicazioni. Nato inizialmentecome forma di dissenso nei confronti delle restrizioni imposte dal mercato informatico, ilsoftware open–source si e affermato oggigiorno come valida alternativa di prodotti commercialigrazie alle sua qualita e robustezza. Emblema dell’intero fenomeno risulta essere il sistemaoperativo Linux che da “giocattolo” per hacker e divenuto uno dei piu diffusi sistemi operativiper macchine server.

Lo scopo di questo testo e quello di fornire le conoscenze necessarie per poter indagare ilfunzionamento interno del sistema operativo Linux, occupandosi in particolare di analizzareil framework KProbes/SystemTAP ed applicarlo ad un caso di studio concreto. Per potercomprendere appieno l’idea alla base di questo tool di strumentazione, nonche capirne lanecessita, e necessario partire dalla filosofia che permea il mondo del Software Libero e nelcui solco si colloca necessariamente anche Linux. Il framework KProbes/SystemTAP, infatti,nasce come conseguenza diretta del paradigma di sviluppo open–source, in base al qualeconviene rilasciare il software spesso anche in maniera incompleta piuttosto che rilasciarlosoltanto come prodotto finito; in questo modo il software diventa un’entita in continua erapida evoluzione, ma d’altro canto aumenta la propria complessita. In tal senso, risultaquindi necessario avere a disposizione uno strumento potente ed efficace di indagine che possamettere in grado qualsiasi utente (perche questa e la filosofia open–source) di analizzare,modificare e migliorare il software. KProbes/SystemTAP nasce proprio seguendo questa sciadi pensiero, con l’idea di semplificare e automatizzare il processo di debugging e probing delkernel di Linux.

1.1 Il Software Libero

Con l’appellativo di Software Libero (Free Software) si indica del software che puo essereutilizzato, copiato, studiato, modificato e ridistribuito senza alcuna restrizione. Il fondatoredella Free Software Foundation, Richard Stallman, chiarisce l’idea alla base di tale definizionecon le seguenti parole: “Il ‘Software libero’ e una questione di liberta, non di prezzo. Per capireil concetto, bisognerebbe pensare alla ‘liberta di parola’ e non alla ‘birra gratis’1”. L’oppostodi tale tipologia di software e pertanto rappresentato non dal software commerciale bensı dal

1NdT: il termine free in inglese significa sia gratuito che libero, in italiano il problema non esiste.

3

Page 5: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.1. Il Software Libero Capitolo 1. Introduzione 4

Software Proprietario. Con quest’ultimo appellativo si intende un software sul quale sonostate imposte delle restrizioni sull’utilizzo e sulla copia, solitamente da un proprietario per vietecniche e legali; le vie tecniche implicano il rilascio di programmi esclusivamente in formatobinario, senza fornire alcun segmento di codice sorgente, mentre le vie legali coinvolgonobrevetti software, copyright e licenze restrittive.

1.1.1 Genesi del Software Libero

Piuttosto che parlare di genesi del Software Libero, bisognerebbe parlare di genesi del SoftwareProprietario. In origine, infatti, le principali aziende che operavano nel settore dell’informaticaerano i grandi produttori di hardware come la DEC, l’IBM o la Texas Instruments, per iquali la principale fonte di guadagno era rappresentata dalla vendita dei loro costosissimimainframes, mentre il software era visto come un qualcosa di marginale e addizionale perrendere le proprie macchine piu utili. A nessuno era mai passata per la mente l’idea diricavare profitto dalla vendita di programmi, anzi in quel periodo (anni ’60 e meta anni ’70) erapratica diffusa che i programmatori e gli sviluppatori condividessero il codice o modificassero ilcodice fornito dai produttori stessi. L’idea di Software House, ossia di un’azienda che producaesclusivamente software, era molto lontana; del resto la diffusione degli elaboratori elettroniciin quel periodo era abbastanza scarsa se raffrontata ai giorni nostri, e soltanto organizzazionimedio–grandi e dipartimenti universitari potevano addossarsi la spesa di una di tali macchine.

La situazione comincia a cambiare dalla meta degli anni ’70. L’hardware diventa sem-pre meno costoso, mentre le capacita di miniaturizzazione e integrazione dei produttori didispositivi elettronici aumenta; e nel 1970, infatti, che la Intel, un’allora piccola e scono-sciuta produttrice di ASIC 2, realizza su commissione di una ditta giapponese di calcolatrici,la Busicom, il primo microchip della storia, il 4004 (capostipite della famiglia di processoricon architettura x86). Nasce, in quel periodo, il Personal Computer, e quindi anche singolistudiosi e hobbisti possono procurarsi ad un prezzo ragionevole un elaboratore. Il mercatodell’informatica si espande, la concorrenza aumenta, e come conseguenza iniziano a presen-tarsi le prime restrizioni sul software sotto forma di licenze di utilizzo, dapprima motivatedal fatto che i produttori non volevano svelare le caratteristiche dell’hardware della macchinanascondendo il codice sorgente (bisogna tenere presente che la programmazione assembly inquel periodo era la norma), e in seguito motivate dal fatto che con la diffusione capillare deiPersonal Computer si capı che era possibile ricavare denaro dalla vendita di software per larisoluzione di problemi comuni (wordprocessors, fogli di calcolo etc.). Lo scenario dell’infor-matica muta, e gli sviluppatori che prima erano abituati a condividere il codice ora avevanole mani legate da accordi di NDA (Non Disclosure Agreement, ossia Accordi di Non Divulga-zione) con le compagnie che li avevano assunti. In sostanza lo sviluppo di software passa dimano dalle universita alle aziende, dovendo sottostare quindi alle leggi del mercato.

Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazionevenutasi a creare nella comunita degli sviluppatori, diede vita al progetto GNU, acronimoricorsivo che sta per “GNU is Not Unix” con l’obiettivo dichiarato di creare un clone del si-stema operativo UNIX (allora e tuttora stato dell’arte dei sistemi operativi nonche standardde facto) che fosse tuttavia libero da restrizioni, introducendo cosı il concetto di copyleft incontrasto al copyright. Nel 1985 fondo inoltre la FSF, Free Software Foundation, una fonda-zione senza motivi di lucro, oggi riconosciuta dall’UNESCO, che ha lo scopo di sponsorizzare

2ASIC e un acronimo che sta per Application Specific Integrated Circuits, ossia Circuiti Integrati perApplicazioni Specifiche.

Page 6: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.1. Il Software Libero Capitolo 1. Introduzione 5

e incoraggiare lo sviluppo di Software Libero. Da allora sino ad oggi il movimento e cresciuto,contando sullo sforzo congiunto di singoli individui nonche intere organizzazioni.

1.1.2 Licenze di Software Libero

Affinche un Software sia effettivamente libero, secondo Stallman, deve essere fornito con unalicenza che preveda le seguenti liberta:

Liberta 0: liberta di utilizzare il software per qualunque scopo.

Liberta 1: liberta di analizzare e modificare il software.

Liberta 2: liberta di copiare il software per aiutare il prossimo.

Liberta 3: liberta di migliorare il software, nonche rilasciarne la versione migliorata alpubblico cosicche l’intera comunita possa beneficiarne.

Ovviamente le liberta 1 e 3 richiedono necessariamente che il software sia fornito con ilrelativo codice sorgente.

La maggior parte del Software Libero viene fornita sotto la licenza GPL (GNU GeneralPublic License), scritta da Stallman stesso e da Eben Moglen, professore di legge della Co-lumbia Law School di New York. Sebbene essa sia stata ideata con lo scopo di garantire agliutenti le precedenti quattro leggi elencate, dal punto di vista software e una licenza abbastan-za restrittiva dal momento che impone che qualunque prodotto software derivato, ossia cheutilizzi o modifichi codice sotto GPL, sia distribuito sotto la stessa licenza. Per tal motivoe stata introdotta anche la LGPL (GNU Lesser Public License) che permette di utilizzare ilcodice anche in prodotti proprietari, purche le parti sotto LGPL, anche se modificate, sianorilasciate sempre sotto tale licenza.

Esistono anche altre licenze di software libero, come la BSD License (Berkeley SoftwareDistribution License) o la Apache License, che comunque presentano alcune incompatibilitafra di loro, ma queste questioni rientrano nell’ambito giuridico.

1.1.3 Vantaggi e svantaggi

I principali vantaggi del software libero sono i seguenti:

• Il software puo essere modificato ed adattato alle proprie esigenze.

• Il codice sorgente e sottoposto alla revisione di un numero molto elevato di persone,cosicche si ha una probabilita maggiore di riscontrare bugs e malfunzionamenti. Inoltrela correzione di un bug avviene in tempi molto rapidi.

• Dal momento che il codice e liberamente consultabile, e molto difficile che possano essereinseriti intenzionalmente in esso backdoor o Cavalli di Troia senza che questi venganorilevati (come invece puo accadere nel software proprietario).

• Non esistendo standard o protocolli proprietari e molto piu semplice realizzare softwareinteroperabile.

• Esiste un feedback piu rapido tra utenti e sviluppatori, ossia nuove funzionalita omodifiche vengono apportate in un tempo minore.

Page 7: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.2. Linux Capitolo 1. Introduzione 6

• Alcuni progetti di software libero hanno raggiunto una complessita e una dimensionetalmente elevata da richiedere il supporto commerciale di alcune aziende; in questomodo si vengono a creare nuovi business nel campo della formazione, del supporto edella personalizzazione del software (caso emblematico e rappresentato dalla Red HatInc.).

• Tramite la collaborazione con la comunita di sviluppatori, anche le medio–piccole azien-de possono creare prodotti di qualita.

• I progetti di software libero non sono soggetti a fenomeni di “Obsolescenza program-mata”. Molti prodotti commerciali, infatti, non vengono piu supportati dopo un certoperiodo di tempo, e le societa che li producono costringono i propri clienti, in manie-ra indiretta, a passare alle nuove versioni (e cio comporta ovviamente nuovi oneri perquesti ultimi).

Secondo i critici, invece, il software libero presenterebbe una serie di svantaggi:

• Essendo di natura volontaria, lo sviluppo di software libero e piu lenta dello sviluppodi software proprietario.

• Alcune tipologie di software, specialmente quelle di nicchia, non sono disponibili sottoforma di software libero.

• Lo sviluppo del software libero presenta una struttura anarchica, che, non rispettandoi principi dell’Ingegneria del Software, porta a risultati incoerenti e ad una mancanzadi uniformita e consistenza3.

• Alcuni progetti sono sprovvisti di un sistema formale di revisione, pertanto risultanoinadatti per applicazioni mission–critical.

• Non tutti sono in grado di modificare il codice, e spesso le applicazioni non sono user–friendly.

1.2 Linux

All’inizio degli anni ’90, il progetto GNU aveva compiuto passi da gigante; erano stati rea-lizzati molti componenti fondamentali, tra cui il compilatore GCC, le librerie, gli editor, lashell Bash, ma mancava il componente fondamentale: il kernel. Il progetto infatti prevedevala realizzazione del sistema operativo GNU HURD basato su microkernel, ma allora esso eraancora in fase embrionale (basti pensare che solo a partire dalla meta degli anni 2000 si e co-minciato a rilasciare HURD come sistema stabile ma non ancora completamente utilizzabile).Mancando il componente fondamentale il progetto GNU era molto lontano dal suo obiettivo.

In questo periodo, nel 1991, uno studente finlandese di informatica, Linus Torvalds, inizioper hobby la realizzazione di un kernel UNIX–like per macchine x86, dando origine a quello chesuccessivamente sarebbe diventato Linux. Nato inizialmente per essere utilizzato da singoliappassionati, tale sistema operativo e cresciuto grazie anche al supporto di numerose aziendedel settore, come IBM, Red Hat, Novell e Sun Microsystems, essendo impiegato anche su

3Esistono, tuttavia, delle critiche a questo punto, vedere sottosezione 1.2.3.

Page 8: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.2. Linux Capitolo 1. Introduzione 7

macchine server, ed oggigiorno sta acquistando popolarita anche come sistema operativo peri desktop.

Il sistema operativo Linux risulta essere il prodotto di volontari e appassionati i quali,lavorando in maniera indipendente senza vincoli commerciali, contribuiscono giornalmente alsuo miglioramento. Da cio si hanno due interessanti risultati:

• Esso e il prodotto di migliaia di persone sparse nel mondo, pertanto viene consideratocome uno dei piu grandi progetti collaborativi della storia umana (se non il piu gran-de). Del resto in uno studio del 2002 di David A. Wheeler, “More Than a Gigabuck:Estimating GNU/Linux’s Size”4, si e stimato che la distribuzione Red Hat Linux 7.1contenesse circa 30 milioni di righe di codice sorgente; lo studio inoltre stima che iltempo necessario per realizzare tale opera sia di circa ottomila anni di lavoro per essereumano e se fosse stato sviluppato da una azienda commerciale il suo costo sarebbe statodi 1.08 miliardi di dollari. Cifre abbastanza significative.

• Il secondo aspetto e che gli utenti hanno a disposizione un prodotto libero, slegatodalle leggi del mercato. Basti pensare infatti che molto spesso nell’implementazione diLinux si e evitato di realizzare funzionalita particolari, che seppur richieste dal mercato(o per meglio dire “di moda”), appesantivano o rallentavano il sistema, generando undegrado delle prestazioni; un esempio e la decisione di non implementare gli STREAMintrodotti in UNIX SVR4, poiche avrebbero appesantito inutilmente il kernel, seppurrappresentassero una buona astrazione.

1.2.1 Vantaggi e Svantaggi

In sostanza Linux fornisce una serie di vantaggi che vengono riportati di seguito:

Linux e privo di costi. Si puo ottenere un sistema UNIX completo senza costi aggiuntivia quelli dell’hardware.

Linux e completamente personalizzabile in tutti i suoi componenti. Grazie al pro-cesso di compilazione e possibile selezionare solo i componenti e le funzionalita di cui siha bisogno, inoltre e possibile scegliere di ottimizzare il kernel per la macchina specifi-ca su cui eseguirlo. Nei sistemi operativi commerciali, un’operazione del genere non econsentita.

Linux funziona anche su hardware antiquato e macchine embedded. Con Linux e pos-sibile realizzare completi server di rete utilizzando vecchi processori 386, nonche eseguir-lo su palmari, videoregistratori etc.

Linux punta sull’efficienza. Come detto in precedenza non tutte le funzionalita impostedal mercato (come gli STREAM) sono state implementate, dal momento che gli svilup-patori di Linux puntano sull’efficienza e sulle prestazioni nel progettare l’architettura delkernel. In sostanza, gli sviluppatori sono slegati da logiche legate al costo e al mercatoessendo il sistema frutto del lavoro di appassionati.

Il kernel puo essere molto compatto. Con le opportune scelte di compilazione e possi-bile generare un’immagine binaria del kernel molto compatta, cosı da poter installare ilsistema piu qualche utility su un singolo floppy disk.

4http://www.dwheeler.com/sloc/redhat71-v1/redhat71sloc.html

Page 9: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.2. Linux Capitolo 1. Introduzione 8

Linux e compatibile con molti sistemi operativi. Linux e in grado di interpretare i file-system di molti sistemi operativi, nonche, con le dovute librerie, di eseguire i programmiscritti per tali sistemi.

Linux e ben supportato. La comunita di utenti e sviluppatori di Linux e molto estesa.Sulla rete e possibile trovare numerosi newsgroup e mailing list in cui poter richiedereaiuti e consigli. Inoltre l’hardware supportato e in rapido aumento.

D’altro canto esistono molte critiche che possono essere riassunte nei seguenti punti:

Linux non e User-friendly. In effetti Linux non e un sistema operativo semplice da uti-lizzare e richiede conoscenze di informatica supplementari; infatti ha una curva diapprendimento maggiore rispetto ad alcuni sistemi operativi commerciali.

Linux non e adatto come sistema operativo Desktop. Nonostante sia stata raggiuntauna certa maturita, Linux nel campo dei sistemi operativi per desktop e ancora lontanoda Windows della Microsoft e MacOS della Apple che dominano il mercato di questosettore. Da questo punto di vista risulta essere ancora carente in quanto a facilita d’uso,supporto di periferiche, integrazione degli strumenti comuni e accessibilita da parte dipersonale non esperto.

Parco software limitato. Molte applicazioni commerciali non sono fornite per questo si-stema operativo, costringendo molti utenti ad adoperare altri sistemi.

Incompatibilita con molte periferiche hardware. Anche se gli sforzi nel supportare unnumero sempre maggiore di periferiche e stato molto elevato, non tutte le periferichesono supportate. Le aziende produttrici di hardware spesso non ritengono economica-mente favorevole sviluppare driver per sistemi operativi che non siano commerciali.

1.2.2 Diffusione di Linux

Oggigiorno, Linux e cresciuto come progetto diffondendosi e affermandosi come valida sceltadi sistema operativo per macchine server. Secondo la societa di ricerche e analisi di mercatoIDC (International Data Corporation) nel 2002 la percentuale di server su cui era in funzioneLinux era del 25%, e questa percentuale e tuttora in crescita dal momento che molte aziende,nonche intere organizzazioni, stanno gradualmente passando a questo sistema operativo.

Come esempi emblematici possiamo citare Google, il principale motore di ricerca mondiale,che utilizza su piu di 100.000 server una versione personalizzata di Red Hat Linux, oppure ilgoverno del Brasile che ha lanciato recentemente l’iniziativa “PC Conectado” con cui vengonovenduti ai cittadini computer ad un prezzo ragionevole forniti di sistema operativo Linux.

Le motivazioni alla base di questo fenomeno sono molteplici. Prima fra tutte, Linux rap-presenta una garanzia di sicurezza; essendo il codice disponibile sotto GPL, esso puo essereanalizzato per trovare falle di sicurezza (che verranno prontamente corrette dalla comunita)ed e impossibile inserirne volutamente senza che gli sviluppatori se ne accorgano. InoltreLinux eredita tutta l’infrastruttura di amministrazione degli utenti tipica di Unix, cosicche eimpossibile per un utente qualunque manomettere il funzionamento della macchina; questainfrastruttura e stata notevolmente migliorata con l’ausilio di SELinux (“Security EnhancedLinux”) che fornisce meccanismi piu granulari per il controllo dell’accesso e dell’utilizzo del

Page 10: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.2. Linux Capitolo 1. Introduzione 9

sistema. Spesso, riguardo la sicurezza, vengono mosse delle critiche da societa che produ-cono software proprietario, come la Microsoft. Secondo quest’ultima infatti, il fatto stessoche il codice di Linux sia di dominio pubblico consentirebbe ad un possibile hacker o pira-ta informatico di scoprire falle nel sistema e sfruttarle a proprio vantaggio; a suo parere, ilmodello migliore di sicurezza sarebbe, invece, quello cosiddetto “Security through obscurity”ossia “Sicurezza attraverso la segretezza”. Nascondendo, infatti, i dettagli sul funzionamentodel sistema senza fornire il codice sorgente, si impedirebbe (in teoria) ai malintenzionati discovare falle di sicurezza da poter sfruttare a proprio vantaggio. Ovviamente questo modelloe altamente controverso, e nella pratica si e spesso dimostrato fallimentare dal momento chesistemi basati su tale approccio si sono rivelati spesso vulnerabili ad attacchi esterni. Delresto in crittografia esiste il cosiddetto “principio di Kerckhoff ” secondo il quale la sicurezzadi un sistema dipende dalla sua chiave e non dal fatto che il suo funzionamento sia segreto:riassunto in un unica frase di Shannon “Il nemico conosce il sistema”.

Altre motivazioni sono la robustezza, l’assenza di limitazioni imposte, l’interoperabilitadelle applicazioni e la possibilita di personalizzazione per applicazioni specifiche.

1.2.3 Il modello di sviluppo di Linux

Le caratteristiche vincenti di Linux sono il risultato di un continuo sviluppo e miglioramentoda parte di un numero enorme di volontari sparsi per il mondo. Da questo punto di vista,si puo affermare che non esiste un vero e proprio modello di sviluppo seguito dalla comunitadegli sviluppatori, ma anzi vi e una certa anarchia nel modo in cui le modifiche e le aggiuntevengono apportate al software; in poche parole lo sviluppo del kernel di Linux non segue leregole fondamentali dell’Ingegneria del Software.

Questa argomentazione e stata spesso adoperata contro l’adozione di tale sistema operati-vo, dal momento che la mancanza di un preciso modello di sviluppo del software implicherebbela mancanza di coerenza e consistenza. In un saggio del 1997, “La Cattedrale e il Bazaar”(considerato da molti come manifesto del movimento Open Source), Eric S. Raymond analiz-za questo modello di sviluppo tipico dei progetti open source, quale lo stesso kernel di Linux,contrapponendolo a quello “ortodosso” dell’Ingegneria del Software.

Nel saggio vengono descritti i due modelli adoperando una metafora:

Nel modello a Cattedrale , che rappresenta il modello “ortodosso”, una ristretta cerchiadi “esperti” lavora in totale isolamento per scrivere il codice. Il progetto ha una suddi-visione gerarchica stretta e severa, ed ogni sviluppatore si occupa della propria piccolasezione di codice analogamente a quanto accade in una gerarchia di una associazionereligiosa (da qui la denominazione di modello “a Cattedrale”). Le revisioni vengonorilasciate con relativa lentezza, dal momento che si cerca di rilasciare software il piupossibile completo e privo di bug e errori. Questo modello e tipico delle grandi soft-ware house, ma anche di grandi progetti open source, come GCC5 (ossia la suite dicompilatori GNU) e l’editor EMACS.

Nel modello a Bazaar , invece, il codice della revisione in via di sviluppo e disponibileliberamente, gli utenti possono interagire direttamente con gli sviluppatori (esiste unfeedback piu rapido), e se ne hanno la capacita possono modificare il codice. Non esiste

5Anche se quest’ultimo e passato al modello opposto negli ultimi anni, dato che aveva raggiunto un livellodi lentezza nel rilascio delle revisioni inaccettabile.

Page 11: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.3. Il kernel di Linux Capitolo 1. Introduzione 10

una gerarchia precisa o una suddivisione del lavoro, e un utente puo modificare qualun-que segmento di codice; lo sviluppo in questo modo e piu libero, da qui la denominazionedi modello “a Bazaar”. Questo modello di sviluppo viene adoperato dalla maggior partedei progetti open source tra cui lo stesso kernel di Linux.

In sostanza, la tesi centrale portata avanti dal saggio in questione e riassumibile nellaseguente frase:

“Dato un numero sufficiente di occhi, tutti i bug vengono a galla”

che viene chiamata dall’autore “Legge di Linus”. Secondo Raymond, questa legge e alla ba-se del successo di Linux. Prima si riteneva, infatti, che ogni progetto di una certa complessitaavesse bisogno di essere adeguatamente gestito e coordinato, poiche in caso contrario sarebbecollassato sotto il peso di un numero elevato di revisioni tra loro incompatibili prodotte dapersone diverse. Il progetto di Linux ha dimostrato, invece, che la rigida schematizzazionedel procedimento di sviluppo non sempre e la soluzione ottimale per ottenere un prodottorobusto e di qualita. Con questo il saggio non vuole affermare che tutti i principi su cui poggial’Ingegneria del Software siano un inutile perdita di tempo, ma, anzi, e possibile applicarlianche nel contesto del software libero con una certa flessibilita. Basti pensare, infatti, chei progetti open source possiedono anch’essi una qualche organizzazione, dal momento che,anche se tutti gli sviluppatori sono allo stesso livello e possono lavorare su qualsiasi sezionedel codice, esistono dei cosiddetti “mantainers” che si occupano di indirizzare lo sviluppodel progetto, nonche decidere quali modifiche lasciare nel codice o quando rilasciare nuoverevisioni. Il punto di forza di questa nuova visione sta nell’interpretare in maniera diversa irapporti tra i vari elementi che entrano in gioco nello sviluppo del software; non vi sono piuchiare distinzioni tra programmatori, progettisti, utenti etc. Gli utenti diventano beta tester,e, se vogliono, possono intervenire nello sviluppo, cosicche il controllo del codice e maggiore,aumentando la probabilita di scovare e correggere un bug in maniera rapida, cosa che spessosi rivela impossibile per software proprietari, dove il numero di persone che lavora al codice elimitato.

1.3 Il kernel di Linux

Linux, in quanto clone open source del sistema operativo UNIX, ne condivide molte caratte-ristiche. In primo luogo, come molti suoi predecessori, ha un’architettura monolitica, ossiatutti i livelli che compongono il nucleo vengono fusi in fase di compilazione in un’immagine bi-naria che viene eseguita in modalita supervisore per conto del processo corrente. Oggigiorno,invece, si tende ad adottare, per i moderni sistemi operativi, un’architettura a microkernel, incui il nucleo del sistema operativo implementa soltanto una serie di funzionalita di base, comead esempio comunicazione interprocesso, alcune primitive di sincronizzazione ed un semplicescheduler, demandano le funzionalita piu complesse, come la gestione del filesystem o dellamemoria, a processi che vengono eseguiti al livello utente. Ovviamente entrambi gli approccihanno dei pro e dei contro.

Un’architettura a microkernel fornisce un vantaggio di tipo pratico, dal momento checostringe gli sviluppatori ad adottare un approccio modulare nella realizzazione dei livellidel sistema operativo, poiche ciascuno di essi viene eseguito come un processo relativamenteindipendente che comunica con gli altri attraverso un’interfaccia pulita; la gestione della

Page 12: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.3. Il kernel di Linux Capitolo 1. Introduzione 11

memoria centrale e migliore dal momento che componenti del sistema o driver non necessaripossono essere rimossi dalla memoria o subire uno swap out. Inoltre i sistemi operativi conarchitettura a microkernel possono essere facilmente portati verso altre architetture hardware,dal momento che (in teoria) tutto il codice dipendente dall’architettura risiede nel kernel. Glisvantaggi che una simile architettura pone sono rappresentati, in primis, da un generaledegrado delle prestazioni dovuto al meccanismo di scambio messaggi tra le applicazioni cheha un costo elevato; infatti, mentre nei kernel monolitici la comunicazione tra componenti delsistema avviene in maniera diretta, in quelli a microkernel essa avviene attraverso un livelloaggiuntivo. Secondo svantaggio e rappresentato dal fatto che spesso non e possibile realizzarefunzionalita come la gestione della memoria sotto forma di processi utente, dal momento chenecessitano di svolgere codice in modalita supervisore; pertanto nei sistemi operativi modernisolitamente si utilizza un approccio ibrido.

Figura 1.1: Schematizzazione di un kernel con architettura monolitica.

L’architettura monolitica, invece, fornisce vantaggi soprattutto in termini di prestazioni,dal momento che tutte le funzionalita sono fuse in un’unica immagine binaria eseguibile che,con tecniche di compilazione ottimizzante, riesce a sfruttare meglio le risorse del sistema el’utilizzo del processore. Gli svantaggi sono che non esiste una chiara e precisa interfaccia tra icomponenti del kernel (e purtroppo in questo Linux pecca rovinosamente) e che, ogniqualvoltarisulti essere necessario aggiungere un driver di una periferiche, bisogna per forza ricompilarel’intero kernel.

Come e stato detto in precedenza, gli sviluppatori di Linux tendono a ragionare in ma-niera indipendente dalle leggi del mercato, pertanto hanno cercato di utilizzare i vantaggidi entrambe le architetture. Il kernel viene compilato sempre come un’unica immagine, at-traverso un raffinato processo di compilazione, ma fornisce un supporto ai kernel modules.Questi ultimi sono oggetti il cui codice puo essere collegato in fase di run–time; in questomodo e possibile aggiungere nuovi driver o componenti del sistema operativo senza dover ne-cessariamente ricompilare l’intero kernel. Utilizzando i kernel modules si ottengono i seguentivantaggi:

Approccio modulare. Dal momento che i moduli possono essere collegati e scollegati dina-micamente in fase di esecuzione e necessario introdurre interfacce ben definite per poteraccedere alle strutture dati del kernel.

Page 13: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.3. Il kernel di Linux Capitolo 1. Introduzione 12

Figura 1.2: Schematizzazione di un architettura a MicroKernel.

Indipendenza dalla piattaforma. Anche se i moduli possono implementare codice chegestisca specifiche caratteristiche dell’hardware (come ad esempio la gestione di un discoIDE), un modulo non dipende strettamente dall’hardware sottostante. In questo modo,ad esempio, il driver di un hard disk IDE funziona allo stesso modo su di un PC IBMcompatibile cosı come su di una workstation HP Alpha.

Utilizzo migliore della memoria. Questo vantaggio discende direttamente dalla possibi-lita di caricare e scaricare dinamicamente un modulo dalla memoria principale, cosı dapoter mantenere in memoria solo i moduli necessari.

Nessun degrado delle performances. Una volta collegato, il codice di un modulo e equi-valente a quello collegato staticamente in fase di compilazione del kernel6; del resto none richiesto alcuno scambio di messaggi quando vengono invocate le funzioni del modulo.

Essendo il prodotto di volontari e appassionati, il kernel di Linux migliora continuamentecon una velocita esponenziale. Questo si traduce nella presenza di funzionalita molto avanzateche non sempre sono offerte da kernel UNIX commerciali:

• Linux fornisce il supporto per il SMP (Simmetrical MultiProcessor); sebbene alcunevarianti commerciali di UNIX lo forniscano, molte implementazioni tradizionali ne sonosprovviste.

• Il kernel di Linux e prelazionabile. Diversamente da molte varianti commerciali,Linux e capace di prelazionare un processo anche se questo e in esecuzione nel kernel(ossia anche se il kernel sta svolgendo un compito per il processo in questione); tra leimplementazioni commerciali solo Solaris e IRIX forniscono tale caratteristica.

• Linux utilizza un approccio particolare nel gestire il multiprocessing e il multitaskingnon facendo differenza alcuna tra processo e thread. Infatti la gestione dei processie molto leggera e flessibile: tramite la system call non standard clone() e possibileclonare un processo selezionando quali tra le risorse ad esso assegnate (area di memoria,file aperti etc.) si desideri condividere con il nuovo processo; in questo modo, scegliendo

6In realta c’e un leggero degrado delle prestazioni, ma sicuramente molto trascurabile rispetto a quelloimposto da un’architettura a microkernel.

Page 14: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.4. Debugging del kernel Capitolo 1. Introduzione 13

di condividere tutte le risorse, i due processi in effetti rappresentano due thread dellostesso processo, mentre in caso contrario essi rappresentano due processi separati. Laclone() fornisce la possibilita di utilizzare anche particolari schemi di condivisioneibridi che nessun altro sistema operativo e in grado di fornire.

• Linux fornisce un approccio object–based per la realizzazione dei driver di dispositivo.Gli sviluppatori di driver hanno infatti a disposizione comode interfacce per l’astrazio-ne dei dispositivi; in questo modo e possibile realizzare anche dispositivi virtuali cheastraggono funzionamenti specifici.

1.4 Debugging del kernel

Come si e detto nella sottosezione 1.2.3, lo sviluppo del kernel di Linux segue un modellocosiddetto “a Bazaar”, in cui ogni sviluppatore o utente puo visionare e modificare qualunquesezione del codice; in questo modo si ha una probabilita maggiore di individuare un bug o unmalfunzionamento. Tuttavia il kernel di un sistema operativo e un’entita di natura diversarispetto ad un programma utente, e il debugging delle sue funzionalita non e un’operazionesemplice; i bug sono molto piu insidiosi e possono venire a galla solo in circostanze rare. Perquesto motivo, per progetti di tale dimensione, le aziende utilizzano il modello di sviluppo “aCattedrale” con rigide regole di revisione formale, cercando cioe di evitare sul nascere che unbug possa presentarsi. Dal momento che Linux adopera un modello di sviluppo totalmentedifferente, si e sempre avvertita la necessita di strumenti che possano rivelare a posteriori lapresenza di bug, ossia tool di indagine che possano scandagliare i meandri del kernel stessoin maniera rapida e veloce, proprio in accordo con la filosofia di sviluppo dei progetti opensource.

I tool adoperati in tal senso sono stati numerosi, spesso non sempre efficaci; di seguitosono riportate brevemente le caratteristiche dei principali tra di essi.

1.4.1 Utilizzo di printk()

Sentendo la necessita di avere a disposizione un meccanismo per acquisire dati sul funziona-mento interno del kernel, ossia per effettuare il probing del kernel, il primo strumento chee stato adoperato in tal senso e stata la funzione printk(). Questa funzione si comportaquasi alla stessa maniera della funzione dello standard C printf(), fornendo un supportoalla formattazione dell’output testuale.

Essa offre importanti caratteristiche. In primo luogo e richiamabile da qualsiasi puntodel kernel e in qualsiasi momento (questo e possibile solo grazie al fatto che il kernel diLinux e monolitico). Essa e richiamabile da un interrupt handler cosı come dal contesto diun processo; e inoltre possibile richiamarla da una sezione critica, da piu processori (nel casoSMP), e non c’e un semaforo che la gestisce. Tutte queste caratteristiche rendono la printk()una funzione utilissima che puo aiutare nel processo di probing e debugging del kernel.

Ovviamente anch’essa presenta degli svantaggi. Infatti, e inutilizzabile prima di un certopunto nella fase di booting del kernel di Linux, ossia fin quando non viene inizializzata laconsole (del resto se la console non e inizializzata, l’output testuale dove finisce?). Questonon risulta essere un problema se non bisogna effettuare il debugging e il probing di proce-dure eseguite nella fase di boot del kernel; pertanto esiste una variante non portabile dellaprintk(), la early printk(), che puo essere adoperata in questa fase.

Page 15: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.4. Debugging del kernel Capitolo 1. Introduzione 14

I messaggi restituiti dalla printk() vengono momentaneamente memorizzati in un buffercircolare del kernel, a cui e possibile accedere leggendo il dispositivo a caratteri virtuale/var/log/messages7; in questo modo e possibile ottenere informazioni sul funzionamentointerno del kernel da parte dei processi utente. Inoltre e possibile specificare un loglevel inbase all’importanza del messaggio; in base al loglevel, il kernel decide se visualizzare o menoil messaggio sulla console. Ogni loglevel e identificato da una costante che viene anteposta almessaggio, come nell’esempio seguente:

printk(KERN_WARNING "Utilizzato per segnalare un avvertimento.");printk(KERN_INFO "Utilizzato per messaggi informativi.");printk(KERN_ALERT "Utilizzato per una situazione critica.");

In questo modo e possibile filtrare, in base all’importanza, i messaggi comunicati dalkernel.

Ovviamente utilizzare la printk() nel procedimento di probing e debugging del kernelpresenta una serie di problemi:

Procedimento di probing scomodo. Infatti l’inserimento di un nuovo punto di strumen-tazione nel kernel prevede una nuova ricompilazione dello stesso.

Il Buffer dei messaggi ha una dimensione limitata. Se i messaggi cominciano ad arri-vare con una frequenza elevata, si rischia di perderli; per tal motivo non e possibileeffettuare il probing di processi che variano molto velocemente e l’acquisizione di daticon questo approccio, soprattutto se in grandi quantita, e sconsigliabile.

Supporto al postprocessing nullo. Lo sviluppatore deve necessariamente analizzare i da-ti ottenuti a mano, dal momento che la printk() non fornisce alcun supporto al lo-ro trattamento (del resto essa e una funzione di stampa su console, cosa ci si puoaspettare?).

Ricapitolando la printk() puo andar bene per segnalare eventi occasionali, situazionianomale o brevi messaggi di debugging, ma certamente non e adatta per un procedimentosistematico di indagine del kernel.

1.4.2 Altre soluzioni

Per gli eseguibili a livello utente la situazione e resa molto piu rosea dalla presenza dei debug-ger, come ad esempio GNU gdb (GNU Debugger) in ambiente Linux. Sostanzialmente il lorofunzionamento si basa sull’utilizzo di istruzioni di breakpoints, come ad esempio l’istruzioneINT3 dell’architettura Intel IA32, le quali indicano al processore di bloccare l’esecuzione delprogramma e passare il controllo al debugger in attesa dell’input dall’utente. In questo modoi debugger sono in grado di raccogliere informazioni sull’eseguibile senza che questo debba es-sere ricompilato. Questo particolare paradigma di strumentazione presenta notevoli vantaggirispetto all’inserimento di messaggi diagnostici:

1. Lo sviluppatore non deve modificare l’eseguibile del programma.

2. Si evitano errori imprevisti dovuti alle modifiche applicate al programma.7I messaggi vengono inseriti nel buffer dal demone syslogd.

Page 16: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.4. Debugging del kernel Capitolo 1. Introduzione 15

3. Si evita la ricompilazione e il riavvio del programma stesso.

Per molto tempo gli sviluppatori del kernel hanno richiesto che fosse aggiunto un debuggernell’albero principale di Linux; tuttavia Linus Torvalds e stato per molto tempo contrario aquesta ipotesi. L’informatico finlandese riteneva, infatti, che con uno strumento di questotipo, i problemi riscontrati fossero risolti con modifiche approssimative, le quali, sebbene fun-zionanti, avrebbero avuto effetti impredicibili. In base a questa logica, soltanto una realecomprensione del codice e dell’architettura comportano modifiche corrette e precise. Nono-stante cio, la richiesta di un kernel–debugger ufficiale e stata sempre molto forte, e sono statesviluppate numerose patch che aggiungono supporto nativo al debugging.

Una prima tecnica e quella di adoperare lo stesso debugger GNU gdb. Adoperando gdbsull’immagine binaria del kernel vmlinuz e possibile analizzare l’area di memoria in cui ilkernel risiede (purche quest’ultimo sia stato compilato con le informazioni di debug). Sfor-tunatamente questo e il massimo che gdb e in grado di effettuare; lavorando sull’immaginebinaria del kernel stesso, esso non e in grado di inserire breakpoints, modificare dati o codice,ne tantomeno di effettuare il single–stepping delle operazioni effettuate. Anche se forniscel’indubbio vantaggio di poter esaminare l’area di memoria del kernel, non sempre e statol’approccio preferito degli sviluppatori.

Per superare tali limiti, e stato realizzato kgdb, una patch che permette a gdb di svolgeretutte quelle operazioni che prima gli erano impedite utilizzando uno stratagemma. In sostan-za, il kernel viene patchato in maniera tale da poter effettuare il debugging con gdb tramite laporta seriale. Ovviamente questa patch del kernel e fortemente dipendente dall’architetturae richiede necessariamente due computer per poter essere eseguita.

Ulteriore evoluzione in tal senso e stato kdb, una patch che modifica in maniera massicciail kernel, cosicche non e piu necessario effettuare il debugging da remoto, ma sempre dallostesso host. kdb e abbastanza semplice da utilizzare, basta infatti premere il pulsante breaknella console per richiamarlo; ovviamente non e una soluzione ottimale, in primo luogo per lepesanti modificazioni che apporta al kernel, in secondo luogo poiche e dipendente strettamentedall’architettura ed infine poiche, essendo richiamato con la pressione di un pulsante dellatastiera, non permette di bloccare l’esecuzione in un punto preciso.

1.4.3 KProbes & SystemTAP

La realizzazione di un kernel–debugger, come si e visto nelle sezioni precedenti e stata par-ticolarmente travagliata. Soltanto con la versione 2.6 del kernel di Linux e stato finalmenteintrodotto nell’albero principale di sviluppo uno strumento “ufficiale”: KProbes. Esso nascecon l’idea di superare le limitazioni imposte dai tool precedenti, cercando pero di sfruttarnei punti di forza.

KProbes cerca di utilizzare le caratteristiche alla base di un generico debugger di ap-plicazioni utente. Un normale debugger consente, infatti, di inserire dinamicamente delleistruzioni di breakpoint nell’immagine binaria dell’eseguibile; quando il processore incontraqueste particolari istruzioni macchina, blocca l’esecuzione del programma mentre il sistemaoperativo fornisce il controllo al debugger che rimane in attesa dell’input da parte dell’uten-te. L’utente puo, a tal punto, analizzare l’immagine in memoria del programma esaminatoricavando cosı tutte le informazioni di cui necessita, nonche modificare i dati contenuti inessa. Fatta questa operazione, l’utente puo ridare il controllo al programma esaminato, cheriprendera l’esecuzione dal punto in cui era stato interrotto. KProbes rende propria questa

Page 17: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

1.4. Debugging del kernel Capitolo 1. Introduzione 16

caratteristica tipica di un debugger con qualche modifica; del resto l’esecuzione del kernel nonpuo essere completamente bloccata, dal momento che esistono una serie di funzionalita, comel’handling di interrupt, che non possono essere fermate. L’approccio che viene adoperato equello di utilizzare delle opportune “handling function” che automatizzano il procedimentodi acquisizione dati e analisi, senza bloccare il flusso di esecuzione.

L’infrastruttura di strumentazione KProbes fornisce un’interfaccia semplice che permettel’inserimento dinamico di punti di strumentazione direttamente nell’immagine binaria delkernel, eliminando quindi la necessita di ricompilarlo. Esso permette all’utente di registraredelle funzioni di handling che vengono richiamate prima e dopo un punto di strumentazioneo in caso di segmentation fault e che permettono l’automatizzazione del processo di probing.In tal senso KProbes e uno strumento molto potente a supporto degli sviluppatori del kernel.

Il codice che fa uso di KProbes viene compilato come modulo kernel; in tal modo, piuttostoche essere costretti a ricompilare e riavviare l’intero sistema con un kernel strumentato (comeavveniva per la printk()), un modulo di strumentazione puo essere scritto, compilato ecaricato sul sistema direttamente. Una volta svolto il proprio compito esso puo essere rimossodalla memoria e il kernel puo tornare al suo normale funzionamento.

Il framework fornisce due interfacce di strumentazione: kprobe e jprobe. Il primo inse-risce un probing point in un punto qualsiasi del kernel, mentre il secondo viene adoperatoper strumentare l’entry point delle funzioni, potendone analizzare i parametri forniti dal chia-mante. Infatti, pur potendo inserire un probing point di tipo kprobe in qualunque punto delkernel, esso non e in grado di interpretare lo stack del contesto attuale, non potendo quindifare alcuna assunzione sulle variabili locali o sui parametri passati ad una funzione.

Sebbene KProbes sia uno strumento potente, esso rimane comunque uno strumento dibasso livello; per tal motivo e stato realizzato uno strumento aggiuntivo, SystemTAP, svi-luppato congiuntamente da IBM e Red Hat, che poggia il proprio funzionamento sulle inter-facce fornite da KProbes, nascondendo pero la complessita della realizzazione di un modulodel kernel. Esso infatti semplifica notevolmente il processo di probing fornendo un linguaggiodi scripting semplice da adoperare. Dal momento che dipende da KProbes, SystemTAP puoessere visto come una sua estensione; per tal motivo l’intero framework di strumentazioneKprobes/SystemTAP puo essere suddiviso su tre livelli:

1. Un livello dipendente dall’architettura, che fornisce le funzionalita di base per il si-stema di strumentazione (in particolar modo in questo documento si fa riferimentoall’architettura Intel IA32).

2. Due interfacce di basso livello, Kprobes e Jprobes, per l’inserimento dei probing points.

3. Un’interfaccia di alto livello, SystemTAP, che semplifica l’utilizzo di Kprobes e Jprobesper l’utente finale (attualmente ancora in fase di testing).

In questo testo ci occuperemo di analizzare il framework di strumentazione KProbes/SystemTAP,valutarne i vantaggi e gli svantaggi, nonche confrontarlo con un framework analogo (per DSKIfare riferimento a [1]) e applicarlo ad un caso di studio.

Page 18: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Capitolo 2

KProbes e SystemTAP

In questo capitolo ci occuperemo di analizzare il framework di strumentazione KProbes/SystemTAP,studiarne le interfacce, comprenderne l’utilizzo nonche il funzionamento interno.

2.1 Le interfacce kprobe e jprobe

Come gia affermato in precedenza KProbes e uno strumento di basso livello; per poterlo ado-perare e necessario implementare un modulo di strumentazione. In sostanza il procedimentodi strumentazione attraverso l’ausilio di KProbes si divide nei seguenti passi:

1. Realizzazione di funzioni di handling che si occupano di raccogliere i dati di interesse.

2. Realizzazione di un modulo kernel che si occupi di registrare le funzioni di probing.

3. Compilazione del modulo kernel e suo caricamento in memoria.

4. Effettuate le operazioni di probing, scaricamento del modulo dalla memoria.

L’utilizzo di KProbes non e, quindi, un’operazione semplice come l’utilizzo di un debuggerquale gdb; si presuppone che l’utente sappia realizzare un modulo del kernel. In ogni caso ilframework ci presenta un interfaccia in linguaggio C per la registrazione dei probing points.Quest’ultima presenta principalmente due tipi di kernel probing points: kprobe e jprobe. Ilprimo tipo viene impiegato per strumentare qualsiasi punto del kernel, per cui non si possonofare assunzioni sulle variabili locali e sui parametri presenti sullo stack. Il secondo tipoviene impiegato per strumentare esclusivamente l’entry point delle funzioni, per tal motivoattraverso di esso e possibile conoscere i parametri passati alla funzione strumentata.

2.1.1 kprobe

kprobe e una struttura dati, definita nell’header linux/kprobes.h, che incapsula tutte leinformazioni necessarie per l’inserimento di un probing point in un punto qualsiasi del kernel;assa viene di seguito riportata:

struct kprobe {struct hlist_node hlist;

17

Page 19: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.1. Le interfacce Capitolo 2. KProbes e SystemTAP 18

/* list of kprobes for multi-handler support */struct list_head list;

/* location of the probe point */kprobe_opcode_t *addr;

/* Called before addr is executed. */kprobe_pre_handler_t pre_handler;

/* Called after addr is executed, unless... */kprobe_post_handler_t post_handler;

/* ... called if executing addr causes a fault (eg. page fault).* Return 1 if it handled fault, otherwise kernel will see it. */kprobe_fault_handler_t fault_handler;

/* ... called if breakpoint trap occurs in probe handler.* Return 1 if it handled break, otherwise kernel will see it. */kprobe_break_handler_t break_handler;

/* Saved opcode (which has been replaced with breakpoint) */kprobe_opcode_t opcode;

/* copy of the original instruction */struct arch_specific_insn ainsn;

};

tra i suoi campi quelli piu importanti sono:

kprobe opcode t *addr: Rappresenta la locazione in cui vogliamo inserire il probing point.

kprobe pre handler t pre handler: E’ un puntatore alla funzione di pre–handling che verrainvocata immediatamente prima dell’esecuzione dell’istruzione da strumentare.

kprobe post handler t post handler: E’ un puntatore alla funzione di post–handling cheverra invocata immediatamente dopo l’esecuzione dell’istruzione strumentata.

kprobe fault handler t fault handler: E’ un puntatore alla funzione di fault–handling,invocata nel caso in cui l’esecuzione dell’istruzione da strumentare abbia provocato unfault o il pre–handler non abbia restituito il valore 0.

kprobe opcode t opcode: Campo in cui viene memorizzata temporaneamente l’istruzionestrumentata, sostituita dall’istruzione di breakpoint.

Le funzioni di handling devono avere una struttura specifica:

Pre–Handler La funzione di pre–handling deve essere di questo tipo:int <nome pre-handler> (struct kprobe *kp, struct pt regs *regs);Ad essa vengono passati i parametri struct kprobe *kp, che rappresenta un puntatore

Page 20: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.1. Le interfacce Capitolo 2. KProbes e SystemTAP 19

alla struttura dati utilizzata per registrare il probing point, e struct pt regs *regsche rappresenta invece un puntatore alla struttura dati di tipo pt regs che memorizzail contenuto attuale dei registri del processore (per cui dipende dall’architettura, inparticolare per l’IA32 si trova in $(Linux Source)/include/asm-i386/ptrace.h).La funzione restituisce un intero che se uguale a 0 indica il successo dell’operazione dipre–handling, mentre un qualsiasi altro valore indica un fault (catturato poi dal faulthandler).

Post–Handler La funzione di post–handling deve essere di questo tipo:void <nome post-handler> (struct kprobe *kp, struct pt regs *regs, unsignedlong flags);Ad essa vengono passati oltre ai parametri visti prima, anche il parametro unsignedlong flags che pero nell’attuale implementazione del sistema non viene utilizzato mae riservato per eventuali scopi futuri. La funzione restituisce void.

Fault–Handler La funzione di fault–handling deve essere di questo tipo:int <nome fault-handler> (struct kprobe *kp, struct pt regs *regs, int trapnr);Ad essa viene passato il parametro extra int trapnr che indica il numero del fault ve-rificatosi.Essa deve restituire un intero: nel caso in cui esso sia 1, significa che la funzione hagestito il fault, altrimenti il kernel vedra il fault verificatosi gestendolo con l’handler didefault.

Il funzionamento e riassunto nella figura 2.1.

Figura 2.1: Schematizzazione del funzionamento di kprobes.

Page 21: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.1. Le interfacce Capitolo 2. KProbes e SystemTAP 20

2.1.2 jprobe

Come gia affermato in precedenza, jprobes semplifica il processo di strumentazione di fun-zioni:

struct jprobe {struct kprobe kp;kprobe_opcode_t *entry; /* probe handling code to jump to */

};

La struttura incapsula un elemento di tipo struct kprobe necessario per memorizzare leinformazioni necessarie alla registrazione del probing point, e un elemento chiamato entrydi tipo kprobe opcode t*. Il secondo elemento risulta essere la chiave del funzionamentodi jprobe; per poter raccogliere informazioni sui parametri passati alla funzione, entry devepuntare all’entry point di una funzione creata dallo sviluppatore, che abbia la stessa lista diparametri della funzione da strumentare. Il perche di questa condizione verra spiegato nellasottosezione 2.4.2. Per poter utilizzare jprobes e necessario riempire i campi entry e kp.addr,in quanto gli altri campi vengono riempiti automaticamente dalle funzioni di registrazione.

Bisogna notare inoltre che la funzione di strumentazione, nel caso di jprobes, non puoterminare semplicemente con un return, ma deve ritornare esplicitamente con la macrojprobes return(), che permette all’infrastruttura di strumentazione di intercettare l’uscitadalla funzione.

Il funzionamento e schematizzato nella figura 2.2.

Figura 2.2: Schematizzazione del funzionamento di jprobes.

Page 22: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 21

2.1.3 Funzioni di gestione dei probing points

Le funzioni principali per la registrazione dei probing points (definite in linux/kprobes.h)sono le seguenti:

int register kprobe(struct kprobe *p); Viene impiegata per registrare un kprobe. Re-stituisce 0 in caso di successo, un valore diverso da zero in caso contrario.

void unregister kprobe(struct kprobe *p); Viene impiegata per rimuovere un kprobe.

int register jprobe(struct jprobe *p); Viene impiegata per registrare un jprobe. Re-stituisce 0 in caso di successo, un valore diverso da zero in caso contrario.

void unregister jprobe(struct jprobe *p); Viene impiegata per rimuovere un jprobe.

2.2 SystemTAP

Come si e osservato nelle sezioni precedenti, Kprobes rappresenta un’interfaccia di bassolivello, il cui utilizzo implica la scrittura di un modulo per il kernel in linguaggio C, il chepuo rappresentare un procedimento tedioso. Per semplificare e velocizzare il procedimento distrumentazione e stato introdotto SystemTAP, che fornisce un interfaccia di alto livello, conun proprio linguaggio di scripting, per l’utilizzo di Kprobes.

SystemTAP fornisce infatti l’utility stap che accetta una serie di comandi di probing,scritti in un semplice linguaggio di scripting, li traduce in codice C e li compila in un moduloche verra poi caricato nel kernel per svolgere le operazioni di probing o tracing richieste. Latrattazione di SystemTAP comincia con l’analisi della procedura di processing eseguita dalcomando stap e, considerato che in fin dei conti usare SystemTAP equivale semplicementea scrivere un file di script, prosegue quindi con una descrizione piu o meno minuziosa dellinguaggio di scripting supportato.

2.2.1 Procedura di processing di SystemTAP

L’utility stap prende in ingresso l’insieme dei comandi di scripting, che possono essere raccoltiin un file con estensione *.stp, per applicarvi cinque passi:

1. L’utility inizia il parsing del file di scripting, esaminando anche un insieme di file pre-installati, nella directory /usr/share/systemtap/tapset/, oppure in una directoryspecificata dall’utente con l’opzione -I <percorso>. Se si interrompe l’utility al primopasso si ottengono gli alberi di parsing.

2. Il secondo passo consiste nella risoluzione dei nomi iterativamente in tutti i file di scriptche sono stati passati in input dopodiche l’utility cerca di ottimizzare il codice; se sivuole inibire l’ottimizzazione lo si puo fare attraverso l’opzione -u. Infine il secondopasso si conclude con l’operazione di “type-inference” dal contesto su tutte le variabili.In parole povere il traduttore cerca di imporre un tipo alle eventuali variabili il cuitipo non sia stato precisato nel file di scripting (vedere sezione 2.2.2). Ovviamente eun’operazione che sfrutta il contesto in cui la variabile e inserita per “capire” il tipo inbase all’uso che si fa della stessa. Nel caso risultassero delle incongruenze di tipo o fosseimpossibile determinare il tipo di una o piu variabili viene generato un errore. Fermarsi

Page 23: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 22

al secondo passo significa quindi semplicemente fermarsi alla risoluzione dei nomi e deitipi.

3. Il terzo passo consiste nella traduzione delle azioni descritte nel file di script in linguaggioC, nonche nella creazione di un Makefile per la compilazione del modulo da inserire nelkernel. Se si interrompe il procedimento a questo punto si ottengono i file C e il Makefile.

4. Il quarto passo consiste nell’invocazione del sistema di compilazione del kernel di Li-nux attraverso il Makefile; in poche parole si tratta di eseguire il comando make.Interrompendo il processo a questo punto si ottiene il modulo oggetto stap <xxxx>.ko.

5. Il quinto ed ultimo passo consiste nell’invocare il programma ausiliario di SystemTAPper il caricamento del modulo compilato: stpd. Questo programma gestisce il carica-mento del modulo, la comunicazione con esso e il recupero dei dati di tracing. Essorimuove il modulo solo quando viene esplicitamente richiesto dal modulo attraverso lafunzione exit, oppure quando l’utente invia il segnale SIGINT con il comando CTRL+C.Se si verificano errori di run–time vengono indicati sullo schermo, purche non superinoin numero MAXERRORS; in tal caso viene bloccata qualunque ulteriore operazione di pro-bing. Infine stpd effettua il cleanup del modulo rilasciando la memoria, cancellando ifile intermedi prodotti durante le altre fasi.

I passi appena descritti sono mostrati nel diagramma di attivita di figura 2.2.1.

2.2.2 Basi del linguaggio di scripting

Il linguaggio di scripting di SystemTAP e abbastanza semplice ed essenziale; con qualcheleggera differenza si avvicina al linguaggio awk e per quanto riguarda gli operatori e le espres-sioni si approssima al linguaggio di programmazione C. Sostanzialmente i due macrocostruttiprincipali del linguaggio sono:

probe E’ il costrutto fondamentale. Associa un probing point ad una locazione del kernel; aquesto probing point e a sua volta associato un blocco di codice che viene eseguito nelmomento in cui il probing point viene attraversato.

function E’ un costrutto di ausilio per lo scripting usato per suddividere le operazioni daeseguire.

Sintassi generale

Da un punto di vista generico il linguaggio di scripting di SystemTAP non differisce molto daaltri linguaggi di scripting o di programmazione. Gli spazi bianchi sono ignorati, il simbolo“;” non e necessario ma puo essere utile per separare degli statements e sono previsti tre tipidi commenti:

#... Stile shell, da usarsi alla fine di una riga;

//... Stile C, da usarsi alla fine di una riga;

/*...*/ Come in C.

Le stringhe sono sempre racchiuse tra le virgolette e hanno un limite massimo in lunghezzache si aggira intorno a 130 caratteri (di default); gli interi possono essere indicati, con la stessanotazione del C, in base 8, 10 o 16 e sono rappresentati con segno a 64 bit.

Page 24: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 23

Figura 2.3: Diagramma di attivita dell’utility stap.

Page 25: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 24

Variabili e statements

Nel linguaggio di scripting di SystemTAP tutte le variabili possono essere identificate constringhe alfanumeriche. La dichiarazione del tipo non e necessaria e sono ammessi due tipielementari, stringhe ed interi (string e long rispettivamente), oltre agli array costruiti su diessi. E’ onere del traduttore effettuare, poi, un’operazione di “type-inference” come specificatoprecedentemente. Di default ogni variabile e locale al blocco di codice in cui e definita; levariabili globali (global), invece, hanno una visibilita estesa all’intero file di scripting noncheagli altri file che fanno parte dello stesso progetto e per i quali e definito quindi un unicospazio dei nomi. Supponendo che pero sia necessario riferirsi a variabili che non sono definitenello stesso file di script ma altrove, bisogna aggiungere alla variabile il prefisso $ e la variabilesara resa visibile1. A tal proposito va ricordato che le modalita di accesso alla variabile nondifferiscono da quelle del linguaggio C per cui se x e la nostra variabile allora scriveremo:

$x se e una variabile di tipo elementare;

$x[n]...[k] se e un array e vogliamo accedere all’elemento di indice n ... k;

$x->field se e una struttura e vogliamo accedere al campo field2.

Il linguaggio prevede una serie di parole chiave per costruire degli statements piu o menocomplessi che permettano di definire il flusso di controllo all’interno delle funzioni o dei probes.Esiste pero un limite al numero di statements che possono far parte dello stesso probe e quindidella stessa funzione; tale limite e definito dalla macro MAXACTION. Indicando con EXP# unagenerica espressione logica, con STMT# un sotto-statement, con VAR# una generica variabile,con ARRAY# un array, con INDEX# un indice per array e con SCALAR# uno scalare sono ammessii seguenti costrutti:

• if(EXP1) STMT1 [else STMT2]Come in C: se EXP1 e vera viene eseguito STMT1 altrimenti STMT2.

• while(EXP1) STMT1Come in C: si esegue STMT1 finche EXP1 e vera.

• for(EXP1; EXP2; EXP3) STMT1Come in C: EXP1 e una condizione di inizializzazione, EXP2 e la vera condizione davalutare e se vera viene eseguito STMT1 e anche l’espressione di iterazione EXP3.

• foreach(VAR1 in ARRAY1) STMT1Simile al linguaggio python: viene eseguito STMT1 per ogni elemento dell’array ARRAY1;ad ogni ciclo l’indice dell’array viene copiato in VAR1. L’array viene scandito in ordinecrescente o decrescente a seconda dell’operatore + o - che viene postfisso a VAR1 o aARRAY1. L’array deve essere globale e non puo essere modificato da STMT1.

1Questo e possibile sempre grazie alle informazioni di debug di cui SystemTAP fa ampio uso. L’uso diquesto prefisso non e per niente raro dal momento che spesso si vogliono monitorare funzioni del kernel (lesystem call ad esempio) ed e necessario riferirsi ai loro parametri di ingresso che sono definiti nei sorgenti delkernel e non nel file di scripting!

2Va precisato che il linguaggio di scripting prevede l’uso dell’operatore freccia (->) anche quando bisognariferirsi al campo di un record senza passare per un puntatore. In tal caso in C sarebbe stato usato l’operatorepunto (.), in SystemTAP cio non e possibile.

Page 26: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 25

• foreach([VAR1, ..., VARN]in ARRAY1) STMT1Come prima ma usato nel caso di array a piu dmensioni.

• break, continueCome nel C: istruzioni usate all’interno dei cicli precedentemente descritti per forzarel’uscita o l’iterazione negli statements.

• return EXP1Come in C: ritorna il valore dell’espressione EXP1.

• nextRitorno immediato dal probe–handler in cui viene invocato.

• delete ARRAY1[INDEX1, ..., INDEXN]Rimuove dall’array ARRAY1 l’elemento corrispondente agli indici [INDEX1, ..., INDEXN].

• delete ARRAY1Rimuove tutti gli elementi di ARRAY1.

• delete SCALAR1Rimuove lo scalare SCALAR1 e cioe: se esso e una stringa la riporta a “”, se e un interolo riporta a 0 e se e una statistica3 la riporta al suo valore di partenza.

Quello che segue e un breve file di scripting che mette in evidenza l’uso di alcuni tra glistatements appena descritti:

global pari, dispari

probe begin{nd = 0np = 0for(i=0; i<10; i++){

if(i % 2)dispari[nd++] = i

elsepari[np++] = i

}delete pari[0]delete dispari[2]exit()

}

probe end{foreach(x+ in dispari){

log("dispari[".string(x)."]=".string(dispari[x]))}foreach(y- in pari){

3Per le statistiche vedere la sezione 2.2.2

Page 27: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 26

log("pari[".string(y)."]=".string(pari[y]))}

}

Mostriamo quindi il risultato della sua esecuzione:

dispari[0]=1dispari[1]=3dispari[3]=7dispari[4]=9pari[4]=8pari[3]=6pari[2]=4pari[1]=2

Operatori

Sono ammessi tutti gli operatori logici e matematici comunemente supportati nel linguaggioC (anche le forme abbreviate) e si conservano significato e ordine di precedenza. Ci sonocomunque alcuni operatori aggiuntivi come quello di aggregazione descritto nella sezione 2.2.2.Eccone un elenco:

• operatori binari numerici

*, /, %, +, -, >>, <<, &, ^, |, &&, ||

• operatori binary per stringhe (concatenazione)

.

• operatori di assegnazione numerica

=, *=, /=, %=, +=, -=, >>=, <<=, &=, ^=, |=

• operatori di assegnazione per stringhe

=, .=

• operatori unari numerici

+,-,!, ~, ++, --

• operatori binari di comparazione numerica o tra stringhe

<, >, <=, >=, ==, !=

• operatore ternario

COND?EXP1:EXP2

Page 28: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 27

• operatore di raggruppamento e precedenza

(EXP)

• chiamata di funzione

func([arg0, ..., argn])

Qualche parola va spesa pero sul come possono essere espresse le condizioni di pre–processing, cioe quelle condizioni che sono locate all’inizio dei file di scripting. Queste condizio-ni infatti debbono essere obbligatoriamente espresse attraverso gli operatori ternari mostratiprima. Precisamente, una condizione di pre–processing avra un aspetto del genere:

%( COND %? EXPIFTRUE [%: EXPIFFALSE] %)

dove COND e la condizione da valutare, EXPIFTRUE e l’istruzione da eseguire se la condizionee vera e EXPIFFALSE e l’istruzione eseguita se invece e falsa4. Per tutte le altre condizioni eammessa invece anche la forma non ternaria.

Probes

I probes associano eventi astratti a blocchi di codice da eseguirsi ogniqualvolta tali eventi siverifichino. Sintatticamente li si definisce in questo modo:

probe [ALIAS =] probepoint0 [, probeboint1 [ ... ] ] {blocco di codice

}

Molto interessante e il meccanismo di aliasing supportato. A tal proposito, si analizzi ilseguente esempio:

probe mioprobe = kernel.function("sys_read"){desc = $fd #$fd e il file descriptor

}

probe mioprobe {printf("File descriptor = %d\n", desc)

}

In tale esempio e stato definito un solo vero probe point chiamato mioprobe e che vieneattivato quando viene invocata la system call read. Il probe che viene effettivamente attivatoe il secondo ma il primo e necessario perche e il probe che estende la seconda definizione cheda sola non avrebbe senso. In parole povere il traduttore trasforma questi due probe in unosolo e precisamente in:

4Ovviamente le parentesi quadre indicano che e possibile anche non specificare alcuna istruzione da eseguirein caso di condizione falsa.

Page 29: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 28

probe kernel.function("sys_read"){desc = $fd #$fd e il file descriptorprintf("File descriptor = %d\n", desc)

}

Grazie al meccanismo di aliasing gli autori di SystemTAP hanno definito, all’interno dialcuni file della directory /usr/share/systemtap/tapset, gli alias per tutte le system calldel sistema operativo attraverso definizioni come le seguenti, dove la prima forma e utilizzataper le system call piu frequenti (open, read...):

probe syscall.<nome>[.return] =kernel.function("sys_<nome>")[.return]{...}

probe kernel.syscall.<nome>[.return] =kernel.function("sys_<nome>")[.return]{...}

In consegenza di cio e possibile probare qualunque system call attraverso l’inserimento diprobe del genere:

probe [kernel.]syscall.<nome>[.return]{...}

Per rendersi conto delle variabili a cui si puo accedere e in ogni caso sufficiente analizzarei file in cui sono definiti gli alias senza la necessita di ispezionare i sorgenti veri e propri delkernel.

A monte di tutto cio resta il fatto che i probepoint possono essere scelti fra una serie ditipi supportati dal sistema di traduzione:

begin e end Questi due tipi sono predefiniti dal sistema di traduzione e si riferiscono all’i-stante di inizializzazione e terminazione rispettivamente del modulo. Possono esserne presentipiu di uno per tipo, e in tal caso si eseguono nell’ordine di definizione, oppure possono mancarecompletamente.

timer Questo tipo di probing point genera un evento periodico. Il periodo puo essere de-finito in jiffies, con timer.jiffies(n), o in millisecondi con timer.ms(n). Inoltre e possi-bile specificare un valore aleatorio con distribuzione uniforme compreso in [−n, n] che vienesommato al valore fornito come intervallo m, ad esempio: timer.jiffies(m).randomize(n)o timer.ms(m).randomize(n)5. Infine e possibile specificare timer.profile che genera unevento alla frequenza dei tick del processore. Un esempio di probe del tipo timer e il seguente:

probe timer.ms(1000){exit()

}

Questo probe puo essere usato per forzare l’uscita dal modulo di monitoraggio dopo untempo pari ad un secondo.

5A seconda dell’unita di misura scelta per l’intervallo, il parametro aleatorio n specifica la semiampiezza diun intervallo dell’ordine dei jiffies o dei millisecondi.

Page 30: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 29

dwarf Questa famiglia di probe points utilizza le informazioni simboliche di debugging con-tenute nel kernel, o nel package kernel-debuginfo, per generare eventi collegati ad identifica-tivi quali il nome di una system call, di un modulo, la riga di un file C, o una combinazione diquesti. Inoltre, diversamente dai probing point di tipo timer, questi sono sincroni, in quantosi verificano ogniqualvolta il processore incontra un’istruzione che corrisponda ad essi.

Si suddividono in kernel dwarves e module dwarves; sintatticamente debbono inserirsi conle seguenti espressioni

kernel.<sotto-famiglia>[.sotto-famiglia]{...}

module(MPATTERN).<sotto-famiglia>[.sotto-famiglia]{...}

il primo tipo di probe point fa riferimento al kernel intero, mentre il secondo ad un moduloche rispetti un determinato pattern.

Ciascuno di essi supporta le seguenti sotto–famiglie:

function(PATTERN) Identifica una funzione del modulo o del kernel piazzando un breakpointpresso l’entry point della funzione desiderata (cioe specificata da PATTERN);

return Identifica la fine di una funzione, piazzando un breakpoint presso il termine dellafunzione desiderata concatenandosi ad un’espressione come la precedente;

inline(PATTERN) Identifica una funzione inline6. Con esso non e possibile utilizzare returnperche le funzioni inline non hanno un punto di ritorno;

statement(PATTERN) Identifica un posto ben preciso (riga, indirizzo) all’interno del filesorgente ponendovi un breakpoint.

In tutti i casi MPATTERN e PATTERN sono delle stringhe che possono contenere anche icaratteri speciali * (qualunque sequenza di caratteri) e ? (qualunque carattere ma uno solo)onde identificare piu nomi. MPATTERN serve semplicemente ad identificare un modulo del kernelmentre PATTERN identifica un punto all’interno di un programma. Precisamente, quest’ultimo,e costituito da tre parti (ma puo anche essere un indirizzo di memoria):

1. parte obbligatoria che specifica il nome di una funzione;

2. parte opzionale che comincia col carattere @ e identifica un file sorgente con il relativopath;

3. parte opzionale che comincia col carattere : e identifica una riga ben precisa del filesorgente specificato nella seconda parte.

Per meglio chiarire l’utilizzo di questi probing point ecco alcuni esempi:

kernel.function(‘‘ kmalloc’’) Genera un evento ogniqualvolta viene invocata la funzio-ne kmalloc.

module(‘‘ntfs’’).function(‘‘device read’’) Genera un evento ogniqualvolta viene ri-chiamata la funzione device read del modulo ntfs.

6La sua utilita risulta piu chiara considerando che le funzioni inline vengono compilate per estensione neipunti in cui vengono richiamate, quindi non sono funzioni nel reale senso della parola.

Page 31: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 30

kernel.inline(‘‘context switch’’) Genera un evento quando si esegue la funzione inlinecontext switch.

kernel.statement(0xc0143a51) Genera un evento quando si raggiunge il primo byte dellostatement le cui istruzioni compilate includano tale indirizzo;

kernel.function(‘‘*kernel/sched.c:20’’) Genera un evento quando si raggiunge qua-lunque funzione (*) del file sched.c che attraversi la riga 20.

Functions

Le funzioni prendono in ingresso un numero di parametri qualsiasi (stringhe o interi) perrestituire in uscita un singolo scalare, stringa o intero. Un esempio di funzione puo esserequesto:

function prova(arg1:long, arg2) {return arg1 + arg2}

Da notare che non e necessario specificare il tipo delle variabili impiegate ed e previsto untipo speciale (unknown) nel caso in cui la funzione non restituisca alcun valore.

Le funzioni possono essere ricorsive tuttavia il limite massimo della profondita raggiungi-bile e specificato dal valore della macro MAXNESTING.

Chiamate di printing/logging

Quando il traduttore incontra nella fase di parsing una chiamata ad una funzione di prin-ting o logging, esso la considera una chiamata speciale per formattare in maniera opportunale informazioni da loggare e che derivano probabilmente dalla procedura di probing. Sonoammesse le seguenti chiamate

print() prende un unico valore di qualunque tipo7 e lo stampa sullo standard output8;

log() identica a print ma accetta solo stringhe e include un end-of-line implicito;

printf() opera come printf della libreria C stdio.h ossia stampa sullo standard outputun insieme di valori anche di tipo diverso;

sprint() opera come print ma invece di stampare la stringa a video, semplicemente larestituisce cosı come viene costruita;

sprintf() opera come printf ma alla maniera di sprint cioe non stampa niente a videoma ritorna la stringa costruita a partire dall’ingresso dove ci possono essere elementi ditipo qualunque;

warn() opera come log ma e usata solo per lanciare messaggi di warning;7Non proprio qualunque tipo ma soltanto i due tipi fondamentali del lilguaggio di scripting ossia stringa e

intero.8E’ interessante vedere cosa viene stampato quando l’argomento della funzione e un istogramma. A tal

proposito si rimanda alla sezione 2.2.2.

Page 32: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 31

error() opera similmente a warn stampando il messaggio d’errore specificato9 ma bloccaanche l’esecuzione di tutti i successivi statements che fanno parte del probe in cui einserito e se il numero di volte che viene lanciato supera il valore della macro MAXERRORSallora viene proprio invocata la funzione di exit;

errno str:string(e:long) ritorna semplicemente una stringa costruita a partire dal codicedi errore specificato in ingresso10.

Altre chiamate speciali

Nella sezione precedente sono state esaminate tutta una serie di funzioni che e possibile in-vocare per stampare informazioni varie ma il linguaggio di scripting supporta molte altrefunzioni che, cosı come tutta la struttura di SystemTAP, non sono altro che un’interfacciaverso funzioni definite a livello di linguaggio C e quindi nei sorgenti del kernel inclusi, soprat-tutto, quelli di kprobes (vedi funzione di dump dei registri ad esempio). Ecco l’elenco dellepiu utili con specificati i tipi del valore di ritorno e dei parametri d’ingresso:

Conversioni e operazioni su stringhe Funzioni di conversione che coinvolgono i tipiprincipali del linguaggio ossia string e long nonche le piu comuni funzioni usate per operaresulle stringhe:

hexstring:string(num:long) converte un intero espresso in base dieci in forma esadecimaleanteponendo al valore il simbolo 0x;

string:string(num:long) converte un intero nell’equivalente stringa di cifre;

kernel string:string(addr:long) copia una stringa dallo spazio kernel all’indirizzo spe-cificato;

user string:string(addr:long) copia una stringa dallo spazio utente all’indirizzo specifi-cato11;

strlen:long(str:string) restituisce il numero di caratteri di cui e costituita la stringa iningresso;

substr:string(str:string, start:long, stop:long) restituisce a partire dalla stringastr la sottostringa di caratteri dal numero start al numero stop;

isinstr:long(s1:string, s2:string) ritorna 1 se la stringa s1 contiene la stringa s2 0altrimenti.

Timestamp Funzioni che forniscono informazioni di timestamp facendo riferimento al fa-moso istante noto come “UNIX epoch” (UTC) ossia al 1 gennaio 1970:

gettimeofday us:long() ritorna il numero di microsecondi dall’UTC;9A cui va anteposta la stringa “ERROR” cosı come nel caso precedente era anteposta la stringa “WARNING”.

10Ad esempio al codice 2 corrispondera la stringa “ENOENT”.11Attenzione! Ad oggi il meccanismo di validazione dell’indirizzo e ancora parziale, quindi usare con cautela

queste due ultime funzioni.

Page 33: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 32

gettimeofday ms:long() ritorna il numero di millisecondi dall’UTC;

gettimeofday s:long() ritorna il numero di secondi dall’UTC.

Informazioni relative al contesto Funzioni che consentono di accedere ad informazionirelative al contesto del processo come identificativi vari o contenuto dei registri:

execname:string() ritorna il nome del processo corrente;

pexecname:string() ritorna il nome del padre del processo corrente;

pid:long() ritorna il pid del processo corrente;

ppid:long() ritorna il pid del padre del processo corrente;

uid:long() ritorna l’identificativo dell’utente del processo corrente;

euid:long() ritorna l’identificativo effettivo dell’utente del processo corrente;

gid:long() ritorna l’identificativo del gruppo del processo corrente;

egid:long() ritorna l’identificativo effettivo del gruppo del processo corrente;

print regs:unknown() stampa un dump del contenuto dei registri del processore;

print backtrace:unknown() stampa un backtrace simbolico;

backtrace:string() ritorna una stringa di indirizzi in esadecimale che rappresentano unbacktrace dello stack;

print stack(bt:string) esegue una ricerca simbolica degli indirizzi in bt e li stampa unoper riga;

pp:string() ritorna il punto di probe associato al probe handler inclusi alias e estensioni;

target:long() ritorna il pid del processo target.

Statistiche

Il linguaggio di scipting di SystemTAP offre un interessante meccanismo che consente dicollezionare statistiche relativamente al valore di variabili numeriche. Innanzitutto e possibileutilizzare un particolare operatore binario, detto operatore di aggregazione e il cui simbolo e<<<, per inserire valori numerici (che molto probabilmente varieranno nel tempo) in una pilache deve essere dichiarata globale. La sintassi e la seguente:

var <<< numbers

dove var puo essere ad esempio uno scalare e numbers e un’espressione numerica. Unavolta che la pila viene riempita con dei valori e possibile ottenere informazioni statistiche sudi essi attraverso le seguenti funzioni di estrazione molto simili a quelle messe a disposizionedal linguaggio di interrogazione delle basi di dati (SQL):

@count(var) ritorna il numero degli elementi della pila var;

Page 34: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 33

@sum(var) ritorna la somma degli elementi della pila var;

@min(var) ritorna il minino tra gli elementi della pila var;

@max(var) ritorna il massimo tra gli elementi della pila var;

@avg(var) ritorna la media aritmetica degli elementi della pila var.

Tutte queste funzioni restituiscono un intero. Per ottenere informazioni ancora piu dettagliatee possibile pero utilizzare le seguenti funzioni di istogramma:

@hist linear(var, L, H, W) rappresenta un istogramma lineare di cui sono specificati iningresso il minino (Low), il massimo (High) e il passo (Width). Precisamente vienecostruito l’insieme I = {L, L+W, L+2W, ..., L+kW, ..., W} e per ogni elemento del-l’insieme viene mostrata una barra che conta il numero di occorrenze di quell’ elementoall’interno della pila var12;

@hist log(var, N) come prima ma l’insieme I e costruito con elementi che sono potenzedi 2 (da cui il nome di istogramma logaritmico in base 2) e N e il numero di intervalli(buckets) in cui viene suddiviso l’asse delle ascisse (di default pari a 64).

In tal caso il valore di ritorno e evidentemente un vettore e non uno scalare come nel casodelle funzioni precedenti. E’ possibile usare la funzione print() per ottenere un isogrammatabulare a barre costruite col simbolo @ (chiocciola).

C embedded

Fino a questo punto abbiamo analizzato a grandi linee gli elementi di base del linguaggio discripting di SystemTAP e abbiamo potuto notare che esso si rivela assai simile al linguag-gio di programmazione C. Abbiamo anche detto, nella sezione 2.2.1, che nella terza fase diprocessazione viene fatta una traduzione del linguaggio di scripting proprio nel linguaggio C.In realta, proprio per questi motivi, e possibile incorporare, generalmente all’inizio del file(#include... #define...) o nelle function, righe di codice scritte completamente in C.Per fare cio e sufficiente delimitare queste porzioni di codice C in questo modo:

%{ codice C... codice C... %}

Il traduttore accetta questi stralci di codice esclusivamente nella modalita “guru” (opzione -galla chiamata di stap). Resta un ultimo problema da risolvere: come fare a riferirsi dal C aduna variabile che e definita nel linguaggio di scripting? A tale scopo viene in aiuto la macroTHIS che consente di fare riferimento ai parametri di input o di output di una funzione. Sisupponga ad esempio di avere la seguente funzione:

function fn:long (var1){if (var1 % 2)

return var1*2else

return var1*3}

12In termini statistici si ottiene semplicemente il grafico di una funzione di distribusione di probabilita (nonnormalizzata).

Page 35: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.2. SystemTAP Capitolo 2. KProbes e SystemTAP 34

Volendo usare il C, essa puo essere scritta facilmente in questo modo:

function fn:long (var1)%{if (THIS->var1 % 2)

THIS->__retvalue = THIS->var1*2;else

THIS->__retvalue = THIS->var1*3;%}

Le due espressioni sono perfettamente equivalenti!

2.2.3 Macro e files

Avendo fornito una spiegazione piu o meno esaustiva di SystemTAP e del suo linguaggiodi scripting, possiamo fornire un paio di informazioni per poter utilizzare al meglio questainterfaccia. Innanzitutto ricordiamo che il programmatore puo settare attraverso delle macro(alcune gia incontrate nelle sezioni precedenti) alcuni parametri di base relativi a certe opzioni.In particolare e possibile ridefinire le seguenti macro:

MAXNESTING massimo livello di profondita raggiungibile da una funzione ricorsiva;

MAXSTRINGLEN massima lunghezza di una stringa;

MAXTRYLOCK massimo numero di iterazioni per cui si puo attendere su locks globali prima didichiarare una possibile situazione di deadlock e saltare il probe;

MAXACTION massimo numero di statements eseguibili per ogni probe hit;

MAXMAPENTRIES massimo numero di righe di ciascun array globale;

MAXERRORS massimo numero di errori (non gravi) prima che venga provocata un’uscita;

MAXSKIPPED massimo numero di probres rientranti (in cui viene invocato next) saltati primadi provocare un’uscita.

Naturalmente per ridefinire una qualunque di queste macro bastera utilizzare l’opzione -Ddalla riga di comando e definire un nuovo valore secondo la sintassi -DNOMEMACRO=VALORE. Varicordato infine che tutta la struttura di SystemTAP fa riferimento ad una serie di informazionicontenuti in file che debbono avere locazioni ben determinate cosı come viene precisato diseguito:

tmp/stapXXXXXX e la directory temporanea che conserva i file creati dal traduttore col co-mando stap compresi i file .c e i file oggetto .ko del modulo ottenuto.

/usr/share/systemtap/tapset e la directory di ricerca di file di SystemTAP prevista didefault, ma pua essere modificata attraverso la variabile d’ambiente SYSTEMTAP TAPSET.

/usr/share/systemtap/runtime e la directory predefinita per i sorgenti runtime di System-TAP; puo essere modificata attraverso la variabile d’ambiente SYSTEMTAP RUNTIME.

/lib/modules/VERSIONE/build e la directory per l’infrastruttura di costruzione dei modulidel kernel.

Page 36: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 35

/usr/lib/debug/lib/modules/VERSIONE e la directory che contiene le informazioni di de-bugging del kernel13.

/usr/libexec/systemtap/stpd e la directory che contiene il programma d’ausilio che ge-stisce il caricamento e la terminazione nonche il recupero dati relativi al modulo ossial’applicazione stpd.

Con cio si chiude la trattazione di SystemTAP; per comprendere meglio il significatodi quanto esposto rimandiamo alla sezione 2.3.3 dove vengono mostrati esempi dell’utilizzodell’interfaccia. Qualche ulteriore informazione, soprattutto sulle possibili opzioni, e possibileottenerla dall’help in linea dell’utility stap (man stap).

2.3 Esempi

2.3.1 Kprobes - Monitoraggio di kmalloc

In questo primo esempio ci proponiamo di mostrare l’impiego di kprobes nel monitorare lachiamata della funzione del kernel kmalloc utilizzata dai processi per richiedere un certonumero di byte di memoria. A tal scopo sara necessario costruire un modulo di monitoraggioche andra caricato e scaricato opportunamente negli istanti in cui deve cominciare la fase diprobing e quando deve terminare. Questo modulo deve inoltre ricevere come parametro diingresso il valore che ci consente di riempire il campo addr della sruttura kprobe onde settarel’indirizzo della funzione da probare, indirizzo che possiamo ricavare dalla mappa di sistema.Sia dato quindi il seguente file kmalloc.c:

#include <linux/module.h> /* Necessario per i moduli */#include <linux/kernel.h> /* Header principale del Kernel */#include <linux/kprobes.h> /* Per usare kprobes */

/* Descrizione del modulo */MODULE_AUTHOR("Cristofaro Gozzolino, Paolo Guadagnuolo");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Prova di utilizzo di kprobes");

/* Funzioni di init e cleanup del modulo */static int __init prova_start(void);static void __exit prova_end(void);

/* Variabile che memorizza il numero di chiamate */static long calls = 0;

/* Indirizzo della funzione passato in ingresso al modulo*/static long indirizzo = 0;module_param(indirizzo, long, 0000);MODULE_PARM_DESC(indirizzo, "Indirizzo della __kmalloc()");

13Informazioni simboliche su cui SystemTAP si basa come detto nella sezione 2.2.2.

Page 37: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 36

/* Dihiarazione delle funzioni di handling */int handler_pre(struct kprobe *kp, struct pt_regs *regs);void handler_post(struct kprobe *kp, struct pt_regs *regs, unsigned long flags);int handler_fault(struct kprobe *kp, struct pt_regs *regs, int trapnr);

/* Assegnazione degli handler al kprobe */static struct kprobe kp = {

.pre_handler = handler_pre,

.post_handler = handler_post,

.fault_handler = handler_fault,};

/* Caricamento del modulo */static int __init prova_start(void){

printk(KERN_INFO "Ciao sei entrato nel modulo\n");kp.addr = (kprobe_opcode_t *) (int)indirizzo; //indirizzo di kmalloc()if (register_kprobe(&kp)) {

printk(KERN_ALERT "Impossibile registrare il breakpoint.\n");return -1;

};return 0;

}

/* Terminazione del modulo */static void __exit prova_end(void){

unregister_kprobe(&kp);printk(KERN_INFO "Ciao sei uscito dal modulo\n");printk(KERN_INFO "La funzione e stata invocata %d volte\n", calls);

}

/* Pre-Handler: incrementa il numero di chiamate */int handler_pre(struct kprobe *kp, struct pt_regs *regs){

printk(KERN_INFO "Pre-Handler invocato!\n");return 0;

}

/* Post-Handler */void handler_post(struct kprobe *kp, struct pt_regs *regs, unsigned long flags){

printk(KERN_INFO "Post-Handler invocato!\n");calls++;

}

/* Fault-Handler*/int handler_fault(struct kprobe *kp, struct pt_regs *regs, int trapnr){

printk(KERN_INFO "Fault-Handler invocato!\n");return 0;

}

Page 38: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 37

/* Alias delle funzioni del modulo */module_init(prova_start);module_exit(prova_end);

Parte del codice del file e necessaria per la costruzione del modulo come le funzioni di inited exit che vengono invocate proprio all’atto del caricamento e della terminazione rispetti-vamente. La prima riga che concerne esplicitamente il nostro obiettivo e quella in cui vienedichiarata la variabile globale calls che sara utilizzata per memorizzare il numero comples-sivo di invocazioni della funzione monitorata. Quindi entra in gioco il parametro di ingressoindirizzo. Esso deve essere fornito in ingresso al modulo e viene quindi costruito apposi-tamente secondo le regole di costruzione dei parametri di ingresso dei moduli. Procedendonell’analisi del file e possibile trovare la dichiarazione degli handler e quindi la loro associazioneall’elemento di tipo struct kprobe che verra utilizzato per il probing della funzione. L’ope-razione piu importante da eseguire sul kprobe e sicuramente l’inizializzazione del suo campoaddr che contiene l’indirizzo (in forma intera) della funzione da monitorare e che nel nostrocaso verra passato direttamente in ingresso al modulo. Quindi si passa alla sua registrazionetramite la chiamata della funzione register kprobe(). Queste due operazioni, ovviamente,non possono essere eseguite che all’atto del caricamento del modulo e quindi nella funzione diinit del modulo stesso. In maniera simile, nella funzione di exit sara necessario deregistra-re il kprobe attraverso l’invocazione della funzione unregister kprobe. Infine troviamo leimplementazioni degli handler precedentemente dichiarati. Il pre–handler e il fault–handlernon eseguono operazioni di interesse, in quanto stampano semplicemente un messaggio. Ilpost–handler invece, oltre a stampare un breve messaggio, incrementa la variabile che tienetraccia del numero totale di chiamate della funzione e che viene poi stampata alla fine dellafase di probing cioe quando il modulo viene scaricato e quindi nella chiamata della exit.

Per compilare il sorgente come modulo sara necessario costruire un particolare Makefilecome il seguente:

obj-m += kmalloc.oall:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

A questo punto si esegue il comando make e si otterra il file kmalloc.ko che costituisce ilmodulo vero e proprio. Prima di eseguire l’esperimento e necessario conoscere l’indirizzo dellafunzione che si vuole monitorare e che deve essere ricavato dalla mappa di sistema. Quindiattraverso un comando del tipo

cat /boot/System.map-$(uname -r) |grep __kmalloc

e possibile ottenere l’indirizzo in esadecimale della kmalloc che supponiamo sia c0146348.Adesso e possibile eseguire l’esperimento caricando il modulo e passando l’indirizzo appenatrovato facendo attenzione ad usare il prefisso 0x. Eseguiamo quindi il comando:

insmod kmalloc.ko indirizzo=0xc0146348

Page 39: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 38

Da questo momento in poi comincia la fase di probing e sara possibile interromperla inqualunque momento attraverso il comando di terminazione del modulo ossia:

rmmod kmalloc.ko

Per ottenere informazioni sull’esperimento sara poi sufficiente esaminare il file /var/log/messagesin cui e possibile trovare righe di questo tipo:

Mar 8 11:06:04 localhost kernel: Ciao sei entrato nel moduloMar 8 11:06:04 localhost kernel: Pre-Handler invocato!Mar 8 11:06:04 localhost kernel: Post-Handler invocato!...Mar 8 11:06:07 localhost kernel: Post-Handler invocato!Mar 8 11:06:07 localhost kernel: Pre-Handler invocato!Mar 8 11:06:07 localhost kernel: Post-Handler invocato!Mar 8 11:06:07 localhost kernel: Pre-Handler invocato!Mar 8 11:06:07 localhost kernel: Post-Handler invocato!Mar 8 11:06:07 localhost kernel: Ciao sei uscito dal moduloMar 8 11:06:07 localhost kernel: La funzione e stata invocata 1101 volte

In tal caso si nota che la funzione kmalloc e stata invocata ben 1101 volte in pochisecondi! Andrebbe precisato che per come e stato costruito questo esempio non viene fattanessuna assunzione sull’indirizzo che viene passato in ingresso. In parole povere questo modulopotrebbe essere utilizzato per una qualunque funzione che si trovi nella mappa di sistema; gliunici punti del codice che fanno esplicito riferimento alla kmalloc sono quelli di descrizionedel modulo e dei parametri ma ovviamente la loro presenza non pregiudica un esperimentoin cui viene fornito all’ingresso l’indirizzo di una funzione diversa dalla kmalloc. Infineva ricordato ancora una volta che il monitoraggio della funzione e limitato all’intervallo ditempo compreso tra gli istanti in cui si eseguono, nell’ordine, insmod e rmmod. In teoriapotrebbe quindi accadere, soprattutto per funzioni invocate saltuariamente, che il modulonon catturi alcuna chiamata della funzione. Questo potrebbe spingere il programmatorea caricare il modulo in maniera automatica all’avvio del sistema operativo e lasciarlo inesecuzione (anche fino allo spegnimento del sistema); cio assicurerrebbe un monitoraggiocompleto e aumenterebbe la probabilita di catturare almeno una chiamata della funzionesotto esame.

2.3.2 Jprobes - Monitoraggio di kmalloc

L’interfaccia jprobes semplifica notevolmente l’utilizzo di kprobes; in tal caso infatti non epiu necessario definire i vari handler, ma basta definire una funzione che abbia una lista diparametri uguale a quella da strumentare. Nel nostro esempio strumenteremo, ancora unavolta, le richieste di memoria addizionale che i processi inviano al kernel invocando la funzionekmalloc.

Onde utilizzare jprobe e necessario conoscere l’indirizzo della funzione che vogliamo mo-nitorare ma bisogna pure definire una funzione che la strumenti e che abbia la stessa lista diparametri:

Page 40: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 39

static void *strum_kmalloc(size_t size, unsigned int flags) {num_of_memory_allocations++;num_of_total_bytes += size;

printk("E’ stata fatta una richiesta di %d bytes dimemoria dal processo PID %d.\n",size, current->pid);

jprobe_return();}

Tale funzione sara richiamata prima che la reale kmalloc sia invocata; tuttavia, come sipuo notare dallo stralcio di codice non e possibile ritornare dalla funzione attraverso un returnnormale, ma bisogna richiamare esplicitamente l’infrastruttura di strumentazione attraversola macro jprobes return().

L’ultimo passo da compiere per registrare il probing point e quello di dichiarare una varia-bile di tipo struct jprobe e riempirne il campo entry, che indica l’entry point della funzionestrumentante, e .kp.addr che indica l’entry point della funzione da strumentare14. Anche inquesto caso, come nell’esempio della sezione 2.3.1, l’indirizzo della funzione kmalloc vienepassato come parametro di ingresso del modulo. Fatto questo e possibile poi registrare ilprobing point attraverso la funzione register jprobe e cancellarlo attraverso la funzioneunregister jprobe.

Ecco il listato completo del modulo kmalloc.c:

#include <linux/module.h>/* Necessario per i moduli */#include <linux/kernel.h>/* Header principale del Kernel */#include <linux/kprobes.h>/* Per usare Jprobes */

/* Macro per definire le informazioni del modulo */MODULE_AUTHOR("Paolo Guadagnuolo, Cristofaro Gozzolino");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Prova utilizzo jprobes");

/* Parametro d’ingresso al modulo*/static long indirizzo = 0;module_param(indirizzo, long, 0000);MODULE_PARM_DESC(indirizzo, "Indirizzo della __kmalloc()");

/* Prototipi */static int __init prova_module_initialization(void);static void __exit prova_module_cleanup(void);

/* Prototipo della funzione di strumentazione */static void *strum_kmalloc(size_t, unsigned int);

/* Struttura dati Jprobes */

14La struttura dati jprobe incapsula la struttura kprobe.

Page 41: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 40

static struct jprobe jp;

/* Numero di richieste di memoria */static int num_of_memory_allocations = 0;

/* Numero totale di byte richiesti */static int num_of_total_bytes = 0;

static int __init prova_module_initialization(void) {

jp.kp.addr = (kprobe_opcode_t *) (int)indirizzo;jp.entry = (kprobe_opcode_t *) &strum_kmalloc;

/* Tenta di registrare il breakpoint */if (register_jprobe(&jp)) {

printk(KERN_ALERT "Impossibile registrare il breakpoint.\n");return -1;

}

printk("Breakpoint registrato.\n");

return 0;}

static void __exit prova_module_cleanup(void) {unregister_jprobe(&jp);printk(KERN_INFO "Sono state fatte %d richieste di memoria.\n",

num_of_memory_allocations);printk(KERN_INFO "Sono stati richiesti %d bytes totali.\n",

num_of_total_bytes);}

static void *strum_kmalloc(size_t size, unsigned int flags) {num_of_memory_allocations++;num_of_total_bytes += size;

printk("E’ stata fatta una richiesta di %d bytesdi memoria dal processo PID %d.\n", size, current->pid);

jprobe_return();}

/* Indica quali sono le routine di inizializzazione e di cleanup */module_init(prova_module_initialization);module_exit(prova_module_cleanup);

Per costruire il Makefile e ottenere l’indirizzo della kmalloc si proceda come nell’e-

Page 42: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 41

sempio della sezione 2.3.1. Adesso se si prova a compilare il modulo, a caricarlo con insmodkmalloc.ko indirizzo=0x0146348 e scaricarlo con rmmod kmalloc.ko, si otterranno dellerighe nel file /var/log/messages del tipo:

Breakpoint registrato.

........

E’ stata fatta una richiesta di 104 bytes di memoria dal processo PID 3282.E’ stata fatta una richiesta di 288 bytes di memoria dal processo PID 3906.E’ stata fatta una richiesta di 24 bytes di memoria dal processo PID 3906.E’ stata fatta una richiesta di 96 bytes di memoria dal processo PID 3933.E’ stata fatta una richiesta di 288 bytes di memoria dal processo PID 2655.E’ stata fatta una richiesta di 192 bytes di memoria dal processo PID 2655.E’ stata fatta una richiesta di 288 bytes di memoria dal processo PID 3906.E’ stata fatta una richiesta di 24 bytes di memoria dal processo PID 3906.E’ stata fatta una richiesta di 288 bytes di memoria dal processo PID 2655.E’ stata fatta una richiesta di 192 bytes di memoria dal processo PID 2655.E’ stata fatta una richiesta di 64 bytes di memoria dal processo PID 3906.E’ stata fatta una richiesta di 96 bytes di memoria dal processo PID 3976.E’ stata fatta una richiesta di 1024 bytes di memoria dal processo PID 4002.E’ stata fatta una richiesta di 96 bytes di memoria dal processo PID 3976.E’ stata fatta una richiesta di 80 bytes di memoria dal processo PID 5207.E’ stata fatta una richiesta di 256 bytes di memoria dal processo PID 5207.E’ stata fatta una richiesta di 19 bytes di memoria dal processo PID 5207.E’ stata fatta una richiesta di 192 bytes di memoria dal processo PID 5207.Sono state fatte 458 richieste di memoria.Sono stati richiesti 139806 bytes totali.

In questo caso, avendo utilizzato jprobes, e stato possibile accedere ai parametri di ingressodella funzione oltre che conoscere il numero di volte che viene invocata. Inoltre, a differenzadi prima, questo modulo non puo essere utilizzato per una qualunque funzione ma solo perla kmalloc o al piu per una funzione che abbia la stessa lista di parametri (in quel caso ivalori stampati non sarebbero pero i bytes richiesti).

2.3.3 SystemTAP - Monitoraggio di kmalloc con statistiche

L’esempio fornito in questa sezione risulta una versione adattata a SystemTAP (con l’aggiuntadi varie informazioni) di quello fornito per il caso di kprobes e jprobes. Innanzitutto forniamoil seguente file di scripting chiamato stapex01.stp:

#stapex01.stp

/* Variabili globali: le prime due* usate per calcolare il tempo di* probing, le restanti sono statistiche.*/

Page 43: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 42

global start, end, mem, lotmem, lasttime, vartime

/* Quando si carica il modulo* viene memorizzato l’istante.*/

probe begin {printf("START PROBING\n");start = gettimeofday_ms()

}

/* Vogliamo che il modulo esegua* il monitoraggio per 10 secondi.*/

probe timer.ms(10000){print("In circa 10 secondi sono stati chiesti

meno di 15 MB di memoria!\n")exit()

}

/* Probe usato per catturare la* chiamata di kmalloc. Si fa* ampio uso delle statistiche.*/

probe kernel.function("__kmalloc@mm/slab.c"){printf("Il processo %d (%s) figlio di %d (%s)\nha chiesto [%d] bytes di memoria!\n", pid(),execname(), ppid(), pexecname(), $size)//Accumuliamo i dati sulle richiestemem <<< $size

if ($size > 4096){

/* Quando una richiesta supera i 4 KB* la si accumula e si conserva anche* l’istante e l’intervallo dall’ultima* richiesta.*/

lasttime <<< gettimeofday_us()lotmem <<< $sizevartime <<< (gettimeofday_us()-@max(lasttime))

}if (@sum(mem) >= 15728640){

/* Se la memoria totale richiesta

Page 44: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 43

* supera i 15 MB scarichiamo (error) il* il modulo e stampiamo i dati.*/

end = gettimeofday_ms()msg = ("\n").sprintf("Punto di saturazione

raggiunto dopo %d ms!", (end-start))statistics()error(msg)

}}

/* Alla fine del monitoraggio* vengono stampati i dati* statistici.*/

probe end{print("END PROBING\n")efftime()statistics()

}

/* Funzione usata per stampare i dati* statistici relativi alle richieste* generali di memoria.*/

function stampamem(){print("\n STATISTICHE MEMORIA RICHIESTA\n")printf("-Numero totale di richieste di memoria:

%d\n", @count(mem))printf("-Memoria totale richiesta:

%d bytes\n", @sum(mem))printf("-Picco minimo di memoria richiesta:

%d bytes\n", @min(mem))printf("-Picco massimo di memoria richiesta:

%d bytes\n", @max(mem))printf("-Valor medio di memoria richiesta:

%d bytes\n", @avg(mem))printf("-Memoria media richiesta ogni secondo:

%d KB/s\n", (@sum(mem)/1024)/((end-start)/1000))}

/* Funzione usata per stampare i dati* statistici relativi alle richieste* di memoria superiori ai 4 KB.

Page 45: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 44

*/

function stampalotmem(){print("\n STATISTICHE PICCHI DI

RICHIESTE SOPRA I 4 KB\n")printf("-Numero totale di richieste sopra i 4 KB:

%d\n", @count(lotmem))printf("-Memoria totale richiesta sopra i 4 KB:

%d bytes\n", @sum(lotmem))printf("-Picco minimo di memoria richiesta sopra i 4 KB:

%d bytes\n", @min(lotmem))printf("-Picco massimo di memoria richiesta sopra i 4 KB:

%d bytes\n", @max(lotmem))printf("-Valor medio di memoria richiesta sopra i 4 KB:

%d bytes\n", @avg(lotmem))}

/* Funzione usata per stampare i dati* statistici relativi ai tempi tra le* richieste successive di memoria* superiori ai 4 KB.*/

function stampavartime(){print("\n STATISTICHE ISTANTI DI

RICHIESTE SOPRA I 4 KB\n")printf("-Tempo minimo tra una richiesta e l’altra:

%d us\n", @min(vartime))printf("-Tempo massimo tra una richiesta e l’altra:

%d us\n", @max(vartime))printf("-Tempo medio tra una richiesta e l’altra:

%d us\n", @avg(vartime))}

/* Funzione usata per stampare un istogramma* logaritmico concernente le richieste generali* di memoria.*/

function histlogmem(){print("\n ISTOGRAMMA LOGARITMICO RELATIVO

ALLE RICHIESTE DI MEMORIA\n")print(@hist_log(mem))

}

/* Funzione usata per stampare un istogramma* lineare concernente gli intervalli

Page 46: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 45

* intercorrenti tra le richieste di* memoria superiori a 4 KB.*/

function histlinvar(){print("\n ISTOGRAMMA LINEARE RELATIVO AGLI

INTERVALLI TRA LE RICHIESTE OVER 4 KB\n")print(@hist_linear(vartime, 1, 6, 1))

}

/* Funzione usata per stampare il tempo* effettivo di probing che dovrebbe* approssimarsi ai 10 secondi.*/

function efftime(){end = gettimeofday_ms()printf("Tempo effettivo di probing:

%d ms\n", (end-start))}

/* Funzione d’ausilio che incorpora tutte* le funzioni precedenti.*/

function statistics(){stampamem()histlogmem()stampalotmem()stampavartime()histlinvar()

}

L’obiettivo del nostro file di scripting e fondamentalmente quello di catturare le chiamatedella funzione del kernel kmalloc e mostrare i risultati elaborandoli statisticamente. Ilmonitoraggio della funzione non e ad oltranza ma ha una durata specifica di 10 secondi comeprecisato attraverso il timer all’interno del quale troviamo la chiamata di exit() che provocala terminazione del modulo. Il core del file comunque e sicuramente il probe che gestiscela chiamata di kmalloc. Si puo osservare che al suo interno, all’atto della chiamata dellafunzione, si mostrano a video alcune informazioni che riguardano il processo che esegue lachiamata. Precisamente sono stampati a video il pid e il nome del processo che invoca lafunzione, la quantita di bytes che richiede e il pid e il nome del processo padre. Onde potereoperare statisticamente il quantitativo di memoria richiesto viene accumulato nella variabilestatistica denominata mem. Ma si notera che sono definite altre variabili statistiche usate perscopi simili e precisamente:

Page 47: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 46

lotmem e usata per accumulare volta per volta le richieste di memoria che superano i 4 KBdi memoria;

lasttime e usata mer memorizzare gli istanti assoluti (in realta riferiti alla UNIX epoch) incui viene fatta una richiesta di memoria oltre i 4 KB;

vartime e usata per accumulare via via gli intervalli di tempo che intercorrono tra 2 richiestesuccessive di memoria oltre i 4 KB.

Da notare che la seconda statistica e indispensabile per poter fornire un valore alla terzasecondo la formula mostrata nello script. Sempre nel probe descritto c’e poi una sezionededicata alla gestione di una situazione eccezionale: il caso in cui la memoria totale richiestaprima che si esauriscano i 10 secondi destinati al monitoraggio superi i 15 MB. In tal casoviene prima mostrata la schermata con tutte le statistiche e poi si lancia un errore e, perquanto detto nella sezione 2.2.2, viene scaricato il modulo.

Alla fine del file ci sono poi tutte le funzioni che vengono utilizzate per stampare le infor-mazioni statistiche. Da notare che vengono usate tutte le funzioni fornite dal linguaggio, siaquelle che restituiscono un semplice valore intero (@max(statistica), @min(statistica),@sum(statistica), @avg(statistica), @count(statistica)) sia quelle che stampano unistogramma (@hist log(statistica), @hist linear(statistica, xmin, xmax, step)).L’unica funzione aggiunta e costruita ad hoc e quella che stampa il tempo effettivo di pro-bing (efftime()) basandosi sull’impiego della funzione speciale gettimeofday ms() e sullevariabili globali start (inizializzata all’atto del caricamento del modulo) e end (aggiornataquando il modulo viene scaricato dopo i 10 secondi o, quando ha piu senso15, nella gestionedella situazione eccezionale descritta in precedenza).A questo punto non resta che mandare in esecusione l’esempio attraverso il solito comandostap stapex01.stp.

Quello che verra mostrato a video e un interminabile elenco di chiamate della funzionekmalloc da parte di numerosi processi. Per motivi di spazio ne riportiamo solo una parte e

soprattutto riportiamo la sezione finale delle informazioni mostrate a video:

...Il processo 2680 (gnome-terminal) figlio di 1 (init)

ha chiesto [88] bytes di memoria!Il processo 2680 (gnome-terminal) figlio di 1 (init)

ha chiesto [296] bytes di memoria!Il processo 2680 (gnome-terminal) figlio di 1 (init)

ha chiesto [24] bytes di memoria!Il processo 2445 (X) figlio di 2430 (gdm-binary)

ha chiesto [192] bytes di memoria!Il processo 2445 (X) figlio di 2430 (gdm-binary)

ha chiesto [296] bytes di memoria!Il processo 2445 (X) figlio di 2430 (gdm-binary)

ha chiesto [192] bytes di memoria!Il processo 2680 (gnome-terminal) figlio di 1 (init)

15Il valore del tempo di probing, a meno che non si superi una richiesta totale di memoria pari a 15 MBprima dei 10 secondi, dovrebbe essere per l’appunto 10 secondi, anche se a video viene mostrato un valoreinferiore di qualche millisecondo.

Page 48: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 47

ha chiesto [5928] bytes di memoria!Il processo 2680 (gnome-terminal) figlio di 1 (init)

ha chiesto [112] bytes di memoria!Il processo 2445 (X) figlio di 2430 (gdm-binary)

ha chiesto [192] bytes di memoria!Il processo 2680 (gnome-terminal) figlio di 1 (init)

ha chiesto [112] bytes di memoria!Il processo 2680 (gnome-terminal) figlio di 1 (init)

ha chiesto [112] bytes di memoria!...

In circa 10 secondi sono stati chiesti meno di 15 MB di memoria!END PROBINGTempo effettivo di probing: 9998 ms

STATISTICHE MEMORIA RICHIESTA-Numero totale di richieste di memoria: 14946-Memoria totale richiesta: 10161440 bytes-Picco minimo di memoria richiesta: 8 bytes-Picco massimo di memoria richiesta: 5928 bytes-Valor medio di memoria richiesta: 679 bytes-Memoria media richiesta ogni secondo: 1102 KB/s

ISTOGRAMMA LOGARITMICO RELATIVO ALLE RICHIESTE DI MEMORIAvalue |-------------------------------------------------- count

2 | 04 | 08 | 2416 |@@@@@ 122232 | 11664 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10481128 |@@@@@ 1247256 |@ 218512 | 321024 | 02048 |@ 2864096 |@@@@@@ 13208192 | 016384 | 0

STATISTICHE PICCHI DI RICHIESTE SOPRA I 4 KB-Numero totale di richieste sopra i 4 KB: 1320-Memoria totale richiesta sopra i 4 KB: 7533248 bytes-Picco minimo di memoria richiesta sopra i 4 KB: 5032 bytes-Picco massimo di memoria richiesta sopra i 4 KB: 5928 bytes-Valor medio di memoria richiesta sopra i 4 KB: 5707 bytes

Page 49: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.3. Esempi Capitolo 2. KProbes e SystemTAP 48

STATISTICHE ISTANTI DI RICHIESTE SOPRA I 4 KB-Tempo minimo tra una richiesta e l’altra: 2 us-Tempo massimo tra una richiesta e l’altra: 5 us-Tempo medio tra una richiesta e l’altra: 3 us

ISTOGRAMMA LINEARE RELATIVO AGLI INTERVALLI TRA LE RICHIESTE OVER 4 KBvalue |-------------------------------------------------- count

1 | 02 |@@@ 633 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 10034 |@@@@@@@@@@@@ 2535 | 1

Il risultato mostra che in soli 10 secondi sono state fatte circa 15000 richieste di memoriaper un totale di 10 MB! Questi valori non debbono spaventare perche nello stesso tempo cisono sicuramente altri processi (anche gli stessi che hanno fatto la richiesta nei 10 secondimonitorati) che rilasciano la memoria attraverso la funzione kfree() che pero non viene mo-nitorata nel nostro esempio. Il motivo che porta a trattare come caso a parte una richiestasuperiore ai 4 KB (4096 bytes) giace nel fatto che, come si puo vedere dai risultati, c’e unarichiesta periodica di 5928 bytes fatta dal processo gnome-terminal. Da questa osservazionesi e deciso di trattare quelle richieste come un caso a parte e di capire quale sia l’intervallomedio che intercorre tra una richiesta e l’altra. I risultati ci dicono che tali richieste cadonoabbastanza periodicamente circa ogni 3 us (microsecondi) come mostrato dall’ultimo isto-gramma. E’ un valore relativamente piccolo ma non tanto perche pari a circa il 10% dellerichieste totali16.

Resta da esaminare soltanto il caso eccezionale in cui la richiesta di memoria totale risultiabbastanza alta da lanciare l’errore di “saturazione” che abbiamo definito in precedenza. Permettere in evidenza questo caso ci sono due modi: avviare durante il monitoraggio un paiodi applicazioni che richiedano grandi quantitativi di memoria o diminuire la soglia. In ognicaso il risultato sara qualcosa del genere:

STATISTICHE MEMORIA RICHIESTA-Numero totale di richieste di memoria: 12848-Memoria totale richiesta: 9729392 bytes-Picco minimo di memoria richiesta: 12 bytes-Picco massimo di memoria richiesta: 16296 bytes-Valor medio di memoria richiesta: 757 bytes-Memoria media richiesta ogni secondo: 1187 KB/s

ISTOGRAMMA LOGARITMICO RELATIVO ALLE RICHIESTE DI MEMORIAvalue |-------------------------------------------------- count

2 | 04 | 08 | 15516 |@@@@@@@@ 1379

16Precisamente pari a 1320/14946 = 0.09.

Page 50: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 49

32 | 13064 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7998128 |@@@@@@ 975256 |@@@ 508512 | 1571024 | 32048 |@ 2564096 |@@@@@@@@ 12868192 | 116384 | 032768 | 0

STATISTICHE PICCHI DI RICHIESTE SOPRA I 4 KB-Numero totale di richieste sopra i 4 KB: 1287-Memoria totale richiesta sopra i 4 KB: 7354520 bytes-Picco minimo di memoria richiesta sopra i 4 KB: 5032 bytes-Picco massimo di memoria richiesta sopra i 4 KB: 16296 bytes-Valor medio di memoria richiesta sopra i 4 KB: 5714 bytes

STATISTICHE ISTANTI DI RICHIESTE SOPRA I 4 KB-Tempo minimo tra una richiesta e l’altra: 2 us-Tempo massimo tra una richiesta e l’altra: 4 us-Tempo medio tra una richiesta e l’altra: 3 us

ISTOGRAMMA LINEARE RELATIVO AGLI INTERVALLI TRA LE RICHIESTE OVER 4 KBvalue |-------------------------------------------------- count

1 | 02 |@@@@@@ 1163 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8884 |@@@@@@@@@@@@@@@ 2835 | 0

ERROR:Punto di saturazione raggiunto dopo 8932 ms!WARNING: Number of errors: 1, skipped probes: 0

In questo caso abbiamo mostrato solo la parte finale dato che quella iniziale e molto simile.I valori comunque sono ancora in forte armonia con quelli del caso precedente. In questavariante pero abbiamo abbassato la soglia di “saturazione” da 15 MB a 9 MB circa. Comeconseguenza il modulo viene scaricato prima dei 10 secondi prestabiliti (precisamente dopo8932 millisecondi) e viene lanciato il messaggio d’errore che non c’era nel caso precedente.

2.4 Funzionamento Interno

Il funzionamento interno dell’infrastruttura di strumentazione Kprobes poggia sull’utilizzo diun insieme di meccanismi hardware della macchina sottostante. In particolar modo esso pre-suppone che l’architettura sottostante presenti tutta una serie di funzionalita per la gestionedelle interruzioni.

Page 51: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 50

Sostanzialmente le interruzioni (interrupts) sono eventi che alterano il normale flusso diesecuzione del processore. Possono essere di due tipi:

Sincrone Vengono generate dall’unita di controllo stessa quando vengono incontrate parti-colari istruzioni macchina. Vengono chiamate sincrone in quanto vengono sollevate soloal termine dell’esecuzione di un’istruzione.

Asincrone Vengono generate da dispositivi esterni, come temporizzatori e dispositivi diI/O. Vengono chiamate asincrone in quanto possono essere sollevate in qualsiasi istanterispetto al clock della CPU.

Nei manuali Intel IA32 i due tipi di interruzioni vengono rispettivamente indicati come“Eccezioni” ed “Interruzioni”; da adesso in poi anche noi utilizzeremo questa notazione.Ciascuna Interruzione o Eccezione viene identificata da un numero che puo variare da 0 a255; Intel chiama questo numero “vettore”17, e viene utilizzato per localizzare in una tabella,chiamata IDT, Interrupt Descriptor Table, l’indirizzo di un handler.

In particolare ci occuperemo delle Eccezioni sul cui meccanismo di funzionamento si basal’implementazione di Kprobes.

2.4.1 Il sottosistema di gestione delle Eccezioni Intel IA32

Le eccezioni, come visto precedentemente, sono interruzioni sincrone. Esse vengono sollevatenel caso in cui si riscontri una situazione anomala che deve essere gestita dal Kernel. Esempidi tali situazioni anomale possono essere un errore di programmazione, come una divisioneper zero, un accesso non valido ad una locazione di memoria, che genera un’eccezione disegmentation fault, oppure una richiesta esplicita di un servizio del kernel da parte del processoin esecuzione, come la chiamata di una System Call.

Il kernel, a sua volta, quando si accorge del verificarsi di un’eccezione puo gestirla in varimodi a seconda del tipo, come ad esempio inviare un segnale di SIGFPE (Floating PointError Signal) nel caso di una divisione per zero oppure svolgere una funzione richiesta nelcaso di una System Call.

Le eccezioni vengono classificate dall’architettura IA32 in due grandi categorie:

1. Eccezioni rilevate dal processore,

2. Eccezioni programmate.

Eccezioni rilevate dal processore

Vengono generate quando la CPU rileva una condizione anomala durante l’esecuzione diun’istruzione; esse vengono suddivise in tre ulteriori sottocategorie:

Faults Tali eccezioni indicano una situazione anomala che generalmente puo essere corretta;una volta corretta il processo in esecuzione puo riprendere la sua attivita senza perditadi continuita. Quando viene generata, il valore del descrittore di segmento CS18 ed il

17Questa terminologia tuttavia puo provocare incomprensione.18Code Segment.

Page 52: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 51

contenuto del registro EIP19 vengono salvati sullo stack, ed il valore CS:EIP rappresental’indirizzo dell’istruzione che ha causato il fault.

Traps Viene sollevata immediatamente dopo l’esecuzione dell’istruzione che l’ha generata;appena il kernel ne termina la gestione il processo puo riprendere il controllo senzaperdita di continuita. In tal caso il valore contenuto in CS:EIP rappresenta l’indirizzodell’istruzione che deve essere eseguita immediatamente dopo l’istruzione che ha gene-rato la trap. Generalmente questo tipo di eccezioni vengono sollevate quando non c’e lanecessita di rieseguire l’istruzione che le genera; vengono principalmente utilizzate perscopi di debug.

Aborts Indicano il verificarsi di un errore grave. Solitamente indicano il fatto che l’unita dicontrollo e nei guai e che probabilmente non e in grado di salvare la coppia CS:EIP (ossial’indirizzo dell’istruzione che ha causato l’Abort) sullo stack. Questo tipo di eccezioniviene utilizzato per indicare errori gravi come fallimenti hardware oppure valori invalidio inconsistenti nelle tabelle di sistema (IDT Interrupt Descriptor Table, GDT GlobalDescriptor Table, etc.). Al sistema operativo non rimane altro che abortire il processoche le ha generate.

Eccezioni Programmate

Vengono sollevate quando un processo ne fa esplicita richiesta attraverso le istruzioni INT,INT3, INTO e BOUND. Vengono gestite dall’unita di controllo allo stesso modo delle traps evengono impiegate principalmente per implementare System Calls o per notificare eventi didebug.

Eccezioni principali

Come gia detto in precedenza, ciascun Interruzione o Eccezione e identificata da un numerochiamato “vettore”, variabile nell’intervallo [0, 255]; questo numero viene utilizzato per indi-cizzare dei valori nella tabella IDT (Interrupt Descriptor Table) i cui elementi riportano gliindirizzi degli handler. Le prime 32 posizioni, da 0 a 31, sono fisse ed associate a particolarieccezioni (alcune sono riportate in tabella 2.1); il sistema operativo deve necessariamentefornire degli handler per queste prime 32 eccezioni. Le restanti invece sono liberamente asso-ciabili a interruzioni generate da dispositivi hardware o a eccezioni definite dai programmatoridi sistema.

Interrupt Descriptor Table (IDT)

La IDT, Interrupt Descriptor Table, e una tabella di sistema il cui scopo e di associare alnumero dell’eccezione o dell’interruzione verificatasi l’indirizzo di un handler. Questa tabellapuo trovarsi in qualunque posizione in memoria; i processori Intel dispongono, infatti, di unparticolare registro, IDTR (Interrupt Descriptor Table Register) modificabile solo in modalitasupervisore, che contiene l’indirizzo e la dimensione della IDT; esso e infatti un registro a 48bit, di cui i primi 32 rappresentano l’indirizzo base della tabella e gli ultimi 16 l’offset dellimite (come mostrato in figura 2.4).

19EIP sta per Extended Instruction Pointer, ossia rappresenta il program counter; l’indirizzo logico completodella prossima istruzione si ottiene attraverso la coppia CS:EIP.

Page 53: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 52

V Nome Tipo Descrizione0 Divide Error fault Sollevata quando un programma effettua una

divisione per zero.1 Debug fault o trap Sollevata quando il flag TF (Trace Flag) del re-

gistro EFLAGS e alto dopo l’esecuzione di ogniistruzione (utile per l’esecuzione passo–passo diun programma) oppure quando l’indirizzo dellaprossima istruzione e uguale al contenuto di unodei registri di debug (DR0 – DR3).

2 Not Used – Riservata dal sistema per le interruzioni nonmascherabili.

3 Breakpoint trap Causata dall’istruzione INT3 (solitamente inse-rita da un debugger).

4 Overflow trap Sollevata quando viene eseguita un’istruzionementre il flag OF (Overflow Flag) e alto.

5 Bound Check fault Sollevata quando un’istruzione BOUND (control-lo dei limiti di un array) viene eseguita conl’operando fuori dei limiti validi.

6 Invalid Opcode fault E’ stato incontrato un opcode non valido.12 Stack Segmentation Fault fault E’ stato sfondato il limite dello stack, oppure

il segmento descritto dal descrittore SS (StackSegment) non e presente in memoria.

14 Page Fault fault La pagina di memoria richiesta non e presen-te in memoria, oppure l’entry della Page Tablea cui e stato fatto riferimento e vuota oppuresi e verificata una violazione del meccanismo dipaging.

16 Floating Point Error fault L’unita FP integrata nel processore (o esterna seil processore e di un modello precedente al 486–DX) ha segnalato un errore (ad es. una divisioneper zero in floating point).

17 Alignment Check fault L’indirizzo di un operando non e correttamenteallineato in memoria.

18 Machine Check abort E’ stato riscontrato un problema nella CPU onel bus.

Tabella 2.1: lista dei piu importanti tra i primi 32 vettori dell’architettura IA32 e eccezioni aloro associate.

Page 54: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 53

Figura 2.4: Relazione tra il registro IDTR e la tabella IDT

Ogni entry della tabella e di 8 bytes e rappresenta un descrittore di handler; tali descrittorisi suddividono in tre categorie:

Task Gate Include il TSS (Task State Segment) del processo a cui bisogna passare il controlloquando si verifica l’interruzione o l’eccezione corrispondente.

Interrupt Gate Contiene il Segment Selector20 e l’offset nel segmento di un interrupt oexception handler; la CPU utilizza queste informazioni per saltare all’handler, ma primadisabilita il flag IF del registro EFLAGS disabilitando le interruzioni mascherabili.

Trap Gate Uguale all’Interrupt Gate ma non disabilita il flag IF.

La struttura di ogni tipo di gate e osservabile nella figura 2.5.

Gestione a livello hardware delle Eccezioni/Interruzioni

Adesso osserviamo la sequenza di passi che la CPU compie per gestire a livello hardware leinterruzioni e le eccezioni. Ogniqualvolta il processore termina l’esecuzione di un’istruzione,la coppia di registri CS:EIP contiene l’indirizzo della prossima istruzione; prima di eseguirla laCPU controlla se un’interruzione o un’eccezione si e verificata. In tal caso esegue in sequenzaqueste operazioni21:

1. Determina il vettore i associato all’interruzione/eccezione.

2. Legge la i− esima entry della IDT indirizzata dal registro IDTR.20Il Segment Selector e l’indice del descrittore di segmento contenuto nella GDT (Global Descriptor Table).21Supponendo che la CPU si trovi in Protected Mode.

Page 55: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 54

Figura 2.5: Gate Descriptors. Ogni Gate Descriptor e un entry dell’IDT.

Page 56: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 55

3. Supponendo che si tratti di una Trap Gate o di una Interrupt Gate, la CPU utilizzail Segment Selector per ricavare dalla GDT il Segment Descriptor associato. QuestoDescriptor conterra l’indirizzo base del segmento di memoria che contiene l’handlerdell’interruzione/eccezione.

4. La CPU controlla i diritti di accesso comparando il CPL (Current Privilege Level)22 delcodice che ha generato l’interruzione/eccezione con il DPL (Descriptor Privilege Level)del Segment Descriptor del segmento in cui l’handler si trova. Se DPL < CPL vienegenerata un’eccezione di “General Protection” in quanto l’handler non puo avere unlivello di privilegio minore del codice che genera l’interrupt/eccezione ad esso associato23.Infatti solo un codice con CPL ≤ DPL puo eseguire l’handler specifico. Questo passopuo essere osservato nella figura 2.6.

5. La CPU controlla se si verifica un cambiamento di privilegio, ossia se CPL 6= DPL. Intal caso la CPU deve utilizzare lo stack associato al livello di privilegio corrente. Perfar questo esegue i seguenti sottopassi:

(a) Legge il contenuto del registro TR per ottenere informazioni sul processo corrente.

(b) Carica il contenuto dei registri SS e ESP con i valori corretti associati al nuovo livellodi privilegio ottenuti tramite il contenuto del TSS associato al processo corrente.

(c) Nel nuovo stack salva il contenuto precedente dei registri SS e ESP24.

6. Salva sullo stack il contenuto dei registri EFLAGS, CS e EIP in quest’ordine.

7. Nel caso in cui l’eccezione contiene anche un codice di errore hardware, lo salva sullostack.

8. Carica CS ed EIP rispettivamente con il Segment Selector e l’Offset trovati nell’inter-rupt/exception gate. Il loro contenuto identifica l’indirizzo logico della prima istruzionedell’handler.

Svolte queste operazioni, il controllo passa all’handler che si occupera di gestire le inter-ruzioni/eccezioni via software. Terminato il proprio lavoro, l’handler invoca l’istruzione IRETche svolge una serie di operazioni hardware:

1. Carica i registri CS, EIP e EFLAGS con i valori precedentemente salvati sullo stack.

2. Controlla se il CPL del processo che deve riprendere l’esecuzione (ossia gli ultimi duebit del registro CS) sia uguale al CPL dell’handler. In tal caso IRET conclude la propriaesecuzione; altrimenti prosegue con i passi successivi.

3. Carica i registri SS e ESP con i valori salvati sullo stack; in questo modo il processopotra tornare ad utilizzare lo stack associato al suo vecchio livello di privilegio.

22Il CPL e rappresentato dagli ultimi 2 bit del registro CS.23NB: Nell’architettura Intel IA32 il valore del CPL e inversamente proporzionale al numero di privilegi

concessi; per cui CPL = 0 equivale alla modalita Kernel, mentre CPL = 3 equivale alla modalita utente.24Infatti ogni processo ha uno stack associato ad ogni livello di privilegio; nel caso di Linux ogni processo

ha uno stack utente e uno stack kernel dal momento che Linux usa solo i livelli 0 e 3.

Page 57: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 56

Figura 2.6: Interrupt Procedure Call.

4. Controlla i CPL degli altri descrittori di segmento (DS, ES, FS e GS) confrontandoli conil CPL di CS; se sono diversi cancella il contenuto del descrittore. In questo modo sievita che descrittori di segmento utilizzati dal kernel possano essere sfruttati da utentimaliziosi per creare degli exploit e accedere ad aree riservate di memoria.

Funzionalita di supporto al Debugging IA32

Nella sezione precedente abbiamo osservato come funziona il meccanismo di gestione delleeccezioni fornito dall’architettura Intel IA32. Tale meccanismo fornisce le basi di gestionedel debugging ed in questa sezione vedremo come viene sfruttato per fornire supporto aldebugging.

In pratica, il debug puo essere realizzato sollevando eccezioni in particolari punti delcodice chiamati breakpoints. Quindi un’infrastruttura per il debugging deve prevedere unmeccanismo per l’inserimento di breakpoints nel codice da strumentare, nonche degli handlerche gestiscano l’eccezione sollevata quando tali breakpoints vengono rilevati. L’architetturaIA32 prevede due meccanismi di base per l’inserimento di breakpoints.

1. Il primo consiste nell’utilizzare 8 speciali registri del processore dedicati a questo scopo:DR0 – DR7. In particolare quattro di questi sono utilizzati per contenere informazioni di

Page 58: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 57

Figura 2.7: Modifiche dello Stack dopo un chiamata ad un interrupt handler.

controllo, mentre i primi 4 vengono impiegati per contenere l’indirizzo dei breakpoints;ogniqualvolta la CPU deve eseguire un’istruzione, verifica se l’indirizzo di quest’ultimae uguale al contenuto di uno dei registri DR0 – DR4. Nel caso in cui la comparazione diaesito positivo viene sollevata l’eccezione Debug Exception (#DB, vettore 1). Ovviamente,questa tecnica ha la grossa limitazione di poter disporre esclusivamente di 4 breakpoints(questo particolare tipo di breakpoint hardware e noto con il nome di “watchpoint”).

2. Il secondo meccanismo consiste nell’“OpCode Injection”, ossia nella sostituzione del-l’opcode di un’istruzione del programma da strumentare con l’istruzione INT3 il cuiscopo e proprio quello di sollevare l’eccezione Breakpoint Exception (#BP, vettore 3).In questo modo il numero di breakpoint che e possibile inserire nel codice e illimitato,anche se il sistema di debugging deve salvare l’opcode dell’istruzione sostituita, noncheemulare l’istruzione sostituita quando il processo deve riprendere l’esecuzione.

L’architettura IA32 fornisce anche un meccanismo per l’esecuzione passo–passo di unprocesso, attraverso il flag TF del registro EFLAGS. Quando questo flag e alto, viene lanciataun’eccezione Debug Exception dopo l’esecuzione di ogni singola istruzione.

Un debugger, quindi, lavorando in collaborazione con il sistema operativo puo sfruttarequeste funzionalita per tracciare il funzionamento di un processo in esecuzione. Linux, inparticolare, fornisce la chiamata di sistema ptrace che permette di effettuare il tracing di unprocesso. Il meccanismo di base consiste in questa serie di passi:

1. Il processo tracciante, utilizzando la chiamata alla System Call ptrace, viene registratocome padre del processo tracciato.

Page 59: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 58

2. Il processo tracciante ottiene dal sistema operativo il permesso di inserire breakpointnel segmento codice del processo tracciato (infatti il sistema operativo concede la pos-sibilita di modificare la core image del processo tracciato). Quindi si ha la possibilitadi sostituire un’istruzione qualsiasi con il breakpoint INT3.

3. Quando il processore incontra l’istruzione INT3 lancia un’eccezione, che verra recuperatadall’handler do int3, (situato nel file (Kernel Tree)/arch/i386/kernel/trap.c).

4. Il Sistema Operativo blocca il processo tracciato, e invia il segnale SIGCHILD al proces-so tracciante (che recuperera il segnale con la System Call wait), che precedentementeera stato registrato come processo padre del processo tracciato.

5. Il processo tracciante puo a questo punto ottenere tutte le informazioni che desidera sulprocesso tracciato, nonche decidere come il processo tracciato debba comportarsi.

6. Se a questo punto si vuol far riprendere l’esecuzione del processo figlio sorge un proble-ma; in particolare bisogna notare che in questo momento la prossima istruzione che ilprocesso tracciato deve eseguire e stata precedentemente sostituita con un INT3, quindibisogna momentaneamente emulare l’esecuzione dell’istruzione sostituita. Per far questosi puo sfruttare il flag TF del registro EFLAGS; impostandolo su 1, il processore passerain modalita single–stepping, ossia dopo ogni singola istruzione lancera un’eccezione. Ilprocesso tracciante puo quindi impostare il flag TF su 1, sostituire l’istruzione INT3con l’istruzione precedentemente sostituita e far riprendere l’esecuzione del processotracciato.

7. Immediatamente dopo l’esecuzione dell’istruzione, il processore lancia un’eccezione cat-turata stavolta dall’handler do debug. Il sistema operativo, controllando il processoche l’ha generata, risale al processo padre (ossia il processo tracciante), inviandogli ilsegnale SIGTRAP.

8. Il processo padre puo quindi risostituire l’istruzione con il breakpoint INT3.

I passi sopra descritti sono esemplificati nelle figure da 2.8 a 2.13.

Page 60: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 59

Figura 2.8: Debugging 1: Il processo tracciante, attraverso la chiamata di sistema ptracediventa padre del processo tracciato, ottenendo il permesso di scrivere nel segmento codicedel processo figlio.

Figura 2.9: Debugging 2: Il processo tracciante inserisce il breakpoint INT3 nella posizionedesiderata, salvando l’istruzione sostituita.

Page 61: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 60

Figura 2.10: Debugging 3: Quando il flusso di controllo raggiunge INT3 il processore lancial’eccezione Breakpoint Exception catturata dall’handler do int3. L’handler blocca il processoche ha generato l’eccezione, risale al padre (nel nostro caso il processo tracciante) e gli inviail segnale SIGCHILD che puo essere catturato con una wait.

Figura 2.11: Debugging 4: Il debugger, dopo aver raccolto tutte le informazioni che desiderasul processo tracciato, ripristina momentaneamente l’istruzione sostituita ed imposta il flagTF del registro EFLAGS su 1. A questo punto lascia il controllo al processo figlio e si mette inattesa.

Page 62: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 61

Figura 2.12: Debugging 5: Poiche il flag TF e impostato su 1, il processore lancera un’eccezioneDebug Exception recuperata dall’handler do debug. Analogamente a prima l’handler bloccail processo tracciato, risale al processo tracciante inviandogli il segnale SIGTRAP. Il processotracciante capisce che il processo figlio ha eseguito l’istruzione sostituita.

Page 63: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 62

Figura 2.13: Debugging 6: il processo tracciante ripristina il breakpoint INT3, lascia ilcontrollo e si mette in attesa di un’altra eccezione Breakpoint Exception.

Page 64: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 63

Il meccanismo sopra descritto presenta ovviamente una serie di problematiche ulteriori chenon sono state approfondite. Un problema, tuttavia, che deve essere menzionato, riguarda ladimensione dell’istruzione INT3. Dal momento che le istruzioni hanno dimensione variabile,INT3 deve essere della piu piccola dimensione possibile, per evitare che nella sostituzione possaandare a sovrascrivere le istruzioni successive.

Un’altra problematica che riguarda il meccanismo descritto sopra riguarda il funzionamen-to in ambiente multiprocessore. In tal caso l’approccio di utilizzare dei breakpoint softwarecome gli INT3 rispetto ai watchpoint hardware (ossia utilizzare i registri DR0 – DR7) potreb-be comportare la perdita di breakpoint hits; questo potrebbe accadere durante il passo dimomentanea sostituzione dell’istruzione strumentata. In tal caso infatti un altro processorepotrebbe eseguire quel codice, e anziche trovare l’istruzione INT3 troverebbe l’istruzione so-stituita; questa problematica andrebbe risolta con l’utilizzo di una sezione critica, tuttaviacio esula dagli scopi della trattazione.

2.4.2 Funzionamento interno di Kprobes

Come abbiamo visto nella sezione precedente, il meccanismo di base sfruttato da un debug-ger e quello di sostituire momentaneamente un’istruzione con un breakpoint; raggiunto ilbreakpoint, il debugger e in grado di raccogliere tutte le informazioni necessarie, dopodiche,attraverso un’esecuzione passo-passo, e in grado di emulare l’istruzione sostituita.

Kprobes utilizza sostanzialmente un approccio identico per la strumentazione seppur conqualche modifica. Non e possibile, rispetto al normale processo di debugging di un’appli-cazione utente, fermare l’attivita del kernel in attesa dell’input da parte dell’utente; questoprincipalmente per il fatto che il kernel deve occuparsi di una serie di attivita che non possonoessere bloccate, tra cui la gestione delle interruzioni e dell’hardware. Per questo motivo Kpro-bes basa il proprio funzionamento sull’utilizzo di handler invocati prima e dopo l’esecuzionedell’istruzione strumentata. In secondo luogo, nel caso di Kprobe, non e possibile parlare di“processo padre” e “processo figlio”, quindi la gestione dei breakpoints non puo essere piuaffidata ad un processo tracciante e il meccanismo si complica leggermente.

Possiamo suddividere Kprobes su due livelli. Un primo livello, indipendente dall’archi-tettura, che prende il nome di “Kprobe Manager” implementato nel file (Kernel SourceTree)/kernel/kprobes.c, il cui scopo e quello di tenere traccia dei punti di strumenta-zione, occuparsi della loro registrazione/cancellazione nonche fornire un interfaccia univocaper i livelli superiori. Un secondo livello, dipendente dall’architettura, che si occupa mate-rialmente di gestire il funzionamento di base; esso e implementato nel file (Kernel SourceTree)/arch/<architettura>/kernel/kprobes.c.

Kprobe Manager

Il Kprobe Manager si occupa di tenere traccia di tutti i probing points inseriti nel kernel. Inparticolare, memorizza tutti i probing points in una tabella hash, utilizzando come valore dihash l’indirizzo del breakpoint stesso. L’accesso a questa tabella e serializzato dallo spinlockkprobe spinlock; ogni volta che si registra un kprobe, ne viene cancellato uno oppure siha un evento di kprobe hit, questo spinlock viene bloccato in maniera tale da evitare chele operazioni svolte possano essere eseguite simultaneamente in un ambiente multiprocessore(risolvendo cosı il problema descritto nella sezione 2.4.1).

Il manager e composto dalle seguenti funzioni:

Page 65: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 64

void lock kprobes(void) Blocca Kprobe e registra la CPU su cui e stato bloccato.

void unlock kprobes(void) Esegue l’operazione inversa della precedente.

struct kprobe *get kprobe(void *addr) Utilizzando l’indirizzo passato nella tabella ha-sh, riporta la struttura kprobe memorizzata associata all’indirizzo.

int register kprobe(struct kprobe *p) Funzione fondamentale. Registra il probing pointall’indirizzo desiderato, nonche memorizza la struttura passata nella tabella hash. Laregistrazione e dipendente dall’architettura e si traduce in pratica nella sostituzionedell’istruzione all’indirizzo desiderato con il breakpoint.

void unregister kprobe(struct kprobe *p) Effettua l’operazione inversa della preceden-te, ripristinando l’istruzione all’indirizzo adoperato.

Funzioni dipendenti dall’architettura

Le funzioni descritte nella sezione precedente poggiano il loro funzionamento su un insiemedi funzioni dipendenti dall’architettura implementate in(Kernel Source Tree)/arch/<architettura>/kernel/kprobes.c.

Le funzioni principali sono:

static int kprobe handler(struct pt regs *regs) Questa funzione viene invocata dal-l’handler do int3 e, al suo ingresso, blocca lo spinlock kprobe lock. La sua funzionee quella di scoprire a quale probing point appartiene l’indirizzo che ha generato l’ecce-zione INT3, quindi invocare il pre handler associato. Fatto questo invoca la funzioneprepare singlestep.

static inline void prepare singlestep(struct kprobe *p, struct pt regs *regs)Lo scopo di questa funzione e di preparare l’architettura all’emulazione dell’istruzionesostituita. Come gia spiegato nella sezione 2.4.1, il suo funzionamento consiste nellamomentanea sostituzione dell’istruzione INT3 con quella che si trovava al suo posto,memorizzata temporaneamente nel campo aisn della struttura kprobe, nonche nell’im-postare il flag TF del registro EFLAGS sul valore 1. La funzione termina riprendendol’esecuzione dell’istruzione strumentata.

static inline int post kprobe handler(struct pt regs *regs) Questa funzione vie-ne invocata dall’handler do debug dopo che si e effettuato il single stepping dell’istru-zione strumentata. Il suo scopo e quello di invocare il post handler, nonche ripristinare,invocando la funzione resume execution, la posizione del breakpoint INT3. Fatto que-sto sblocca lo spinlock kprobe lock e riaffida il controllo all’istruzione immediatamentesuccessiva a quella strumentata.

static void resume execution(struct kprobe *p, struct pt regs *regs) Questa fun-zione viene invocata immediatamente dopo l’operazione di single–stepping. Il suo scopoe quello di ripristinare il breakpoint INT3 nella posizione precedentemente specificata,nonche impostare correttamente il valore del Program Counter EIP.

static inline int kprobe fault handler(struct pt regs *regs, int trapnr) Funzio-ne invocata nel caso in cui, durante il funzionamento normale di kprobes, si verifichi

Page 66: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 65

un fault, oppure nel caso in cui il pre handler restituisca un valore diverso da 0. Il suoscopo e quello di preparare il sistema per l’invocazione del fault handler, dopodiche farsı che si possa riprendere la normale esecuzione.

Kprobes in azione

Avendo esaminato i componenti principali del sistema di strumentazione Kprobes, osservia-mone adesso il comportamento in azione.

Come abbiamo visto nella sezione relativa agli esempi, il primo passo nell’utilizzo dikprobe consiste nella registrazione di un probing point attraverso la chiamata alla funzioneregister kprobe. Questa chiamata si traduce, sostanzialmente, nell’inserimento del break-point INT3 all’indirizzo desiderato, nonche nella memorizzazione della struttura dati kprobenella tabella hash.

Quello che accade successivamente si svolge secondo i seguenti passi:

1. Il processore raggiunge il breakpoint INT3 inserito in precedenza, lanciando cosı un’ec-cezione.

2. Attraverso il riferimento nella tabella IDT, il processore invoca l’handler do int3; que-st’ultimo notifica il sistema kprobe del fatto che si e verificata l’eccezione 3, invocandola funzione kprobe handler.

3. kprobe handler verifica se l’indirizzo dell’istruzione che ha generato l’eccezione 3 eassociata ad un kprobe, effettuando una ricerca nella tabella hash. Se a tale indirizzonon e associata alcun kprobe, la funzione non fa nulla. In caso contrario invoca ilpre handler associato ed invoca la funzione prepare singlestep.

4. prepare singlestep prepara l’architettura per l’emulazione dell’istruzione sostituita;quindi sostituisce il breakpoint con l’istruzione temporaneamente salvata nel campoainsn della struttura kprobe ed imposta il flag TF su 1. Riprende quindi l’esecuzionedell’istruzione strumentata.

5. Il processore riprende l’esecuzione all’indirizzo del probing point in questione. Poiche ilflag TF e impostato su 1, dopo l’esecuzione di un’istruzione, viene lanciata l’eccezione 1.

6. L’eccezione 1 (Debug Exception) viene catturata dall’handler do debug che notificaquesto evento invocando la funzione post kprobe handler. Quest’ultimo invoca lafunzione di post handling associata, risostituisce l’istruzione all’indirizzo in questionecon INT3 invocando la funzione resume execution.

7. A questo punto il flusso di esecuzione riprende il suo normale corso.

La sequenza sopra descritta si applica al caso in cui non si verifichino problemi. Infattise si verifica un fault o la funzione di pre handling restituisce 1 viene invocata la funzione difault handling il cui scopo e dovrebbe essere quello di ripristinare le condizioni per un normalefunzionamento.

L’intero processo di funzionamento e mostrato dalla figura 2.14.

Page 67: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 66

Figura 2.14: Funzionamento di Kprobes

2.4.3 Funzionamento interno di Jprobes

Jprobes basa il proprio funzionamento sull’utilizzo dell’interfaccia di base fornita da kprobes.Tuttavia anziche permettere all’utente di definire delle proprie funzioni di pre e post handling,definisce dei propri handler a questo scopo. In questa maniera l’utente deve solo fornirel’indirizzo della funzione di strumentazione che ha la stessa lista di parametri della funzioneda strumentare. Jprobes e implementato negli stessi file in cui e implementato Kprobes:

• (Kernel Source Tree)/include/linux/kprobes.h

• (Kernel Source Tree)/kernel/kprobes.c

• (Kernel Source Tree)/arch/i386/kernel/kprobes.c

le funzioni principali che lo compongono sono:

int register jprobe(struct jprobe *jp) Funzione indipendente dall’architettura. Il suoscopo e quello di registrare la funzione di strumentazione, il cui indirizzo e memorizzatonella struttura dati di tipo jprobe. Per far questo invoca le funzioni per la registrazionedi un probing point fornite da kprobes, registrando i propri handler. Inoltre posizionaun breakpoint al posto della prima istruzione della funzione strumentata.

void unregister jprobe(struct jprobe *jp) Funzione inversa della precedente. Il suoscopo e cancellare una funzione di strumentazione ed il relativo probing point.

Page 68: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 67

int setjmp pre handler(struct kprobe *p, struct pt regs *regs) Funzione dipenden-te dall’architettura. Rappresenta l’handler sfruttato da Jprobes per implementare ilmeccanismo di funzionamento. Il suo scopo e quello di salvare lo stack frame e chiamarela funzione di strumentazione.

void jprobe return(void) Questa funzione deve essere esplicitamente richiamata dalla fun-zione di strumentazione al posto di un normale return.

int longjmp break handler(struct kprobe *p, struct pt regs *regs) Viene invocatadopo che la funzione jprobe return e stata chiamata dalla funzione di strumentazio-ne. Il suo scopo e quello di ripristinare lo stack frame permettendo che la funzionestrumentata possa essere eseguita.

Lo scopo ultimo di Jprobe e quello di trasferire il controllo ad una funzione che ha lastessa lista di parametri della funzione da strumentare; dopodiche deve restituire il controlloa quest’ultima. Il tutto avviene secondo i seguenti passi:

1. La registrazione di un jprobe consiste essenzialmente nell’inserimento di un breakpointINT3 all’entry point della funzione da strumentare. Avendo registrato il proprio handlersetjmp pre handler, quando si avra un INT3 hit, il sottosistema kprobes invochera talehandler. Questi salvera lo stack frame (che conterra quindi tutti i parametri passati allafunzione da strumentare), e salvera il contenuto del registro EIP modificandone poi ilcontenuto con l’indirizzo della funzione di strumentazione. A questo punto l’handlerrestituisce 1.

2. Restituendo 1, si comunica a Kprobes semplicemente di ritornare senza impostare ilsingle–stepping. Il controllo passa quindi alla funzione di strumentazione.

3. La funzione di strumentazione, svolto il proprio lavoro di raccolta dati, invoca la funzionejprobe return. Quest’ultima tronca l’attuale stack frame e genera un breakpoint chesara catturato dall’handler do int3; il controllo passera alla funzione kprobe handlerche si occupa di associare ad ogni probing point il proprio handler. In tal caso, tut-tavia, kprobe handler vede che a questo breakpoint non e associato alcun handler, epoiche Kprobe e attivo sulla CPU corrente comprende che e stato generato dalla fun-zione jprobe return. Per cui viene invocata la funzione longjmp break handler cheripristina lo stack frame ed il registro EIP alla situazione in cui si trovavano prima dellachiamata alla funzione di strumentazione.

4. A questo punto il sistema Kprobes imposta il single–stepping all’indirizzo dell’istruzionedove il punto di jprobing e stato impostato (l’entry point della funzione) ed i passi svoltisono esattamente quelli gia visti per kprobe.

L’intero processo di funzionamento e visibile nella figura 2.15.

2.4.4 SystemTAP, cenni sulla traduzione

Quest’ultima parte copre in maniera sintetica il meccanismo di traduzione dal linguaggiodi scripting al linguaggio C attuato da SystemTAP e che porta infine alla realizzazione delmodulo kernel che poi l’utility stpd carica e scarica opportunamente. Per meglio mostraretale meccanismo si fa riferimento ad un semplice esempio di file di script chiamato ad esempiostapex.stp e mostrato di seguito:

Page 69: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 68

Figura 2.15: Funzionamento di Jprobes

Page 70: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 69

#file di script stapex.stp

global totmem /*variabile globale che indica la quantita*progressiva e totale di memoria richiesta*/

#indichiamo all’utente che e iniziato il probing

probe begin{print("\nStart Probing...\n")delete totmem //riportiamo a zero il valore di totmem

}

#scarichiamo il modulo dopo un tempo di 1 secondo (1000 ms)

probe timer.ms(1000){exit()

}

#monitoriamo la chiamata di "__kmalloc()"

probe kernel.function("__kmalloc"){printf(" Chiesti %d bytes dal processo %d\n", $size, pid())totmem += $size //$ perche definita altrove

if (totmem >= 4000){warn(" Chiesti piu di 4000 bytes!")exit() //forziamo l’uscita

}}

#alla fine mostriamo la memoria totale richiesta

probe end{printf("Chiesti in totale %d bytes di memoria!\n", totmem)print("...end Probing\n")

}

L’obiettivo di questo file e assai semplice. Si vuole monitorare per 1 secondo il kernel e inparticolare vogliamo catturare le chiamate della funzione kmalloc(size t size, unsignedint flags) che viene invocata per chiedere size bytes di memoria con certe caratteristiche(specificate dal parametro flags ma che non ci interessano ai fini dell’esempio). Definiamoquindi la variabile globale totmem (implicitamente intera) che conterra volta per volta lasomma dei bytes richiesti fino a quel momento. Per arricchire l’esempio si nota che il moduloviene scaricato (attraverso l’esplicita invocazione della chiamata exit()) in ogni caso (cioe

Page 71: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 70

pure se non e ancora trascorso 1 secondo) se qualche processo (di cui viene mostrato il pid)richiede piu di 4000 bytes. Avviamo l’esempio con l’utility stap fornendo le opzioni di verbosee di keep onde ottenere che venga mostrato sullo schermo cio che avviene in ogni passo evengano conservati i file generati dall’utility. Digitiamo quindi il comando

stap -v -k stapex.stp

Quello che si otterra a video e qualcosa del genere:

Pass 1: parsed user script and 11 library script(s)in 160usr/0sys/186real ms.

Pass 2: analyzed script: 4 probe(s), 5 function(s), 1 global(s)in 290usr/30sys/384real ms.

Pass 3: translated to C into "/tmp/stapsJRUDw/stap_4714.c"in 130usr/30sys/260real ms.

Pass 4: compiled C into "stap_4714.ko"in 2390usr/200sys/3047real ms.

Start Probing...Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 112 bytes dal processo 2840Chiesti 88 bytes dal processo 2840WARNING: Chiesti piu di 4000 bytes!Chiesti 5928 bytes dal processo 2840Chiesti in totale 8368 bytes di memoria!...end ProbingPass 5: run completed in 10usr/20sys/1070real ms.Keeping temporary directory "/tmp/stapsJRUDw"

Page 72: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 71

Nell’esempio sono state catturate 23 chiamate da parte del processo 2840 il quale alla fine hachiesto 5928 bytes e per questo motivo il modulo e stato scaricato prima che si esaurisse iltempo di 1 secondo (dopo 20 ms per l’esattezza)25. Notiamo che grazie all’opzione di verbose(-v) vengono mostrati a video una serie di informazioni utili al nostro scopo di partenza.Soffermiamoci in particolare su queste righe:

Pass 3: translated to C into "/tmp/stapsJRUDw/stap_4714.c"in 130usr/30sys/260real ms.

Pass 4: compiled C into "stap_4714.ko"in 2390usr/200sys/3047real ms.

Keeping temporary directory "/tmp/stapsJRUDw"

Le righe ci indicano che nella directory /tmp/stapsJRDUw sono stati conservati i filegenerati dalla procedura (ma solo perche abbiamo espresso questa scelta) e in particola-re il file stap 4714.c e il relativo file oggetto stap 4714.ko. Spostandoci nella directory/tmp/stapsJRUDw e possibile notare la presenza di numerosi file:

stap_4714.c stap_4714.mod.c stap-symbols.h stap_4714.kostap_4714.o stap_4714.mod.o symbols.sorted Makefile

Ispezionando i 2 file nel cui nome e presente la parola symbol si puo facilmente osservareche essi corrispondono (a grandi linee) alla mappa di sistema cioe elencano le corrispondenzedel tipo {indirizzo di memoria} {funzione del kernel ivi allocata}. Ecco quindi un evidentepunto di incontro tra SystemTAP e kprobe. Come detto nella sezione 2.1.1 in kprobe, per regi-strare un punto di probing associato ad una funzione, bisogna conoscerne l’indirizzo. EbbeneSystemTAP, che poggia su kprobes, fa altrettanto e da qui la necessita di conoscere questecoppie di valori se effettivamente si vuole monitorare una funzione del kernel. Nell’esempio lafunzione da monitorare e kmalloc() che sara allocata all’indirizzo specificato, non diversoda quello che si trova nella mappa di sistema e cioe in /boot/System.map-VERSIONE26.I due file oggetto (.o) e il file oggetto kernel (.ko) ovviamente sono ottenuti dalla compi-lazione, attraverso il Makefile, degli altri due file .c. Il file che piu interessa per il nostroscopo e comunque quello denominato stap 4714.c. Esso contiene gran parte del risultatodella traduzione del file di scripting in linguaggio C. Poiche il file risulta abbastanza grandeci soffermiamo solo sugli aspetti piu interessanti. Innanzitutto si notano, all’inizio del file, ledefinizioni delle macro di cui si e trattato nella sezione 2.2.3:

#ifndef MAXNESTING#define MAXNESTING 10#endif#ifndef MAXSTRINGLEN#define MAXSTRINGLEN 128

25Per quanto detto nella sezione 2.2.3 in realta il modulo dovrebbe essere scaricato solo quando il numeromassimo di errori supera il valore della macro MAXERRORS. Nel nostro caso viene scaricato dopo 1 solo erroreperche di default, come si vedra piu avanti, la macro assume valore 0 quindi e sufficiente un errore per provocarela terminazione del modulo.

26Va precisato che SystemTAP non fa un accesso diretto alla mappa di sistema specificata ma, come giaprecisato, sfrutta le informazioni di debug che gli consentono di ricostruirla nonche di accedere ad informazionimolto piu dettagliate.

Page 73: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 72

#endif#ifndef MAXACTION#define MAXACTION 1000#endif#ifndef MAXTRYLOCK#define MAXTRYLOCK MAXACTION#endif#ifndef TRYLOCKDELAY#define TRYLOCKDELAY 100#endif#ifndef MAXMAPENTRIES#define MAXMAPENTRIES 2048#endif#ifndef MAXERRORS#define MAXERRORS 0#endif#ifndef MAXSKIPPED#define MAXSKIPPED 100

Quelli riportati sono i valori di default ma, volendo, il programmatore potrebbe ridefinirele macro a suo piacimento. Preseguendo nel file si incontra un’interessante struttura chiamatacontext usata per rappresentare appunto il contesto del processore; non a caso essa contieneun puntatore al valore dei registri (struct pt regs *regs;), un puntatore all’ultimo errore(const char *last error;), uno all’ultimo statement (const char *last stmt;) e con-tiene un intero positivo chiamato actioncount che viene usato per tenere traccia, volta pervolta, del numero di statements eseguiti (che come detto nella sezione 2.2.3 non deve superareil valore MAXACTION).

struct context {atomic_t busy;const char *probe_point;unsigned actioncount;unsigned nesting;const char *last_error;const char *last_stmt;struct pt_regs *regs;union {... //continua

Ma il campo piu interessante della struttura e quello di tipo union che viene usato perconservare le variabili locali dei vari probe definiti nel file di script. Per questo motivo essocontiene quattro strutture, una per ogni probe inserito e ciascuna definisce solo le variabilinecessarie al probe in questione. La numerazione dei probe parte da 0 quindi ad esempio ilprobe numero 1 e quello relativo al timer e poiche non abbiamo usato al suo interno alcunavariabile nemmeno nella struttura in questione troviamo alcunche:

struct probe_1_locals{

Page 74: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 73

union{struct{};

};}probe_1;

Consideriamo invece la struttura relativa al probe numero 2 cioe quello che cattura la chiamatadella funzione kmalloc():

struct probe_2_locals{union{

struct{int64_t __tmp0;int64_t __tmp1;int64_t __tmp2;

};struct{

int64_t __tmp3;int64_t __tmp4;

};struct{

union{struct{

string_t __tmp5;};struct{};

};};

};}probe_2;

In questo caso invece sono definite delle variabili, stringhe e interi, proprio perche il probedefinito nel file di script usa non solo la variabile totmem (che in questo file e definita piuavanti) ma anche la variabile $size , il pid del processo e poi la stringa del messaggio quindie abbastanza normale che la struttura venga tradotta in tal modo. Il discorso puo essere fattoanche per gli altri probe, ma e piu utile analizzare a questo punto direttamente le funzionidefinite di seguito. Scorrendo il file e possibile incontrare la dichiarazione delle varie funzioniche nella sezione 2.2.2 abbiamo chiamato speciali. Come campione analizziamo la definizionedi warn():

void function_warn (struct context* __restrict__ c) {struct function_warn_locals * __restrict__ l =

& c->locals[c->nesting].function_warn;(void) l;#define CONTEXT c#define THIS l

Page 75: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 74

if (0) goto out;if (unlikely (c->last_error)) goto out;c->last_stmt = "embedded-code at /usr/share/systemtap/tapset/logging.stp:14:28";c->actioncount += 1;if (unlikely (c->actioncount > MAXACTION)) {

c->last_error = "MAXACTION exceeded";goto out;

}{

_stp_warn ("%s", THIS->msg);

}out:

;#undef CONTEXT#undef THIS

}

Il suo comportamento e abbastanza semplice. Essa riceve in ingresso un puntatore al contesto(parametro di ingresso-uscita) e opera sui suoi campi opportunamente. Ad esempio se nonsi e verificato un errore viene incrementata la variabile che tiene memoria del numero distatement eseguiti e dopo aver verificato che questa non abbia superato il valore massimodefinito dalla macro MAXACTION non fa altro che costruire la stringa che costituisce il messaggiodi warning richiamando una funzione ( stp warm) predefinita all’interno del sistema. Nientedi piu semplice. Da questo punto in poi troviamo tutte le funzioni che vengono utilizzateper i probe point inseriti. Si noteranno quindi 4 funzioni del tipo void probe X (structcontext * restrict c) {...} dove X e il numero del probe. Ad esempio se ci riferiamoal probe piu importante, cioe il numero 2, ossia quello che gestisce la chiamata della funzionekmalloc(), e interessante vedere come siano state tradotte le istruzioni specificate nel file

di scripting. Riportiamone quindi uno stralcio:

if ((((global_totmem) >= (((int64_t)4000LL))))) {{

if (unlikely (c->last_error)) goto out;c->last_stmt = "operator ’{’ at stapex.stp:15:21";if (unlikely (c->last_error)) goto out;c->last_stmt = "identifier ’warn’ at stapex.stp:16:3";c->actioncount += 1;if (unlikely (c->actioncount > MAXACTION)) {c->last_error = "MAXACTION exceeded";goto out;

}(void)({

c->last_stmt = "string ’ Chiesti piu di 4000 bytes!’ at stapex.stp:16:8";

Page 76: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 75

strlcpy (l->__tmp5, " Chiesti piu di 4000 bytes!", MAXSTRINGLEN);

if (unlikely (c->nesting+2 >= MAXNESTING)) {c->last_error = "MAXNESTING exceeded";c->last_stmt = "identifier ’warn’ at stapex.stp:16:3";

} else if (likely (! c->last_error)) {strlcpy (c->locals[c->nesting+1].function_warn.msg, l->__tmp5, MAXSTRINGLEN);c->nesting ++;function_warn (c);c->nesting --;if (c->last_error && ! c->last_error[0])c->last_error = 0;

}(void) 0;

});

Il frammento riportato corrisponde alle seguenti righe del file di scripting:

if (totmem >= 4000){warn(" Chiesti piu di 4000 bytes!")exit()

}

Ovviamente l’esplosione di queste tre righe in un insieme molto piu lungo di istruzioni edovuta soprattutto a tutti i controlli collaterali che debbono essere necessariamente fatti alivello C ma che risultano comletamente nascosti all’utente che usa direttamente l’interfacciadi SystemTAP attraverso il linguaggio di scripting27.

Verso la fine del file e possibile incontrare quelle funzioni che sicuramente ci interessanodi piu per quanto riguarda il funzionamento interno di SystemTAP. Abbiamo detto che l’in-terfaccia poggia su kprobe quindi non possono mancare le implementazioni delle funzioni diregistrazione dei probe point presenti per l’appunto anche in kprobe. Facendo riferimento alprobe numero 2 e possibile osservare le seguenti righe:

noinline int register_probe_2 (void) {int rc = 0;const char *probe_point = "kernel.function(\"__kmalloc@mm/slab.c:2961\")";{

int i;for (i = 0; i < 1; i++) {

dwarf_kprobe_2[i].pre_handler = &dwarf_kprobe_2_enter;rc = rc || register_kprobe (&(dwarf_kprobe_2[i]));if (unlikely (rc)) {

probe_point = dwarf_kprobe_2_location_names[i];break;

}

27Da notare che viene fatto un largo uso della parola unlikely() la quale esprime che molto probabilmentel’espressione valutata sara falsa. Il suo uso, nel caso di previsione azzeccata, porta ad una ottimizzazione delcodice e viceversa se la previsione dovesse essere sbagliata.

Page 77: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 76

}if (unlikely (rc)) while (--i >= 0)

unregister_kprobe (&(dwarf_kprobe_2[i]));}if (unlikely (rc)) {

atomic_set (&session_state, STAP_SESSION_ERROR);_stp_error ("probe 2 registration failed, rc=%d, %s\n", rc, probe_point);

}return rc;

}

La terza riga precisa in maniera estesa quale e il punto preciso da probare. Nel file discripting in realta non era stato precisato ne il sorgente ne la riga a cui posizionare il probepoint ma solo la funzione. Ma in fin dei conti cio equivaleva a scrivere

kernel.function(\"__kmalloc@mm/slab.c:2961\")

e quindi ecco la presenza di questa riga stessa. Inoltre per ogni punto da probare bisognavaspecificare un handler (in realta almeno tre: pre–handler, post–handler e fault–handler).Ebbene questa operazione viene fatta dalla riga

dwarf_kprobe_2[i].pre_handler = &dwarf_kprobe_2_enter;

che registra il pre–handler del probe point. Precisamente il pre–handler viene definito piuavanti e comincia da questo punto:

static intdwarf_kprobe_2_enter (struct kprobe *probe_instance,

struct pt_regs *regs) {...

L’aspetto della funzione e perfettamente identico a quello gia visto in kprobe nella sezione2.1.1. Anche il fault–handler e simile:

int stap_kprobe_fault_handler (struct kprobe* kp,struct pt_regs* regs, int trapnr) {

con la differenza che il fault–handler e lo stesso per tutti i probe. Resta solo da capiredove effettuare la registrazione dei gestori. Niente di piu ovvio: SystemTAP, appoggiandosia kprobe, non fa altro che realizzare un modulo di monitoraggio e quindi, per come sonorealizzati i moduli del kernel, la registrazione va eseguita nella funzione di init() del modulostesso e la deregistrazione in quella di exit() come mostrato dalle seguenti righe che si trovanogiusto in fondo al file:

int systemtap_module_init (void) {int rc = 0;const char *probe_point = "";atomic_set (&session_state, STAP_SESSION_STARTING);if (sizeof (struct context) <= 131072)

contexts = alloc_percpu (struct context);

Page 78: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 77

if (contexts == NULL) {_stp_error ("percpu context (size %lu) allocation failed",

sizeof (struct context));rc = -ENOMEM;goto out;

}global_totmem = 0;rwlock_init (& global_totmem_lock);rc = register_probe_0();if (rc)

goto out;rc = register_probe_1();if (rc)

goto unregister_0;rc = register_probe_2();if (rc)

goto unregister_1;rc = register_probe_3();if (rc)

goto unregister_2;if (atomic_read (&session_state) == STAP_SESSION_STARTING)

atomic_set (&session_state, STAP_SESSION_RUNNING);goto out;

unregister_2:unregister_probe_2();

unregister_1:unregister_probe_1();

unregister_0:unregister_probe_0();

out:return rc;

}

void systemtap_module_exit (void) {int holdon;if (atomic_read (&session_state) == STAP_SESSION_STARTING)

return;if (atomic_read (&session_state) == STAP_SESSION_RUNNING)

atomic_set (&session_state, STAP_SESSION_STOPPING);do {

int i;holdon = 0;for (i=0; i < NR_CPUS; i++)

if (cpu_possible (i) && atomic_read

Page 79: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

2.4. Funzionamento Interno Capitolo 2. KProbes e SystemTAP 78

(& ((struct context *)per_cpu_ptr(contexts, i))->busy))holdon = 1;} while (holdon);

unregister_probe_3();unregister_probe_2();unregister_probe_1();unregister_probe_0();free_percpu (contexts);if (atomic_read (& skipped_count) || atomic_read (& error_count))

_stp_warn ("Number of errors: %d, skipped probes: %d\n",(int) atomic_read (& error_count), (int) atomic_read (& skipped_count));}

Page 80: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Capitolo 3

Caso di studio

Nel capitolo precedente sono state esaminate le caratteristiche e le potenzialita del frameworkdi strumentazione KProbes/SystemTAP; nel lavoro di tirocinio svolto sono stati analizzatianche altri tool di probing del kernel, in particolare l’interesse e ricaduto sul tool DSKI. Quellodi cui ci vogliamo occupare in questo capitolo e innanzitutto di confrontare a priori i tool, nelsenso di effettuarne un confronto a partire dalle caratteristiche di base, dopodiche impiegarliin un esperimento pratico ed analizzarne i risultati, evidenziando cosı i vantaggi e gli svantaggidell’impiego di ciascuno strumento. Per avere un’analisi approfondita del framework DSKIfare riferimento a [1].

3.1 Confronto DSKI – KProbes/SystemTAP

DSKI fornisce uno strumento di probing totalmente indipendente dall’architettura della mac-china sottostante, quindi si tratta di un framework di alto livello; utilizzando congiuntamenteun dispositivo a caratteri virtuale ed un demone eseguito in background e in grado di repe-rire informazioni sui meccanismi interni del kernel. KProbes/SystemTAP, dall’altra parte,sfrutta un approccio di basso livello, adoperando le debugging facilities fornite dall’architet-tura sottostante, per fornire uno strumento di probing dinamico. Entrambi gli approcci deidue framework hanno dei pro e dei contro; lo scopo che ci prefiggiamo in questa sede e diconfrontarli sulla base delle loro caratteristiche fondamentali, quindi una sorta di confronto apriori. In particolare, sebbene KProbes/SystemTAP possano essere considerati come un uni-co strumento, in questa sede li considereremo come tool separati, in quanto KProbes e unostrumento di basso livello che dipende dall’architettura, SystemTAP invece poggia su KPro-bes e fornisce funzionalita di alto livello per cui puo essere adoperato alla stessa maniera suarchitetture differenti purche sia fornito lo strato di basso livello, KProbes, per l’architetturain questione.

Di seguito sono riportate le considerazioni per i vari tool secondo varie basi di confronto:

Procedimento di strumentazione

• KProbes/JProbes L’inserimento di punti di strumentazione comporta sia la cono-scenza del linguaggio C, sia la capacita di creare moduli del kernel.

• SystemTAP Non e necessaria alcuna conoscenza del linguaggio C o capacita di crearemoduli. E’ necessaria pero la conoscenza del linguaggio di scripting.

79

Page 81: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.1. Confronto Capitolo 3. Caso di studio 80

• DSKI E’ necessaria una parziale conoscenza del C. Procedimento di strumentazionesupportato da utility grafiche.

Dipendenza dall’architettura

• KProbes/JProbes KProbes e Jprobes dipendono altamente dall’architettura sotto-stante. In particolar modo sfruttano le funzionalita fornite dall’architettura per lagestione degli interrupt nonche per il supporto del debugging. Tuttavia fornisconoun’interfaccia univoca a livello di linguaggio C.

• SystemTAP Completamente indipendente dall’architettura a livello del linguaggio discripting, anche se basa le proprie funzionalita sull’utilizzo di KProbes e JProbes.

• DSKI Completamente indipendente dall’architettura. Infatti fa utilizzo esclusivamen-te di funzionalita di alto livello fornite dal kernel (in particolar modo del filesystemvirtuale).

Inserimento di Breakpoints

• KProbes/JProbes Presuppone la conoscenza esatta dell’indirizzo del punto da stru-mentare (entry point di funzione o istruzione singola). Ovviamente tale informazionevaria a seconda dell’immagine binaria del kernel.

• SystemTAP Non presuppone la conoscenza esatta di un indirizzo perche si basa sulleinformazioni simboliche di debug fornite dal processo di compilazione del kernel.

• DSKI Presuppone l’inserimento diretto nel codice sorgente dei punti di strumentazione.

Postprocessing

• KProbes/JProbes Non fornisce alcun supporto al postprocessing dei dati di strumen-tazione. Il tutto e a cura dell’utente.

• SystemTAP Fornisce uno scarso supporto al trattamento dei dati raccolti permettendoesclusivamente di tracciare istogrammi realizzati in modo elementare.

• DSKI Fornisce un supporto molto completo al trattamento dei dati grazie alla suiteKUSP che permette di effettuare elaborazioni sequenziali sui dati, permettendo filtraggioe formattazione grafica degli stessi. Inoltre permette l’estensione dei meccanismi dipostprocessing attraverso l’impiego del linguaggio Python.

Agilita d’uso

• KProbes/JProbes Fornisce un’agilita d’uso medio-elevata, dal momento che non ri-chiede ne la compilazione del kernel (in quanto e in grado di strumentare dinamicamentel’immagine binaria del kernel) ne le informazioni simboliche di debug (in quanto nonstrettamente necessarie). L’utente dovra, tuttavia, costruire moduli che andranno op-portunamente caricati e scaricati nonche registrare e cancellare esplicitamente nel codicedel modulo i punti di strumentazione e fornire delle opportune funzioni di handling.

Page 82: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.1. Confronto Capitolo 3. Caso di studio 81

• SystemTAP Fornisce un’agilita alta, in quanto, basando il proprio funzionamento suKProbes e Jprobe, e necessario fornire esclusivamente il file di scripting che descrive leoperazioni da effettuare nel momento in cui il flusso di controllo attraversa i breakpoint.Tutte le problematiche sono nascoste dall’utility stap che si occupa della traduzionedello script, nonche della creazione di un modulo di probing che provvedera automa-ticamente a caricare e scaricare. Quindi non e necessario ricompilare il kernel, anchese sono necessarie comunque le informazioni simboliche di debug che aumentano ladimensione finale dell’immagine binaria del kernel stesso.

• DSKI Sebbene fornisca un supporto molto avanzato al postprocessing, la sua agilitad’uso non e molto elevata. Infatti presuppone, per l’inserimento dei breakpoints, lamodifica del codice sorgente stesso (che potrebbe tradursi in effetti collaterali impredi-cibili), nonche la ricompilazione del kernel stesso ogni volta che risulti necessario inserireun nuovo breakpoint o eliminarne uno.

Risoluzione di probing

• KProbes/JProbes Fornisce una risoluzione di probing limitata all’entry point di unafunzione.

• SystemTAP La risoluzione di probing e illimitata. Grazie alle informazioni di debugessa puo arrivare perfino alla singola riga di un file sorgente.

• DSKI C’e una risoluzione molto elevata, anche in questo caso e possibile monitorareun qualunque punto del codice sorgente (ammesso che faccia parte di una funzione).

Visibilita dei dati

• KProbes/JProbes KProbes non e in grado di fare assunzioni sulle variabili localie sui parametri passati ad una funzione quindi non e in grado di reperire tali dati(tuttavia con una conoscenza di basso livello ed impiegando il linguaggio assembly epossibile ricavare tali informazioni). Jprobes e in grado di strumentare l’entry point dellefunzioni, potendo interpretare i parametri ad esse passati; non e in grado, comunque,di strumentare le variabili locali.

• SystemTAP Considerando che SystemTAP fa uso delle informazioni di debug delkernel, e in grado di accedere a qualunque variabile o struttura dati.

• DSKI E in grado di accedere al contenuto delle variabili locali di cui bisogna specificarela dimensione e l’indirizzo nel momento in cui si inserisce un breakpoint.

Supporto

• KProbes/JProbes Essendo parte integrante del kernel dalla versione 2.6 e facilereperire documenti ufficiali e notizie relative al tool.

• SystemTAP Esso e stato sviluppato da un gruppo di societa e non e integrato nelkernel standard. Non e difficile comunque ritovare informazioni sul tool ma esso eancora in fase sperimentale.

Page 83: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.2. Workloads Capitolo 3. Caso di studio 82

• DSKI Non e integrato nel kernel standard ed e stato sviluppato alla Kansas Univer-sity. Fatta eccezione per pochi documenti inclusi nella suite KUSP e difficile trovareinformazioni a riguardo; inoltre anche DSKI e in fase sperimentale e presenta ancoraqualche evidente problema riguardo alla perdita di eventi.

3.2 Workloads

Abbiamo confrontato nella sezione precedente i due tool di probing analizzati nel corso dellavoro di tirocinio. Adesso vogliamo impiegare i due tool in un caso reale ossia utilizzarliper ottenere dati quantitativi che permettano di analizzare il comportamento del kernel delsistema operativo, o di un suo sottosistema, in presenza di un determinato stimolo in ingresso.In questa sede, oltre ai risultati numerici, quello che risulta essere di particolare importanza el’approccio metodologico adoperato vale a dire l’analisi del comportamento del kernel sotto-posto ad uno stress scelto a priori e quale sia la validita, nonche i limiti di questa tecnica. Insostanza, non potendo prevedere a priori la situazione in cui il sistema andra ad operare, sisimula un carico tipico per lo stesso, per cercare di diagnosticare situazioni anomale e effetticollaterali imprevisti in fase di progettazione. Il problema e che bisognerebbe stabilire, datal’enorme eterogeneita dei workload a cui un sistema puo essere sottoposto, quale sia il wor-kload ideale, ossia che copra tutti i possibili carichi presentabili; per tal motivo l’approccioadottato e stato quello di suddividere i workload esistenti in tre classi: CPU, I/O e MEMORYbound cosı definiti:

CPU bound Questa situazione si riferisce ad una condizione in cui il tempo per completareuna computazione e determinato principalmente dalla velocita dell’Unita Centrale. Ciosignifica che la computazione mantiene l’utilizzo del processore molto alto e che quest’ul-timo non sta spendendo molto tempo in attesa di interrupt come nel caso in cui si debbaattendere la terminazione di un’operazione di IO. In tal caso un programma che e CPUbound puo aumentare le proprie prestazioni soltanto se viene impiegato un algoritmomigliore oppure se si utilizza un processore con una velocita di calcolo superiore.

I/O bound In tal caso ci si riferisce ad una condizione in cui il tempo per completare unacomputazione e determinato principalmente dagli intervalli di tempo spesi in attesa chele operazioni di IO vengano completate. Esempi di questo tipo sono processi che devonoleggere/scrivere dati dal disco o da una socket; in tal caso le prestazioni dipendono dasvariati fattori (tempo di accesso al disco, algoritmo di scheduling del disco etc.) e nonesistono soluzioni generalmente valide per eliminare il problema dal momento che unprocesso non puo intervenire su tali fattori.

MEMORY bound In questo caso ci si riferisce ad una situazione in cui i fattori primariche limitano la velocita e il tempo di esecuzione di un processo sono principalmentela velocita di accesso alla memoria e la quantita a disposizione. Per questo motivoquando la CPU deve elaborare grandi quantita di dati, avendo un limite sulla capacitadella memoria e sulla sua velocita, vengono eseguite molte operazioni di swapping suldisco, per cui il tempo di esecuzione viene limitato da questi tempi morti in cui non vie lavoro utile. Per migliorare le prestazioni in tali situazioni bisogna intervenire nelletecniche che il processo utilizza nel gestire i propri dati, come ad esempio accesso aidati di una matrice memorizzata per righe su di un’architettura che usa la paginazione;

Page 84: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.2. Workloads Capitolo 3. Caso di studio 83

generalmente intervengono molti fattori non controllabili dal processo come la latenzadi accesso alla memoria o al disco, oppure l’algoritmo di gestione della memoria delsistema operativo.

A partire dai risultati ottenuti stressando il kernel con questi carichi si e cercato di stabilirese l’esperimento fosse ripetibile, ossia se possedesse caratteristiche di stazionarieta; in tal casosi potrebbe costruire un workload come fusione dei tre presentati sopra. Naturalmente unapproccio alternativo sarebbe quello di utilizzare un carico dalle caratteristiche completamentecasuali che, non rientrando in degli schemi prefissati, puo in qualche modo permettere discovare rapporti causa–effetto impredicibili e di intervenire su di essi per migliorare la stabilitadel sistema.

In particolare i workload adoperati sono stati UnixBench per il caso CPU bound eIOzone per il caso IO bound. Per quanto riguarda invece il caso MEMORY bound abbiamooptato per la realizzazione di un workload appositamente creato per la macchina su cui sonostati effettuati i test.

3.2.1 UnixBench

UnixBench e una suite di benchmarks modulari che e possibile combinare tra di loro a secondadelle esigenze; tali moduli sono raggruppati in gruppi logici definiti come di seguito:

arithmetic insieme di benchmark aritmetici che simulano il comportamento di applicazioniscientifiche tipiche; in particolare sono forniti il benchmark di Whetstone per il calcolodelle prestazioni delle operazioni in virgola mobile del processore, nonche una serie diworkload per ogni tipo di dato numerico (int, long, double etc.).

system insieme di benchmark per testare l’overhead delle operazioni di sistema (overhead dichiamata a system call, pipe throughput, overhead di creazione processi etc.).

misc insieme di benchmark che simulano il comportamento di applicazioni non numerichecome ad esempio compilazione C, chiamate ricorsive e operazioni su stinghe (simulandocosı il comportamento di compilatori, editor testuali etc.).

Dal momento che UnixBench e stato impiegato per generare un carico di tipo CPU bound estato scelto il modulo arithmetic. Tra i vari sottomoduli l’attenzione e ricaduta precisamentesui moduli Whetstone e Dhrystone descritti di seguito.

Whetstone e Dhrystone

Il benchmark Whetstone nasce con lo scopo di misurare le performance di calcolo floatingpoint di un processore; esso cerca di fornire una valutazione quantitativa della velocita dicalcolo della macchina in termini di KWIPS, (KiloWhetstone Per Seconds, ossia migliaiadi cicli Whetstone per secondo) mentre alcune versioni piu avanzate autocalibranti offronorisultati in termini di MOPS (Millions of OPerations per Seconds). Le caratteristiche che locontraddistinguono sono:

1. contiene un’alta percentuale di dati e istruzioni floating point;

2. circa il 50% dell’esecuzione e spesa in funzioni matematiche li libreria (sin(), cos(),tan() etc.);

Page 85: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.2. Workloads Capitolo 3. Caso di studio 84

3. i cilci impiegati sono molto brevi in tal modo processori dotati di un Instruction cachevedono aumentare le loro prestazioni significativamente;

4. i dati sono globali, in maniera tale che i processori RISC non possano avvantaggiarsidella presenza di un maggiore numero di registri general purpose per la gestione divariabili locali.

Il benchmark Dhrystone sfrutta la stessa idea di base del benchmark Whetstone1, cercandopero di stimare le prestazioni del processore in presenza di carichi che eseguono computazioninon numeriche. La sua attenzione e rivolta soprattutto ad operazioni intere o su stringhe,cercando di simulare il carico tipico fornito da applicazioni come word processors, compilatorietc. Esso e progettato in maniera tale da poter confrontare anche l’output generato da piucompilatori per la stessa macchina, potendo cosı confrontare le ottimizzazioni introdotte infase di compilazione da ciascuno di essi. Le sue caratteristiche fondamentali sono di seguitoelencate:

1. non contiene alcuna operazione floating point;

2. una percentuale considerabile del tempo di esecuzione e speso su operazioni che lavoranosu stringhe;

3. i cicli impiegati non sono, come in Whetstone, molto brevi ma studiati in maniera taleda generare cache miss. In questo modo vengono stimate le performance con cui ilprocessore gestisce il codice e i dati, oppure come il compilatore riesce ad ottimizzare ilcodice;

4. c’e solo una piccola percentuale di variabili globali, cosı i processori RISC ottengonoun notevole miglioramento delle prestazioni dal momento che gestiscono in modo piuefficiente i dati locali (a differenza di prima).

3.2.2 IOzone

IOzone e un insieme di benchmark per calcolare le prestazioni del sottosistema di gestione diIO di Linux. In particolare esso e utile per effettuare analisi su una vasta gamma di operazionitipiche del filesystem tra cui:

write tale test misura le performance di scrittura di un nuovo file. Quando un nuovo fileviene scritto necessitano di essere memorizzati non solo i dati ma anche le informazioniaggiuntive per tenere traccia di dove gli stessi siano locati sul supporto. Queste infor-mazioni aggiuntive sono chiamate metadati e consistono di informazioni di directory, dispazio allocato e altri dati associabili al file ma che non fanno parte del suo contenuto. Enormale quindi che le performance di una write iniziale siano piu basse di una re–writeproprio a causa di questo overhead.

re–write questo test misura le performance di scrittura su di un file gia esistente. Quandosi scrive su un file pre–esistente il lavoro richiesto e minore dal momento che i metadatisono gia presenti. E normale che le performance in tal caso migliorino rispetto al casodescritto prima.

1Il nome stesso deriva da un gioco di parole basato sul nome del benchmark Whetstone.

Page 86: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.2. Workloads Capitolo 3. Caso di studio 85

read questo test misura le performance di lettura di un file.

re–read tale test misura le performance di lettura di un file recentemente letto. Solitamentele prestazioni sono migliori rispetto al caso precedente dal momento che spesso il sistemaoperativo mantiene una cache dei dati recentemente letti.

random read questo test misura le performance di accesso casuale in lettura ad un file. Leperformance in tal caso dipendono da svariati fattori come la dimensione della cachedel sistema operativo, la latenza di seek etc.

random write questo test misura le performance di accesso casuale in scrittura ad un file.

backwards read questo test misura le performance nel leggere un file all’indietro. Nono-stante vi siano molti sistemi operativi che hanno delle caratteristiche speciali che con-sentono di leggere un file in avanti molto rapidamente, vi sono pochi sistemi operativiche riconoscono e migliorano le prestazioni di una lettura di un file all’indietro.

mmap molti sistemi operativi supportano l’uso della mmap() per mappare un file nello spazioindirizzi dell’utente. Una volta eseguita la mappatura una modifica di un dato in questaarea di memoria si traduce in una modifica sul file. Questo e utile se l’applicazionedesidera utilizzare un file come segmenti di memoria. La coerenza tra i dati contenutiin memoria e quelli memorizzati sul disco puo essere gestita in maniera sincrona oasincrona e scopo del benchmark e di calcolare le performance di questo meccanismo.

3.2.3 Workload MEMORY bound

Per quanto riguarda il caso MEMORY bound si e scelto di realizzare un workload su misuraper la macchina dell’esperimento; dal momento che il nostro scopo e stressare il sottosistemadi gestione della memoria del sistema operativo si e realizzata un’applicazione che richiedememoria ad oltranza finche il sistema operativo non e costretto ad impiegare l’area di swapquindi si rilascia la memoria. Tale operazione viene eseguita ciclicamente e di seguito siriporta l’implementazione del workload:

#include <stdio.h>#include <stdlib.h>

int main() {printf("Programma Memory Bound\n");

int *mem_area[560000];int allocated;int failed;int numofcycles;numofcycles = 0;int i;int j, k;

for(;;) {// Fase di allocazione

Page 87: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.3. Scopo degli esperimenti Capitolo 3. Caso di studio 86

printf("Allocazione in corso\n");allocated = 0;failed = 0;while((allocated < 560000) && (failed == 0)) {

mem_area[allocated] = (int *) malloc(sizeof(int) * 1024);if(mem_area[allocated] == NULL) {

failed = 1;printf("Fallita un’allocazione\n");

} else {allocated++;

}}

//Ciclo di pausafor(j = 0; j < 4000000; j++)

for(k = 0; k < 40; k++);

// Fase di deallocazioneprintf("Deallocazione in corso\n");for(i = allocated; i == -1; i--) {

free(mem_area[i]);}

}}

Come si puo notare, il workload e abbastanza sintetico e lineare. Esso opera in due fasi

• nella prima fase il programma richiede al sistema operativo, attraverso la funzione dilibreria C malloc()2, un quantitativo di memoria pari a 2.1 GB (560000 * 32 * 1024bit). Considerando che la macchina stressata possiede 2 GB di memoria fisica, cio vuoldire che il sistema operativo comincera ad usare la memoria di swap;

• nella seconda fase l’applicazione libera totalmente la memoria allocata e tutto ricomin-cia.

L’ultima cosa da notare e che tra l’allocazione e la deallocazione e previsto un ciclo dipausa per ridurre la frequenza delle richieste di memoria e dare all’utente la possibilita diaccorgersi delle richieste fatte3.

3.3 Scopo degli esperimenti

Nelle sezioni precedenti ci siamo proposti di adoperare dei particolari workloads per stressareil kernel del sistema operativo. A grandi linee lo scopo degli esperimenti e quello di stabilirel’affidabilita del kernel linux impiegato. E noto che un kernel offre i suoi servizi attraverso

2Si ricordi che la malloc() alla fine si traduce nella chiamata alla system call brk().3Si noti che la pausa non viene realizzata con la chiamata a system call sleep() onde evitare di inquinare

i risultati sperimentali.

Page 88: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.3. Scopo degli esperimenti Capitolo 3. Caso di studio 87

le SVC (SuperVisor Call) dunque la sua affidabilita e determinata direttamente dalla misurain cui le SVC falliscono ovvero la misura secondo cui la SVC, stimolata opportunamente,soddisfa il comportamento atteso. Benche l’esperimento non si spinga fino a questo punto ipassi preliminari risultano grossomodo i seguenti:

• isolare le system call piu critiche (cioe quelle stimolate maggiormente);

• individuare come le SVC rispondono a sollecitazioni di un workload, ovvero ad unprogramma che simula il comportamento di uno corretto.

E percio utile osservare la frequenza con cui le SVC vengono chiamate a seconda delworkload applicato (I/O bound, CPU bound, MEMORY bound) nonche l’esito della chiamata(che dipende ovviamente dalla semantica della system call). Quest’ultima informazione puoessere utilizzata per diagnosticare eventuali problemi di stabilita e intervenire di conseguenzain modo mirato.

Il primo passo in questa direzione consiste nel capire come il S.O. gestisce le system call, inmaniera tale da trovare la modalita ottima con cui utilizzare i due tool studiati. Nello specificovediamo come le chiamate di sistema vengono gestite da un kernel Linux su piattaforma x86.

3.3.1 Sottosistema di gestione delle System Call in Linux

Un processo utente per completare la propria esecuzione ha bisogno di risorse tra cui memoria,processore, spazio sul disco etc. Nella realizzazione di un programma e teoricamente necessa-rio (o quantomeno e utile) conoscere i dettagli architetturali del sistema su cui l’applicazionesara eseguita; se pero i programmatori si dovessero preoccupare dei “dettagli” la complessitarealizzativa dell’applicazione sarebbe talmente elevata da impedire un facile e veloce svilup-po della stessa. Per questo motivo il sistema operativo nasconde la complessita, nonchel’eterogeneita, del sistema sottostante fornendo una serie di servizi al livello applicativo. Inquesto modo l’applicazione, sfruttando i servizi messi a disposizione, vedra un’astrazione dellamacchina sottostante.

Le system call nascono proprio per questo scopo; esse rappresentano il punto di contattofra il livello applicativo e il sistema operativo che a sua volta svolgera il compito richiestoridando poi il controllo all’applicazione. In parole povere le system call svolgono una serie dioperazioni in modalita supervisore per conto di un processo che funziona in modalita utente eche quindi non potra mai eseguire istruzioni privilegiate. E necessario percio che l’architetturadella macchina sottostante fornisca un meccanismo attraverso il quale il processo in questionepossa richiamare segmenti di codice del sistema operativo. La tecnica adoperata dalla maggiorparte dei sistemi e quella di impiegare le interruzioni software o traps. Sull’architettura x86e possibile registrare una ISR che risponda ad un vettore di interruzione passando quindidalla modalita utente alla modalita supervisore e quindi in effetti passando da un task utentead uno del sistema operativo; proprio questo e l’approccio che si adopera anche in Linuxsull’architettura x86.

3.3.2 ISR come handler di System Calls

Il meccanismo di gestione di una system call in Linux presuppone innanzitutto che si siaregistrata una ISR per l’Interrupt 0x80; quando un processo vuole invocare una system call,memorizza l’identificativo numerico della stessa nel registro EAX del processore. Questo ID

Page 89: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.3. Scopo degli esperimenti Capitolo 3. Caso di studio 88

fa parte di una tabella memorizzata nel file sorgente asm/unistd.h. I parametri della systemcall vengono poi salvati nei registri in ordine EBX, ECX, EDX, ESI, EDI; se questi registrinon dovessero bastare viene utilizzato anche lo stack. Questa tecnica viene utilizzata pervelocizzare il processo di chiamata dal momento che l’acceso ai registri e piu voloce rispettoad uno in memoria. A questo punto il processo effettua una Software Interrupt attraversol’esecuzione dell’istruzione INT 80h e il flusso di controllo passa all’ISR registrata per il vettore80 memorizzata nel file entry.S di cui si mostra la sezione interessata:

ENTRY(system_call)pushl %eax # save orig_eaxSAVE_ALL

#ifdef CONFIG_LATENCY_TRACEpushl %edx; pushl %ecx; pushl %ebx; pushl %eaxcall sys_callpopl %eax; popl %ebx; popl %ecx; popl %edx

#endifGET_THREAD_INFO(%ebp)

# system call tracing in operation/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)jnz syscall_trace_entrycmpl $(nr_syscalls), %eaxjae syscall_badsys

syscall_call:call *sys_call_table(,%eax,4)movl %eax,EAX(%esp) # store the return value

syscall_exit:cli # make sure we don’t miss an interrupt

# setting need_resched or sigpending# between sampling and the iret

movl TI_flags(%ebp), %ecxtestw $_TIF_ALLWORK_MASK, %cx # current->workjne syscall_exit_work

restore_all:movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS$

Come e possibile osservare l’handler system call per chiamare la system call effettiva uti-lizza l’indirizzo di base della tabella delle system call (puntato dal puntatore sys call table)a cui aggiunge lo spiazzamento ottenuto dal prodotto di EAX per un fattore 4 dal momentoche gli indirizzi sono a 32 bit (4 byte). In tal modo ottiene l’indirizzo effettivo dell’entry dellasystem call a cui cede il controllo (call). La system call viene eseguita e, come da convenzio-ne per le chiamate delle funzioni C-Assembly per l’architettura x86, il valore di ritorno vienememorizzato in EAX se si tratta di un valore rappresentabile entro 32 bit4 oppure se si tratta

4Solitamente le system call ritornano un long che in effetti e rappresentato in 32 bit su x86.

Page 90: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.4. Preparazione esperimenti con KProbes/SystemTAP Capitolo 3. Caso di studio 89

di una struttura dati EAX contiene un puntatore al valore. Il controllo viene quindi restituitoal processo che ha richiesto il servizio.

3.3.3 Contesto degli esperimenti

Una volta discusso il meccanismo di gestione delle system call non rimane che preparare edeseguire gli esperimenti utilizzando i tool presi in considerazione. Gli esperimenti eseguitisono stati svolti su una macchina con le seguenti caratteristiche salienti:

Processore: Intel Pentium 4 a 3GHz (2.998 GHz stimati)Memoria RAM: DDR a 400 MHz, 2048 MBPartizione di Swap: 1024 MB

Nel caso dell’esperimento con il tool KProbes/SystemTAP e stato adoperato un kernelcustom della distribuzione Linux Fedora Core 4, in particolare la versione 2.6.15-1.1830 FC4che rappresenta un kernel stabile. Le caratteristiche specifiche di tale kernel consistono nelfatto che e stato compilato con ottimizzazioni per il processore Intel Pentium 4 e che hauno schema di prelazione Preemptive (ossia low latency desktop). Per l’esperimento in cui estato impiegato il tool DSKI e stato impiegata la versione del kernel 2.6.12-RT-LIBERTOSconfigurata con le stesse opzioni appena descritte.

3.4 Preparazione esperimenti con KProbes/SystemTAP

In questa sezione ci proponiamo di descrivere gli esperimenti eseguiti attraverso il tool KPro-bes/SystemTAP. L’attenzione si concentrera dapprima sulla procedura di strumentazione perpoi spostarsi sui risultati ottenuti.I tre esperimenti di cui si mostrano i risultati sono statieseguiti per una durata di 6 ore ciascuno.

Avendo analizzato il sottosistema di gestione delle System Call in Linux e dal momentoche il tool di probing KProbes/SystemTAP puo inserire punti di strumentazione dinamica-mente si e deciso di inserire un punto in ingresso e uno in uscita dall’handler delle systemcall; per ottenere gli indirizzi fisici di questi due punti si puo utilizzare la mappa di sistemafornita in uscita dal processo di compilazione del kernel. Nel nostro caso siamo interessatiall’attraversamento delle locazioni di memoria che nel file entry.S, mostrato in precedenza,sono etichettate con le label system call e syscall exit.

3.4.1 Realizzazione dello script

Grazie al fatto che SystemTAP riesce ad inserire dinamicamente probing points, risulta moltosemplice realizzare uno script che possa monitorare il sottosistema di gestione delle systemcalls. Infatti, come e possibile osservare nella sezione 3.3.2, nella breve porzione di codiceassembly riportata vengono esportati degli identificatori globali che e possibile sfruttare perinserire i punti di strumentazione. Analizzando la mappa di sistema fornita in uscita dalprocesso di compilazione del kernel e possibile ottenere l’indirizzo fisico di tali punti delcodice; essendo interessati in particolare ai punti system call e syscall exit e possibileutilizzare l’utility grep sulla mappa di sistema per ottenere gli indirizzi fisici.

Lo script ha la funzione di monitorare il numero, la frequenza e i codici di ritorno dellevarie system calls. Esso inizia con queste righe di codice:

global ncalls // Numero di chiamate a syscalls per periodo

Page 91: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.4. Preparazione esperimenti con KProbes/SystemTAP Capitolo 3. Caso di studio 90

global callsperperiod // Vettore di chiamate a syscalls per periodoglobal numofperiods // Numero di periodi di strumentazione

global sysinvocations // Numero di chiamate totali per syscalls

global sysretvalues // Matrice di valori di uscita delle syscallsglobal pidcalls // Vettore di invocazione System Call

global timeforexit

probe begin {ncalls = 0delete callsperperiodnumofperiods = 0

delete sysinvocations

delete sysretvaluesdelete pidcalls

timeforexit = 0}

In tale segmento di codice e possibile osservare la dichiarazione delle variabili utilizzateper il monitoraggio, nonche la loro inizializzazione effettuata nel momento di registrazionedei probing points. Passo successivo consiste nel definire un punto di strumentazione che siainvocato ogni 1000ms (ogni secondo), il cui scopo e quello di tenere traccia delle frequenze diinvocazione nonche incrementare la variabile timeforexit, utilizzata dallo script per capirequando siano trascorse sei ore in maniera tale da poter terminare le proprie operazioni.

probe timer.ms(1000) { // Probe point invocato ogni secondo// Aggiunge il numero di chiamate al vettorecallsperperiod[numofperiods] = ncalls// Incrementa il numero di periodinumofperiods += 1// Azzera il numero di chiamate per periodoncalls = 0

// Termina dopo 6 oretimeforexit += 1if(timeforexit == 21600) {

exit()}

}

Nello script viene poi definita la funzione getEAX in codice C embedded, il cui scopo equello di ottenere il contenuto attuale del registro EAX del processore. Tale funzione viene

Page 92: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.4. Preparazione esperimenti con KProbes/SystemTAP Capitolo 3. Caso di studio 91

utilizzata sia in ingresso all’handler per capire quale system call sia stata invocata (vederesezione 3.3.2), sia in uscita all’handler per ottenere il codice di uscita. Si ricordi infatti che,per le convenzioni di chiamata C/Assembler dell’architettura IA32, i valori di ritorno di unafunzione sono riportati nel registro EAX se rappresentabili in un numero di bit fino a 32;dal momento che le system call riportano sempre in uscita un codice numerico intero, risultachiara l’importanza di questa funzione.

function getEAX:long()%{THIS->__retvalue = CONTEXT->regs->eax;

%}

A tal punto lo script inserisce due probing points che devono lavorare congiuntamente iningresso all’handler di system call e in uscita (sfruttando gli indirizzi ottenuti precedentemen-te):

// Probe in ingresso al wrapper delle syscallsprobe kernel.statement(0xC0102E3C) {

// Memorizza quale syscall il processo pid() ha invocatopidcalls[pid()] = getEAX()

}

// Probe in uscita dal wrapper delle syscallsprobe kernel.statement(0xC0102E79) {

if(getEAX() < 0 && getEAX() > -255) {ernum = - getEAX()sysretvalues[pidcalls[pid()], ernum] += 1

}else {

sysretvalues[pidcalls[pid()], 0] += 1}

// Incrementa il numero di chiamate a syscall totalisysinvocations[pidcalls[pid()]] += 1// Incrementa il numero di chiamate di syscalls per periodoncalls += 1

delete pidcalls[pid()]}

Per poter tener traccia dell’associazione system call invocata/valore di ritorno, lo scriptutilizza il vettore di supporto pidcalls che ha lo scopo di memorizzare in ingresso al wrapperquale sia stata la system call invocata dal processo con un determinato pid; tale valore sarautilizzato in uscita dal wrapper, in quanto sfruttando il pid del processo corrente si puorisalire alla system call invocata, potendo quindi associare a quest’ultima il valore di ritornoattualmente presente nel registro EAX. Questo stratagemma risulta essere necessario; infatti,sebbene in ingresso al wrapper e possibile identificare la system call invocata leggendo il

Page 93: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.5. Preparazione esperimenti con DSKI Capitolo 3. Caso di studio 92

contenuto del registro EAX, in uscita questa informazione viene perduta e l’unico modo perrisalirvi risulta essere il pid del processo che l’ha invocata5.

Infine lo script definisce un punto di uscita che ha lo scopo di visualizzare i risultati; inquesto modo, mostrando i dati al termine delle sei ore dell’esperimento, si evita di falsarei risultati dello stesso, dal momento che la visualizzazione su schermo comporta chiamate asystem call di scrittura, come la write:

probe end { // Probe di uscita

// Stampa le frequenze di chiamataforeach(i in callsperperiod) {

printf(" %d\n", callsperperiod[i])}

// Stampa il numero di chiamate totali per syscallsforeach(j in sysinvocations) {

printf("in %d\t%d\n", j, sysinvocations[j])}

// Stampa i valori di ritorno delle syscallforeach([k, ernum] in sysretvalues) {

printf("va %d\t%d\t%d\n", k, ernum, sysretvalues[k, ernum])}

}

Onde valutare i risultati sperimentali sono stati realizzati, per ogni esperimento, una seriedi grafici. In particolare si traccia una distribuzione di probabilita del numero di chiamatea system call in un secondo. Questo grafico risulta essere indicativo delle caratteristiche delworkload: quanto piu il sistema viene stressato tanto piu il numero di system call per secondoaumenta e quindi la pdf avra il suo massimo sempre piu spostato verso destra. Un secondografico (o una tabella) e indicativo delle frequenze di chiamata delle system call e questo dainformazione sulla particolare system call (ad esempio ci si aspetta che per un workload I/Obound la read venga chiamata con una frequenza maggiore rispetto alle altre). Infine unatabella riporta le percentuali di codici di uscita delle system call.

3.5 Preparazione esperimenti con DSKI

Una volta eseguiti gli esperimenti appena descritti, ci siamo proposti di impiegare per lo stessoscopo l’interfaccia DSKI. Purtroppo pero l’handler delle system call, che costituisce un puntodi incontro di tutte le chiamate a sistema, si trova in un file sorgente in linguaggio assembly(entry.S) e non C. Dal momento che il framework DSKI sfrutta un sistema di macro C perrealizzare le proprie funzioni cio costringe ad inserire dei punti di strumentazione direttamentein ogni system call. Possiamo pero sfruttare i risultati degli esperimenti eseguiti con l’altrotool e mostrati nel capitolo successivo nella sezione 4.1. Tali risultati mettono in evidenza

5Si ricordi che tale assunto vale anche in ambiente multithread dal momento che Linux gestisce thread eprocessi allo stesso modo.

Page 94: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

3.5. Preparazione esperimenti con DSKI Capitolo 3. Caso di studio 93

che, stressando il sistema con i workload descritti nella sezione 3.2, non tutte le system callhanno una elevata probabilita di essere invocate anzi alcune non vengono affatto chiamatementre molte intervengono solo sporadicamente. Alla luce di questi fattori si e deciso di nonmonitorare con DSKI tutte le circa 300 system call ma di limitarsi ad un sottoinsieme di 10system call scelte proprio sulla base dei risultati sperimentali ottenuti con gli altri tool. Diseguito sono riportate le 10 system call selezionate per essere strumentate con DSKI:

• read usata per leggere da un file descriptor;

• write usata per scrivere in un file descriptor;

• llseek usata per muovere un puntatore all’interno di un file in scrittura o lettura;

• open usata per aprire un file o un dispositivo;

• close usata per chiudere un file descriptor;

• ioctl usata per controllare un device;

• select usata per la sincronizzazione in operazioni di I/O;

• rt sigaction usata per gestire i segnali;

• mmap2 usata per mappare pagine di memoria;

• brk usata per cambiare la lunghezza di un segmento dati allocato ad un processo.

Gli esperimenti si limiteranno a queste 10 system call e avranno, in tal caso, una duratadi 1 ora. Il motivo per cui si e preferito ridurre ad un sesto la durata del monitoraggio sta nelfatto che DSKI restituisce in uscita un file binario che risulta avere dimensioni molto elevate,infatti con un esperimento della durata di 1 ora il file binario di uscita assume dimensioni disvariati MB. Quindi si e preferito ridurre la durata dell’esperimento anche perche i workloadimpiegati durano meno di un’ora dopodiche vengono rimessi in esecuzione quindi teoricamentenon ci dovrebbero essere differenze tra i risultati se questi vengono normalizzati.

Page 95: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Capitolo 4

Risultati sperimentali

In questo ultimo capitolo ci preoccuperemo di mostrare i risultati ottenuti dall’esecuzionedegli esperimenti descritti nel capitolo precedente. Cominceremo con i risultati ottenuti mo-nitorando le system call con il tool KProbes/SystemTAP dato che questi risultati sono statiesaminati per prendere la decisione sulle system call da monitorare con DSKI. Proseguiremoquindi con i risultati relativi agli esperimenti monitorati con DSKI e infine deriveremo lerelative conclusioni.

4.1 Risultati KProbes/SystemTAP

In tale sezione vengono mostrati i risultati del monitoraggio di tutte le circa 300 system call at-traverso il tool KProbes/SystemTAP. Le tre sezioni seguenti mostrano gli effetti relativamenteal carico impiegato. Per ogni sezione vengono fornite le seguenti informazioni:

1. pdf del numero di chiamate (al secondo) di tutte le system call;

2. tabella contenente la percentuale di chiamata di ciascuna system call;

3. tebella contenente i codici d’errore con cui le system call terminano.

4.1.1 Caso CPU bound

Il primo esperimento consiste nell’esecuzione del workload CPU bound descritto nella sezione3.2.1 e parallelamente nell’utilizzo del tool per catturare le informazioni desiderate. Dall’espe-rimento ci si aspetta che le frequenze di chiamata per secondo a system call si distribuiscanocon una distribuzione decrescente; infatti dal momento che la CPU e per la maggior partedel tempo impegnata ad effettuare calcoli numerici ci si aspetta che la probabilita di averen chiamate in un secondo diminuisca con l’aumentare di n. I risultati ottenuti approssima-tivamente concordano con le predizioni tenendo conto comunque che vi sono dei picchi spuridovuti principalmente alle attivita secondarie di IO svolte dal benchmarck (stampa a videodi alcune informazioni etc.) e che generano questi impulsi nel grafico (figura 4.1); a talemotivazione sono imputabili anche le componenti intorno a 140 e 220 chiamate, che in ognicaso corrispondono complessivamente ad una probabilita molto bassa. Calcolando la mediadella pdf ottenuta si ricava µ = 111.86 mentre la deviazione standard e σ = 360.41 il cherisulta essere in sintonia con il fatto che il workload e di tipo CPU bound, infatti una media

94

Page 96: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 95

di circa 111 chiamate a system call al secondo e davvero molto bassa, considerando che perun calcolatore un intervallo di 1 secondo e un’enormita.

Figura 4.1: Pdf numero chiamate system call al secondo, caso CPU

Grossomodo la pdf sembra approssimabile ad una distribuzione esponenziale. Per validarequesta affermazione e possibile utilizzare un software di identificazione delle curve a partiredai campioni che vengono impiegati per il plottaggio; nel nostro caso i campioni indicano ilnumero di chiamate al secondo. Senza andare nei dettagli descrittivi del software impiegato,ci limitiamo a dire che una volta forniti i campioni e possibile precisare il tipo di distribuzionerelativamente alla quale va eseguito il confronto. Nel nostro caso siamo interessati a confron-tare la pdf con un’esponenziale per cui e stata scelta appunto questa particolare distribuzionetra quelle disponibili (normale, esponenziale, logaritmica etc.). I risultati sono mostrati nellafigura 4.2 in cui sull’asse delle ascisse vengono mostrati i percentili esponenziali1.

Per comprendere il risultato ottenuto basta riferirsi alla retta obliqua mostrata sullo sfon-do. Se tutti i punti coincidessero con tale retta allora avremmo effettivamente una curvaesponenziale. Nel nostro caso i punti coincidono fino al percentile 97/98-esimo2 poi si al-lontanano. Gli ulteriori punti, pero, non sono sparsi casualmente ma si allontanano distri-

1Si ricordi che il percentile u-esimo di una variabile aleatoria, con u ∈ [0, 1] (in quanto probabilita), eindicato col simbolo xu e rappresenta il valore che la variabile aleatoria non supera con probabilita pari a u.

2A rigore si dovrebbe dire il percentile 0.97/0.98-esimo ma, per uniformarci alla notazione delle figure, daqui in avanti indicheremo i percentili tramite i corrispondenti valori normalizzati a 100.

Page 97: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 96

Figura 4.2: Comparazione della pdf con la distribuzione esponenziale, caso CPU bound.

buendosi su altre due rette parallele a quella di riferimento. Si puo pensare che quindi ladistribuzione e una somma di esponenziali dove gli altri due esponenziali sono semplicementeshiftati rispetto al primo. La somma di piu esponenziali, nota come funzione iperesponenzia-le, e ancora un’esponenziale quindi si puo concludere che effettivamente la pdf si distribuisceesponenzialmente.

La pdf del numero di chiamate al secondo da un’informazione generale sulle caratteristichedel workload. Quello che e interessante analizzare, a questo punto, sono le frequenze relativedelle singole system call invocate dal workload. Tali informazioni sono riportate nelle tabelle4.1 e 4.2 e nel grafico a barre di figura 4.3 sono riportate le percentuali di chiamata dellesystem call piu invocate.

Come e possibile evincere dalle tabelle riportate, in cui sono evidenziate in grassettole system call con una percentuale di chiamata maggiore del 5%, le syscall maggiormenteinvocate sono la rt sigprocmask e la rt sigaction; esse vengono impiegate per gestire l’inviodi segnali tra processi concorrenti, quindi e ragionevole supporre tale risultato in sintonia conle previsioni riguardanti un carico di tipo CPU bound. In effetti nelle applicazioni di tipoCPU bound vengono spesso utilizzate tecniche di programmazione concorrente per ottimizzarel’utilizzo del processore.

In ultima analisi, osserviamo adesso i codici di ritorno restituiti dalle system call invocateriportati nelle tabelle 4.3 e 4.4. Ovviamente non sempre i codici di ritorno negativi rappre-sentano una situazione di errore, ma il tutto dipende dalla semantica della particolare system

Page 98: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 97

Tabella 4.1: System Call invocate nell’esperimento CPU bound con SystemTAP/KProbes conID da 0 a 100. In grassetto sono evidenziate le system call con una percentuale di chiamatemaggiore del 5%.

KProbes/SystemTAP – CPU BOUND – Frequenze invocazioni – Parte 1ID Nome Numero Chiamate %

0 restart syscall 20123 00.833 read 105159 04.354 write 130923 05.425 open 112139 04.646 close 283215 11.727 waitpid 35444 01.47

10 unlink 1089 00.0511 execve 15166 00.6312 chdir 3904 00.1613 time 16346 00.6815 chmod 55 00.0019 lseek 110 00.0020 getpid 789 00.0327 alarm 10816 00.4529 pause 5 00.0033 access 28846 01.1936 sync 3126 00.1337 kill 2379 00.1042 pipe 4422 00.1845 brk 36936 01.5354 ioctl 188003 07.7860 umask 167 00.0163 dup2 14262 00.5964 getppid 899 00.0465 getpgrp 899 00.0466 setsid 6 00.0075 setrlimit 90 00.0077 getrusage 44717 01.8578 gettimeofday 35186 01.4685 readlink 140 00.0191 munmap 40985 01.7094 fchmod 72 00.0096 getpriority 2880 00.1297 setpriority 1446 00.0699 statfs 72 00.00

100 fstatfs 36 00.00

Page 99: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 98

Tabella 4.2: System Call invocate nell’esperimento CPU bound con SystemTAP/KProbescon ID da 101 a 300. In grassetto sono evidenziate le system call con una percentuale dichiamate maggiore del 5%.

KProbes/SystemTAP – CPU BOUND – Frequenze invocazioni – Parte 2ID Nome Numero Chiamate %

102 socketcall 130284 05.39114 wait4 2016 00.08118 fsync 13 00.00119 sigreturn 22071 00.91120 clone 19717 00.82122 newuname 1011 00.04125 mprotect 41310 01.71133 fchdir 110 00.00140 llseek 4081 00.17141 getdents 5928 00.25142 select 31844 01.32146 writev 12 00.00149 sysctl 3456 00.14162 nanosleep 14230 00.59168 poll 5068 00.21174 rt sigaction 346470 14.34175 rt sigprocmask 252364 10.44183 getcwd 173 00.01190 vfork 385 00.02191 getrlimit 4274 00.18192 mmap2 163763 06.78195 stat64 70259 02.91196 lstat64 3045 00.13197 fstat64 103357 04.28199 getuid 795 00.03200 getgid 789 00.03201 geteuid 801 00.03202 getegid 795 00.03205 getgroups 1004 00.04206 setgroups 12 00.00207 fchown 72 00.00213 setuid 18 00.00214 setgid 6 00.00220 getdents64 696 00.03221 fcntl64 19236 00.80240 futex 376 00.02243 set thread area 14396 00.60256 epoll wait 4319 00.18258 set tid address 3456 00.14265 clock gettime 3401 00.14268 statfs64 55 00.00

Page 100: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 99

Figura 4.3: KProbes/SystemTAP, caso CPU bound. Percentuali del numero di invocazionidelle system call maggiormente invocate.

call. In ogni caso per conoscere il significato di ogni codice fare riferimento all’appendiceC. Nell’analisi di tali tabelle bisogna pero tenere presente che si e eseguito l’esperimentoutilizzando un kernel stabile e che pertanto la maggior parte delle system call non restituiscecodici d’errore particolari.

4.1.2 Caso IO bound

In questo secondo esperimento e stato applicato il workload I/O bound. I risultati che cisi aspetta di trovare ovviamente sono diversi rispetto al caso precedente; in tal caso infatti,poiche il workload in questione si suppone debba effettuare molte operazioni di I/O, ci siaspetta che la distribuzione sia sempre decrescente, ma con un fattore di scala maggiore, datoche sicuramente il numero complessivo di chiamate al secondo sara superiore. I risultati sonomostrati in figura 4.4; come e possibile notare, e chiaramente visibile l’andamento decrescentedella pdf, anche se sono presenti componenti spurie come nel caso precedente. In tal caso lamedia risulta µ = 822.29 cioe circa otto volte maggiore rispetto a prima, mentre la deviazionestandard e σ = 3446.5; una σ cosı elevata, oltre ad avere un riscontro grafico, dal momentoche la pdf I/O bound e maggiormente distribuita sull’asse delle ascisse, possiede anche unamotivazione tecnica, poiche in alcuni intervalli il workload era bloccato in attesa del comple-tamento delle operazioni di I/O, cosicche il numero di chiamate a system call al secondo erabasso, in altri invece era in piena attivita.

Osservando la figura 4.4 si potrebbe pensare che la pdf assume anche in tal caso unandamento esponenziale visto che la differenza piu evidente col caso CPU bound e che risultanon nulla in molti piu intervalli dell’asse delle acisse. Eseguiamo quindi il procedimento diidentificazione della curva specificando la distribuzione esponenziale come base di confronto.Il risultato e mostrato in figura 4.5

Stavolta i punti coincidono con la retta di riferimento solo fino al 50-esimo percentile perpoi distribuirsi su una retta con un coefficiente angolare significativamente diverso. Cio sug-

Page 101: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 100

Tabella 4.3: Codici di ritorno delle system call invocate nell’esperimento CPU bound conSystemTAP/KProbes, primo gruppo.

KProbes/SystemTAP – CPU BOUND – Codici di Ritorno – Parte 1Nome OK % Altri Codici

restart syscall 100.00 Nessunoread 100.00 Nessuno

write 100.00 Nessunoopen 097.42 ENOENT = 2.57, ENXIO = 0.01close 099.48 EBADF = 0.52

waitpid 051.04 ECHILD = 48.96unlink 057.58 ENOENT = 42.42execve 094.92 ENOENT = 4.35, ENOEXEC = 0.73chdir 100.00 Nessunotime 100.00 Nessuno

chmod 100.00 Nessunolseek 100.00 Nessuno

getpid 100.00 Nessunoalarm 100.00 Nessunopause 100.00 Nessunoaccess 049.46 ENOENT = 50.51, EACCESS = 0.03

sync 100.00 Nessunokill 100.00 Nessuno

pipe 100.00 Nessunobrk 100.00 Nessuno

ioctl 075.35 EAGAIN = 0.77, EINVAL = 11.59, ENOTTY= 0.8, EADDRNOTAVAIL = 11.49

umask 100.00 Nessunodup2 100.00 Nessuno

getppid 100.00 Nessunogetpgrp 100.00 Nessuno

setsid 100.00 Nessunosetrlimit 100.00 Nessuno

getrusage 100.00 Nessunogettimeofday 100.00 Nessuno

readlink 100.00 Nessunomunmap 100.00 Nessunofchmod 100.00 Nessuno

getpriority 100.00 Nessunosetpriority 100.00 Nessuno

statfs 100.00 Nessunofstatfs 100.00 Nessuno

Page 102: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 101

Tabella 4.4: Codici di ritorno delle system call invocate nell’esperimento CPU bound conSystemTAP/KProbes, secondo gruppo.

KProbes/SystemTAP – CPU BOUND – Codici di Ritorno – Parte 2Nome OK % Altri Codici

socketcall 099.81 ENOENT = 0.14wait4 099.70 ECHILD = 0.03fsync 100.00 Nessuno

sigreturn 090.15 EINTR = 9.85clone 100.00 Nessuno

newuname 100.00 Nessunomprotect 100.00 Nessuno

fchdir 100.00 Nessunollseek 099.85 ESPIPE = 0.15

getdents 100.00 Nessunoselect 100.00 Nessuno

writev 100.00 Nessunosysctl 100.00 Nessuno

nanosleep 100.00 Nessunopoll 071.61 EINTR = 28.39

rt sigaction 099.17 EINVAL = 0.83rt sigprocmask 100.00 Nessuno

getcwd 100.00 Nessunovfork 100.00 Nessuno

getrlimit 100.00 Nessunommap2 100.00 Nessunostat64 069.75 ENOENT = 30.25lstat64 100.00 Nessunofstat64 100.00 Nessunogetuid 100.00 Nessunogetgid 100.00 Nessuno

geteuid 100.00 Nessunogetegid 100.00 Nessuno

getgroups 100.00 Nessunosetgroups 100.00 Nessuno

fchown 100.00 Nessunosetuid 066.67 EPERM = 33.33setgid 100.00 Nessuno

getdents64 100.00 Nessunofcntl64 100.00 Nessuno

futex 100.00 Nessunoset thread area 100.00 Nessuno

epoll wait 100.00 Nessunoset tid address 100.00 Nessunoclock gettime 100.00 Nessuno

statfs64 100.00 Nessuno

Page 103: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 102

Figura 4.4: Pdf numero chiamate system call al secondo, caso I/O

gerisce che l’andamento della pdf non e approssimabile ad un’esponenziale per cui proviamoad eseguire il confronto con una distribuzione normale. Il risultato e fornito in figura 4.6

Purtroppo anche questa seconda comparazione da esito negativo perche i punti sono as-sai lontani dalla retta di riferimento, anzi sono anche piu lontani rispetto al confronto conl’esponenziale. Volendo si potrebbe tentare di identificare la pdf con altre possibili curvema l’andamento della funzione non sembra ricordare alcuna funzione canonica ad eccezionedell’esponenziale. Si puo concludere quindi che la pdf ha, nel caso IO bound, un andamentomolto piu irregolare, tanto da non poterla ricondurre ad una funzione nota. Le figure 4.5 e4.6 ci permettono di dire che comunque essa e molto piu simile ad un’esponenziale che ad unanormale pur non essendo ne l’una ne l’altra.

Anche in questo caso riportiamo le tabelle con le frequenze relative di invocazioni systemcall al secondo (tabelle 4.5 e 4.6).

Nel caso I/O bound e possibile osservare che le system call che vengono invocate con unafrequenza maggiore del 5% sono solo tre ed in particolare la read, la write e la llseek; si notila predominanza di tali system call rispetto alle altre, tanto e vero che circa il 93% delle voltee stata invocata una di esse. Questo fatto del resto e in pieno accordo con le previsioni, dalmomento che un carico di tipo I/O bound effettuera molte operazioni di scrittura e lettura, ilche spiega la loro predominanza (si ricordi che la llseek serve per spostare l’offset all’internodi un file aperto in lettura/scrittura).

Page 104: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 103

Tabella 4.5: System Call invocate nell’esperimento I/O bound con SystemTAP/KProbes conID da 0 a 100. In grassetto sono evidenziate le system call con una percentuale di chiamatemaggiore del 5%.

KProbes/SystemTAP – I/O BOUND – Frequenze invocazioni – Parte 1ID Nome Numero Chiamate %

0 restart syscall 3021 00.023 read 6636768 37.364 write 5015786 28.245 open 83926 00.476 close 220403 01.247 waitpid 3075 00.02

10 unlink 6640 00.0411 execve 68 00.0012 chdir 9 00.0013 time 15332 00.0920 getpid 15 00.0027 alarm 4367 00.0229 pause 5 00.0033 access 161 00.0036 sync 4320 00.0237 kill 2159 00.0142 pipe 60 00.0045 brk 204 00.0054 ioctl 185280 01.0460 umask 3 00.0063 dup2 140 00.0064 getppid 15 00.0065 getpgrp 15 00.0066 setsid 6 00.0075 setrlimit 90 00.0078 gettimeofday 93104 00.5285 readlink 30 00.0091 munmap 24176 00.1493 ftruncate 2160 00.0194 fchmod 71 00.0096 getpriority 2880 00.0297 setpriority 1446 00.0199 statfs 72 00.00

100 fstatfs 36 00.00

Page 105: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 104

Tabella 4.6: System Call invocate nell’esperimento I/O bound con SystemTAP/KProbes conID da 101 a 300. In grassetto sono evidenziate le system call con una percentuale di chiamatemaggiore del 5%.

KProbes/SystemTAP – I/O BOUND – Frequenze invocazioni – Parte 2ID Nome Numero Chiamate %102 socketcall 129859 00.73114 wait4 15 00.00118 fsync 51876 00.29119 sigreturn 5857 00.03120 clone 1559 00.01122 newuname 35 00.00125 mprotect 212 00.00140 llseek 4943308 27.83141 getdents 5928 00.03142 select 31980 00.18146 writev 15 00.00149 sysctl 17 00.00162 nanosleep 11102 00.06168 poll 5086 00.03174 rt sigaction 133219 00.75175 rt sigprocmask 56288 00.32183 getcwd 9 00.00191 getrlimit 116 00.00192 mmap2 24949 00.14195 stat64 10128 00.06196 lstat64 2880 00.02197 fstat64 34043 00.19199 getuid 21 00.00200 getgid 15 00.00201 geteuid 27 00.00202 getegid 21 00.00205 getgroups 6 00.00206 setgroups 12 00.00207 fchown 71 00.00213 setuid 18 00.00214 setgid 6 00.00220 getdents64 36 00.00221 fcntl64 3312 00.02240 futex 94 00.00243 set thread area 68 00.00256 epoll wait 4320 00.02258 set tid address 17 00.00

Page 106: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 105

Figura 4.5: Comparazione della pdf con la distribuzione esponenziale, caso IO bound.

Adesso esaminiamo i codici di ritorno riportati nelle tabelle 4.7 e 4.8.Bisogna tuttavia notare che, dal momento che le system call maggiormente invocate sono

la read, la write e la llseek mentre il resto ha una frequenza di invocazione al di sottodell’1%, tali risultati sono significativi esclusivamente per le tre suddette system call. Si vedeinfatti che la read e la write praticamente non falliscono mai, mentre la llseek ha anch’essaun tasso di successo prossimo al 100%.

4.1.3 Caso MEMORY bound

Nel terzo esperimento e stato applicato il workload appositamente realizzato per sforzare lamemoria del sistema descritto in precedenza. Nel caso MEMORY bound, tuttavia, data lanatura lineare e semplice del workload adoperato, ci si aspettava una pdf completamentediversa dalle precedenti, con caratteristiche abbastanza regolari. Il risultato, mostrato infigura 4.7, ci mostra una pdf chiaramente gaussiana3; in parte cio e dovuto alla natura costantedel carico, che nella frazione di tempo considerato effettua quasi sempre lo stesso numero dichiamate al sistema. La media della pdf in questione risulta µ = 526.74 mentre la deviazionestandard σ = 621.7.

Nelle tabelle 4.9 e 4.10 che riportano le frequenze di invocazioni a system call, si puo no-3In tal caso l’andamento della pdf e nettamente evidente quindi, come anche per DSKI, non ci

preoccuperemo di giustificarne l’andamento (al contrario dei casi precedenti).

Page 107: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 106

Tabella 4.7: Codici di ritorno delle system call invocate nell’esperimento I/O bound conSystemTAP/KProbes, primo gruppo.

KProbes/SystemTAP – I/O BOUND – Codici di Ritorno – Parte 1Nome OK % Altri Codici

restart syscall 099.97 EINTR = 0.03read 100.00 Nessuno

write 100.00 Nessunoopen 099.88 ENOENT = 0.1, ENXIO = 0.02close 099.00 EBADF = 1

waitpid 050.37 ECHILD = 49.63unlink 098.67 ENOENT = 1.33execve 100.00 Nessunochdir 100.00 Nessunotime 100.00 Nessuno

getpid 100.00 Nessunoalarm 100.00 Nessunopause 100.00 Nessunoaccess 042.86 ENOENT = 49.69, EACCESS = 7.45

sync 100.00 Nessunokill 100.00 Nessuno

pipe 100.00 Nessunobrk 100.00 Nessuno

ioctl 75.88 EAGAIN = 0.78, EINVAL = 11.67, ENOTTY= 0.01, EADDRNOTAVAIL = 11.66

umask 100.00 Nessunodup2 100.00 Nessuno

getppid 100.00 Nessunogetpgrp 100.00 Nessuno

setsid 100.00 Nessunosetrlimit 100.00 Nessuno

gettimeofday 100.00 Nessunoreadlink 100.00 Nessunomunmap 100.00 Nessunoftruncate 100.00 Nessuno

fchmod 100.00 Nessunogetpriority 100.00 Nessunosetpriority 100.00 Nessuno

statfs 100.00 Nessunofstatfs 100.00 Nessuno

Page 108: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 107

Tabella 4.8: Codici di ritorno delle system call invocate nell’esperimento I/O bound conSystemTAP/KProbes, secondo gruppo.

KProbes/SystemTAP – I/O BOUND – Codici di Ritorno – Parte 2Nome OK % Altri Codici

socketcall 099.98 ENOENT = 0.01wait4 060.00 ECHILD = 40fsync 100.00 Nessuno

sigreturn 062.57 EINTR = 37.43clone 100.00 Nessuno

newuname 100.00 Nessunomprotect 100.00 Nessuno

llseek 099.91 EINVAL = 0.09getdents 100.00 Nessuno

select 100.00 Nessunowritev 100.00 Nessunosysctl 100.00 Nessuno

nanosleep 100.00 Nessunopoll 071.35 EINTR = 28.65

rt sigaction 097.84 EACCESS = 2.16rt sigprocmask 100.00 Nessuno

getcwd 100.00 Nessunogetrlimit 100.00 Nessunommap2 100.00 Nessunostat64 098.84 ENOENT = 1.16lstat64 100.00 Nessunofstat64 100.00 Nessunogetuid 100.00 Nessunogetgid 100.00 Nessuno

geteuid 100.00 Nessunogetegid 100.00 Nessuno

getgroups 100.00 Nessunosetgroups 100.00 Nessuno

fchown 100.00 Nessunosetuid 066.67 EPERM = 33.33setgid 100.00 Nessuno

getdents64 100.00 Nessunofcntl64 100.00 Nessuno

futex 100.00 Nessunoset thread area 100.00 Nessuno

epoll wait 100.00 Nessunoset tid address 100.00 Nessuno

Page 109: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 108

Tabella 4.9: System Call invocate nell’esperimento MEMORY bound con System-TAP/KProbes con ID da 0 a 100. In grassetto sono evidenziate le system call con unapercentuale di chiamate maggiore del 5%.KProbes/SystemTAP – MEMORY BOUND – Frequenze invocazioni – Parte 1ID Nome Numero Chiamate %

0 restart syscall 2371 00.023 read 53057 00.344 write 69504 00.445 open 41213 00.266 close 174547 01.117 waitpid 4209 00.03

10 unlink 140 00.0011 execve 872 00.0112 chdir 6 00.0013 time 15105 00.1020 getpid 12 00.0027 alarm 4128 00.0329 pause 11 00.0033 access 890 00.0137 kill 2145 00.0142 pipe 12 00.0045 brk 14622839 93.1554 ioctl 184482 01.1863 dup2 48 00.0064 getppid 12 00.0065 getpgrp 12 00.0066 setsid 6 00.0075 setrlimit 90 00.0078 gettimeofday 31698 00.2085 readlink 30 00.0091 munmap 22593 00.1494 fchmod 70 00.0096 getpriority 2456 00.0297 setpriority 1234 00.0199 statfs 70 00.00

100 fstatfs 36 00.00

Page 110: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.1. Risultati KProbes/SystemTAP Capitolo 4. Risultati sperimentali 109

Tabella 4.10: System Call invocate nell’esperimento MEMORY bound con System-TAP/KProbes con ID da 101 a 300.KProbes/SystemTAP – MEMORY BOUND – Frequenze invocazioni – Parte 2ID Nome Numero Chiamate %102 socketcall 128928 00.82114 wait4 12 00.00118 fsync 8 00.00119 sigreturn 6198 00.04120 clone 2112 00.01122 newuname 12 00.00125 mprotect 1768 00.01140 llseek 30 00.00141 getdents 5078 00.03142 select 31598 00.20146 writev 6 00.00162 nanosleep 11103 00.07168 poll 5611 00.04174 rt sigaction 125725 00.80175 rt sigprocmask 62030 00.40183 getcwd 6 00.00191 getrlimit 96 00.00192 mmap2 27975 00.18195 stat64 9865 00.06196 lstat64 2456 00.02197 fstat64 35524 00.23199 getuid 18 00.00200 getgid 12 00.00201 geteuid 24 00.00202 getegid 18 00.00206 setgroups 12 00.00207 fchown 70 00.00213 setuid 18 00.00214 setgid 6 00.00220 getdents64 36 00.00221 fcntl64 2859 00.02240 futex 87 00.00243 set thread area 872 00.01256 epoll wait 4311 00.03

Page 111: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 110

Figura 4.6: Comparazione della pdf con la distribuzione esponenziale, caso IO bound.

tare in questo caso una netta predominanza della brk con un frequenza del 93% circa. Questorisultato e in accordo con le previsioni, in quanto la brk ha lo scopo di modificare la dimen-sione in memoria assegnata al segmento dati di un processo da parte del sistema operativo.Dal momento che il workload impiegato nell’esperimento e stato studiato appositamente perstressare il sottosistema di gestione della memoria assegnata ai processi, tale risultato era ineffetti piu che prevedibile.

Per quanto riguarda i codici di ritorno, riportati nelle tabelle 4.11 e 4.12, dal momentoche tutte le system call vengono invocate con una frequenza al di sotto del 2% mentre labrk viene invocata quasi sempre, il risultato maggiormente significativo riguarda il tasso disuccesso di quest’ultima. Si vede infatti che essa praticamente non fallisce mai, avendo untasso di successo del 100%.

4.2 Risultati DSKI

Le successive tre sezioni mostrano i risultati dell’indagine sulle 10 system call monitorate conDSKI a seconda del carico impiegato. Ogni sezione mostra le stesse informazioni descrittenella sezione 4.1; l’unica eccezione e costituita dalla percentuale di chiamata di ciascunasystem call che viene mostrata graficamente e non tabularmente (dato che sono coinvolte unnumero esiguo di SVC).

Page 112: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 111

Tabella 4.11: Codici di ritorno delle system call invocate nell’esperimento MEMORY boundcon SystemTAP/KProbes, primo gruppo.

KProbes/SystemTAP – MEMORY BOUND – Codici di Ritorno – Parte 1Nome OK % Altri Codici

restart syscall 099.96 EINTR = 0.04read 100.00 Nessuno

write 100.00 Nessunoopen 099.87 ENOENT = 0.1, ENXIO = 0.03close 100.00 Nessuno

waitpid 049.99 ECHILD = 50.01unlink 050.00 ENOENT = 50execve 100.00 Nessunochdir 100.00 Nessunotime 100.00 Nessuno

getpid 100.00 Nessunoalarm 100.00 Nessunopause 100.00 Nessunoaccess 001.35 ENOENT = 98.65

kill 100.00 Nessunopipe 100.00 Nessunobrk 100.00 Nessuno

ioctl 064.44 EAGAIN = 0.67, EINVAL = 11.64, EADDR-NOTAVAIL = 23.26

dup2 100.00 Nessunogetppid 100.00 Nessunogetpgrp 100.00 Nessuno

setsid 100.00 Nessunosetrlimit 100.00 Nessuno

gettimeofday 100.00 Nessunoreadlink 100.00 Nessunomunmap 100.00 Nessunofchmod 100.00 Nessuno

getpriority 100.00 Nessunosetpriority 100.00 Nessuno

statfs 100.00 Nessunofstatfs 100.00 Nessuno

Page 113: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 112

Tabella 4.12: Codici di ritorno delle system call invocate nell’esperimento MEMORY boundcon SystemTAP/KProbes, primo gruppo.

KProbes/SystemTAP – MEMORY BOUND – Codici di Ritorno – Parte 2Nome OK % Altri Codici

socketcall 099.99 ENOENT = 0.01wait4 050.00 ECHILD = 50fsync 100.00 Nessuno

sigreturn 048.69 EINTR = 51.31clone 100.00 Nessuno

newuname 100.00 Nessunomprotect 100.00 Nessuno

llseek 080.00 ESPIPE = 20getdents 100.00 Nessuno

select 100.00 Nessunowritev 100.00 Nessuno

nanosleep 100.00 Nessunopoll 056.50 EINTR = 43.5

rt sigaction 098.05 EINVAL = 1.95rt sigprocmask 100.00 Nessuno

getcwd 100.00 Nessunogetrlimit 100.00 Nessunommap2 100.00 Nessunostat64 099.76 ENOENT = 0.24lstat64 100.00 Nessunofstat64 100.00 Nessunogetuid 100.00 Nessunogetgid 100.00 Nessuno

geteuid 100.00 Nessunogetegid 100.00 Nessuno

setgroups 100.00 Nessunofchown 100.00 Nessunosetuid 066.67 EPERM = 33.33setgid 100.00 Nessuno

getdents64 100.00 Nessunofcntl64 100.00 Nessuno

futex 100.00 Nessunoset thread area 100.00 Nessuno

epoll wait 100.00 Nessuno

Page 114: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 113

Figura 4.7: Pdf numero chiamate system call al secondo, caso MEMORY

4.2.1 Caso CPU bound

Come nel caso degli esperimenti di SystemTAP ci aspettiamo che il sistema stressato con unworlkload di tipo CPU bound non vada a sforzare particolarmete l’insieme delle system callin quanto le operazioni aritmetiche con cui e in effetti realizzato non richiedono dei “servizi”alle system call. Analizziamo quindi la pdf ottenuta attraverso il filtro e mostrata in figura4.8.

Come presupposto il numero di chiamate in un secondo non e molto elevato e la probabilitapiu alta e che questo numero sia compreso tra 1 e 25 chiamate. Da notare come l’andamentocomplessivo della pdf sia decrescente come gia accadeva nell’esperimento con SystemTAP.Ci sono comunque due piccole regioni corrispondenti ad un numero di chiamate superiore a70 in cui la probabilita e non nulla seppur molto bassa. Questi picchi lontani sono dovutiprobabilmente alla natura ciclica del benchmark4 che periodicamente sforza il sistema in modomaggiore ma per breve durata; questo aspetto si riflette anche sul valor medio µ = 69.68 esulla deviazione standard σ = 221.7. Valori tanto elevati di questi due parametri sono dovutianche al fatto che, sempre a causa della natura del benchmark, in certi intervalli di un secondovengono effettuati fino ad un massimo di 4419 chiamate come si evince dall’informazionerelativa al massimo numero di chiamate in un secondo (Max) riportata anch’essa nel titolo

4Oltre ai motivi gia ricordati nella sezione relativa a SystemTAP.

Page 115: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 114

Figura 4.8: Pdf delle chiamate ogni secondo nel caso CPU bound.

del grafico. Naturalmente e molto bassa la probabilita che in un secondo sia effettuato unnumero cosı alto di chiamate e proprio per questo motivo si e deciso di fissare la massimaascissa rappresentabile a 150 onde non comprimere troppo il grafico che presenta valori diversida zero solo entro tale limite.

Ma possiamo dire anche in questo caso che la pdf si distribuisce in maniera esponenziale?Analizzando il grafico sembrerebbe di sı ma per giustificare tale risposta eseguiamo il pro-cedimento di identificazione dei campioni specificando l’esponenziale come base di confrontoottenendo cosı la figura 4.9.

Anche in questo caso la maggior parte dei punti coincide con la retta di riferimento fino alpercentile 97/98-esimo e gli altri punti formano due rette parallele. L’unica differenza col casoSystemTAP e che i punti distribuiti in alto sono in numero inferiore ma cio e legato al fattoche nell’esperimento con DSKI viene generato un numero inferiore di campioni (sia perche lesystem call monitorate sono solo 10 sia perche l’esperimento dura di meno). Anche in tal casocomunque la curva e un’iperesponenziale e quindi la pdf segue effettivamente l’andamentoesponenziale.

Analizziamo a questo punto i risultati relativi alla percentuale di chiamata delle singolesystem call. Applicato il filtro otterremo la figura 4.10 generata da gnuplot. Dal grafico

Page 116: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 115

Figura 4.9: Comparazione della pdf con la distribuzione esponenziale, caso CPU bound.

risulta che oltre alle system call di I/O che risultano inevitabilmente invocate5 la system callpiu stressata e la rt sigaction che indubbiamente puo rientrare tra le system call maggior-mente stressate da un worload CPU bound perche seve a gestire i segnali che si scambianoi processi. La system call brk che si occupa di ridimensionare i segmenti dati dei processi einvocata pochissime volte e questo e coerente con quanto ci si aspetta dal carico impiegato.

Resta infine da esaminare la situazione relativa ai codici di uscita delle singole system call.Tale informazioni vengono elencate nella tabella 4.13.

Il significato dei codici di uscita viene mostrato nell’appendice C. Dalla tabella si evinceche la maggior parte delle chiamate termina a buon fine (alcune system call terminano semprecon successo) e solo una piccola percentuale termina in modo “anomalo”. Precisiamo che nonsi tratta di veri e propri insuccessi ma di situazioni particolari che possono ritenersi anchenella norma da certi punti di vista. La system call che termina con piu “variabilita” e di sicurola ioctl e questo non solo perche essa resta una di quelle piu invocate ma anche perche vieneusata per manipolare una miriade di caratteristiche operative relative ai file o ai device.

4.2.2 Caso IO bound

Utilizzando un workload che stressa il sistema di I/O e normale aspettarsi che il numero dichiamate alle system call fatte ogni secondo sia maggiore che nel caso in cui si usi un workload

5L’inevitabilita della loro invocazione e legata intrinsecamente al meccanismo di funzionamento di DSKI.

Page 117: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 116

Figura 4.10: Percentuale di chiamata delle system call nel caso CPU bound.

che sforzi la CPU. Questa previsione e confermata dalla figura 4.11 che mostra la pdf relativaalle chiamate per secondo.

Rispetto al caso CPU bound la probabilita maggiore e che si abbiano tra le 20 e le 40chiamate in un secondo quindi quasi il doppio rispetto a prima. Inoltre la pdf, che ha in ognicaso un andamento decrescente, e piu distribuita lungo l’asse delle ascisse perche aumentala probabilita che le chiamate possano essere in numero elevato mentre nel caso CPU boundin molti intervalli la probabilita era proprio nulla. La media in tal caso raggiunge il valoreµ = 219 mentre la deviazione standard arriva a σ = 536.8 e cio anche in conseguenza delfatto che il massimo numero di chiamate al secondo registrate stavolta raggiunge addiritturale 5824 unita ben 1400 in piu di prima.

La pdf ottenuta non differisce molto da quella dell’esperimento con SystemTAP ad ecce-zione del fatto che i picchi piu alti non partono dall’origine ma sono leggermente spostati adestra. Ci si aspetta quindi che anche in tal caso non sia possibile riconoscere nella pdf unafunzione nota. Questa previsione e confermata dalle figure 4.13 e 4.14. La prima mostra ilrisultato di comparazione con la distribuzione esponenziale, la seconda con quella normale.In entrambi i casi i punti sono abbastanza lontani dalle rette di riferimento e ancora una voltaquesto distacco e maggiore nel caso in cui il confronto viene eseguito con la curva normale.Si puo concludere quindi che, anche in tal caso, la pdf non assume un andamento noto ma disicuro assomiglia piu ad un’esponenziale che ad una normale.

Page 118: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 117

Tabella 4.13: Codici di uscita nel caso CPU bound.ErrorName Name Occorrenze Totale PercRel PercAssOK SYS BRK 6876 6876 100.00 2.74OK SYS CLOSE 52961 56369 93.95 21.12EBADF SYS CLOSE 3408 56369 6.05 1.36OK SYS IOCTL 24166 32060 75.38 9.64EPERM SYS IOCTL 1 32060 0.00 0.00EAGAIN SYS IOCTL 240 32060 0.75 0.10EINVAL SYS IOCTL 3629 32060 11.32 1.45ENOTTY SYS IOCTL 424 32060 1.32 0.17EADDRNOTAVAIL SYS IOCTL 3600 32060 11.23 1.44OK SYS LLSEEK 895 896 99.89 0.36ESPIPE SYS LLSEEK 1 896 0.11 0.00OK SYS MMAP2 30878 30878 100.00 12.31OK SYS OPEN 21312 22100 96.43 8.50ENOENT SYS OPEN 738 22100 3.34 0.29ENXIO SYS OPEN 50 22100 0.23 0.02OK SYS READ 23348 23348 100.00 9.31OK SYS RT SIGACTION 48780 48786 99.99 19.45EINVAL SYS RT SIGACTION 6 48786 0.01 0.00OK SYS SELECT 5469 5469 100.00 2.18OK SYS WRITE 23985 23985 100.00 9.56

Analizziamo quindi il secondo grafico relativo alla percentuale di chiamata delle systemcall e mostrato in figura 4.12. Il grafico e perfettamente coerente con quanto ci si aspettaperche circa il 90% delle chiamate e distruibuito tra read, write e llseek ossia le principalisystem call di I/O.

La tabella 4.14 infine mostra i risultati relativi ai codici d’uscita. Anche in questo caso icodici sono piu o meno gli stessi e la system call con piu variabilita resta la ioctl nonostantenon sia, in questo caso, la piu invocata (e “solo” al quarto posto); e confortante pero il fattoche, come nell’esperimento IO bound gia descritto, le tre system call piu invocate termininosempre con successo (a parte qualche volta la llseek) e cio sicuramente riflette la natura“stabile” del kernel su cui sono stati eseguiti gli esperimenti.

4.2.3 Caso MEMORY bound

Il workload impiegato per stressare le system call che operano sulla memoria e descritto nellasezione 3.2.3 da cui si evince che esso e molto lineare in quanto non fa che chiedere memoriafinche non si comincia ad “intaccare” l’area di swap. Prima di mostrare i risultati ottenutibisogna rimarcare un aspetto estremamente importante. Come detto nella sezione 3.1 DSKIe ancora in fase sperimentale e si puo notare infatti che in particolari situazioni alcuni eventivengono persi nel senso che non arrivano al buffer seppur generati a livello kernel. Questasituazione accade in casi molto particolari e precisamente quando la frequenza con cui sigenera un evento e elevatissima. In tali casi, infatti, applicando al file binario un filtro dinarrazione si otterra un xml che elenca gli eventi catturati; ebbene i numeri che identificano

Page 119: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 118

Figura 4.11: Pdf delle chiamate ogni secondo nel caso IO bound.

gli eventi non sono tutti progressivi ma in alcuni punti ci sono dei vuoti. Ad esempio ci sonotutti gli eventi da 1 a 145 tranne qualcuno in mezzo. Il workload usato negli esperimentiMEMORY bound e per natura un workload insistente, che chiede continuamente memoriaquindi sicuramente devono essere catturati a livello kernel tantissimi eventi. Eseguendo ilworkload e stato possibile notare che, per i motivi appena indicati, molti eventi vengonoperduti. Questo fatto ci ha portato a cambiare leggermente il workload per ridurre il numerodi eventi generati. Naturalmente questo significa che i risultati dovranno essere interpretatiin maniera diversa per tenere conto di questo cambiamento. L’unica modifica apportata estata l’introduzione di una pausa tra una richiesta di 2.1 GB e la successiva (dopo il rilascioovviamente). In pratica si richiama la procedura usleep()6 che fa riposare il sistema perun certo numero di microsecondi. Il valore in questione e pari a 100000 µs ossia un decimodi secondo. In tal modo le richieste diventano meno insistenti e si perdono meno eventi.Data la natura del workload comunque ci si aspetta che il numero di system call invocatesia abbastanza costante in ogni secondo. La figura 4.15, che mostra la pdf nel caso in cui siutilizzi tale carico, conferma pienamente ogni previsione in quanto la probabilita di avere uncerto numero di chiamate al secondo e tutta concentrata tra 40 e 50 chiamate. L’andamentostavolta non e simile ad un esponenziale decrescente ma si puo approssimare ad una gaussiana.

6Si tenga presente che la chiamata di tale procedura non inquina i nostri risultati perche essa non richiamaalcuna system call tra le 10 monitorate con DSKI.

Page 120: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 119

Figura 4.12: Percentuale di chiamata delle system call nel caso IO bound.

Certamente il numero di chiamate che ha maggiore probabilita di occorrere e superiore aicasi esaminati in precedenza e questo e dovuto al fatto che il workload richiede in maniera“soffocante” memoria al sistema. Questa insistenza e pero molto continua in quanto il valormedio stavolta e pari a µ = 45.13 chiamate al secondo cioe e compreso nell’intervallo deivalori che hanno la piu alta probabilita di capitare. Il valore della deviazione standard risultanettamente inferiore ai casi precedenti essendo pari solo a σ = 78.82 e anche il massimonumero di chiamate non supera le 2300 unita (2267 per l’esattezza). Se consideriamo lacurva come una normale possiamo allora affermare che con un fattore di copertura k = 3c’e il 99.7% delle probabilita che in un secondo il numero di chiamate stia nell’intervallo[1, 45 + 3 ∗ 78] ≈ [1, 280]7. In parole povere e rarissimo (0.3% delle probabilita) che in 1secondo vengano effettuate piu di 280 chiamate alle system call monitorate.

Confrontando la pdf con quella ottenuta nella sezione 4.1.3 si notera comunque che la nuovapdf e spostata verso sinistra cosı come si evince anche dal valor medio. Questa differenzae legata alla modifica apportata al workload ma si puo facilmente azzerare correggendo irisultati. Avendo inserito una pausa di un decimo di secondo, per avere risultati comparabili alcaso precedente bisogna considerare il numero di chiamate ogni 10 secondi. Allora applichiamo

7Matematicamente parlando l’intervallo dovrebbe essere approssimabile a [−191, 280] ma ovviamente l’e-sperimento non contempla un numero di chiamate non positivo quindi l’estremo sinistro deve essere posto a1.

Page 121: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 120

Figura 4.13: Comparazione della pdf con la distribuzione esponenziale, caso IO bound.

il filtro inserendo un intervalo di 10 secondi e non 1; il risultato e riportato nella figura 4.16.Il risultato mostrato stavolta e paragonabile a quello ottenuto nell’esperimento analogo conl’impiego di KProbes/SystemTAP. La media risulta µ = 449.3 e la deviazione standard eσ = 504.6 quindi valori vicini a quelli ottenuti in precedenza (526.74 e 621.7 rispettivamente).

Ma quale sara la system call piu invocata? La risposta ci viene fornita dalla figura 4.17 chemostra le percentuali di chiamata. Il premio della system call piu invocata stavolta spetta,come nell’esperimento MEMORY bound gia descritto, alla brk che copre circa il 22% deltotale. Questo e dovuto al fatto che il workload non fa altro che chiedere e rilasciare memoriae la brk svolge appunto l’operazione di allocazione (deallocazione) di memoria per i processiaumentando (diminuendo) il segmento dati relativo. Naturalmente la percentuale non arrivaai valori dell’esperimento analogo gia eseguito ma questo non e dovuto al fatto che e stataapportata la modifica ma e legato alla natura del meccanismo di DSKI. Come precisato nellasezione ?? esso registra i dati su un dispositivo a caratteri quindi scrive su di esso mentreparallelamente il demone legge; questo spiega la percentuale di chiamata cosı alta delle systemcall di IO, anche in conseguenza del fatto che il carico genera tantissimi eventi e quindi siscrive tantissimo sul dispositivo. La tabella 4.15, infine, mostra i codici d’uscita ottenuti conil carico che stressa la memoria.

I valori ottenuti non differiscono molto dagli altri casi, segno che e normale che certeanomalie si verifichino; conforta ancora il fatto che la brk, la system call piu invocata, nontermini mai in modo anomalo.

Page 122: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.2. Risultati DSKI Capitolo 4. Risultati sperimentali 121

Tabella 4.14: Codici di uscita nel caso IO bound.ErrorName Name Occorrenze Totale PercRel PercAssOK SYS BRK 12 12 100.00 0.00OK SYS CLOSE 14007 14055 99.66 3.12EBADF SYS CLOSE 48 14055 0.34 0.01OK SYS IOCTL 10829 14275 75.86 2.41EAGAIN SYS IOCTL 112 14275 0.78 0.02EINVAL SYS IOCTL 1669 14275 11.69 0.37ENOTTY SYS IOCTL 1 14275 0.01 0.00EADDRNOTAVAIL SYS IOCTL 1664 14275 11.66 0.37OK SYS LLSEEK 115283 115371 99.92 25.65EINVAL SYS LLSEEK 87 115371 0.08 0.02ESPIPE SYS LLSEEK 1 115371 0.00 0.00OK SYS MMAP2 1858 1858 100.00 0.41OK SYS OPEN 3967 3976 99.77 0.88ENOENT SYS OPEN 7 3976 0.18 0.00ENXIO SYS OPEN 2 3976 0.05 0.00OK SYS READ 172009 172009 100.00 38.28OK SYS RT SIGACTION 4746 4746 100.00 1.06OK SYS SELECT 2460 2460 100.00 0.55OK SYS WRITE 120619 120619 100.00 26.84

Tabella 4.15: Codici di uscita nel caso MEMORY bound.ErrorName Name Occorrenze Totale PercRel PercAssOK SYS BRK 36057 36057 100.00 22.29OK SYS CLOSE 32037 32073 99.89 19.81EBADF SYS CLOSE 36 32073 0.11 0.02OK SYS IOCTL 22959 30301 75.77 14.19EAGAIN SYS IOCTL 235 30301 0.78 0.15EINVAL SYS IOCTL 3542 30301 11.69 2.19ENOTTY SYS IOCTL 39 30301 0.13 0.02EADDRNOTAVAIL SYS IOCTL 3526 30301 11.64 2.18OK SYS LLSEEK 76 183 41.53 0.05ESPIPE SYS LLSEEK 107 183 58.47 0.07OK SYS MMAP2 8268 8268 100.00 5.11OK SYS OPEN 9988 11962 83.50 6.17ENOENT SYS OPEN 1963 11962 16.41 1.21ENXIO SYS OPEN 11 11962 0.09 0.01OK SYS READ 17577 17577 100.00 10.87OK SYS RT SIGACTION 10618 10618 100.00 6.56OK SYS SELECT 5245 5245 100.00 3.24OK SYS WRITE 9473 9473 100.00 5.86

Page 123: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.3. Conclusioni Capitolo 4. Risultati sperimentali 122

Figura 4.14: Comparazione della pdf con la distribuzione normale, caso IO bound.

4.3 Conclusioni

Scopo di questo testo era quello di analizzare il framework di strumentazione KProbes/SystemTAP,studiarne il funzionamento interno, confrontarlo con altri tools analoghi (nel nostro casoDSKI) e applicarlo concretamente ad un caso reale.

I risultati ottenuti dagli esperimenti effettuati permettono di trarre una serie di conclu-sioni. In primo luogo e possibile osservare una sostanziale coincidenza tra i risultati ottenutidai tool indipendentemente, il che implica una effettiva equivalenza di questi ultimi. Infatti,anche se per il tool DSKI e stato necessario modificare leggermente l’esperimento MemoryBound, in quanto l’eccessiva velocita con cui gli eventi venivano generati comprometteva lavalidita dei risultati, i dati ottenuti rispecchiano una effettiva corrispondenza. Pertanto, unprogrammatore puo scegliere indifferentemente uno dei due tool per indagare e analizzare ilfunzionamento del kernel, dal momento che i risultati saranno identici. Le differenze sorgo-no sul piano del procedimento di strumentazione; da questo punto di vista entrambi i toolpresentano vantaggi e svantaggi. KProbes/SystemTAP ha come punto di forza la capacitadi poter inserire dinamicamente punti di strumentazione nell’immagine del kernel, evitan-do all’utente l’onere della ricompilazione, ma d’altro canto fornisce uno scarso supporto allaraccolta e al post–processing dei dati. DSKI, invece, adoperando l’intelligente astrazione didatastream, fornisce un supporto all’analisi statistica dei dati notevole, ma l’inserimento dipunti di strumentazione non e cosı semplice, e richiede una ricompilazione del kernel; questo

Page 124: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.3. Conclusioni Capitolo 4. Risultati sperimentali 123

Figura 4.15: Pdf delle chiamate ogni secondo nel caso MEM bound.

fatto si traduce nell’impossibilita di utilizzare DSKI per ispezioni rapide del kernel. Da questopunto di vista, uno sviluppo futuro potrebbe essere quello di poter integrare le caratteristichevincenti di entrambi i tool in un unico strumento al servizio dello sviluppatore di sistema.

In seconda analisi, l’interpretazione dei risultati ottenuti comporta una serie di interessanticonsiderazioni. Le distribuzioni di probabilita ottenute analizzando i dati dimostrano unasostanziale corrispondenza tra i risultati previsti per ogni tipo di carico e quelli sperimentali,il che implica la validita degli strumenti adoperati. Inoltre, e possibile riscontrare una certastazionarieta degli esperimenti considerati il che implica la loro ripetibilita. Quest’ultimacaratteristica risulta essere importante, dal momento che conferma la validita di utilizzaredei workload come strumento di indagine di un sistema; in altre parole, si considera il kernelcome una scatola nera che sottoposta ad un determinato input fornisca in uscita dei datiche e possibile adoperare per diagnosticare possibili anomalie di funzionamento. Osservandoi codici di errore che le system call restituiscono, risulta che solo in una esigua percentualedei casi essi sono riconducibili a situazioni anomale, il che conferma il fatto che il kernelstrumentato sia un kernel stabile; del resto gli stessi codici di uscita riportati risultano esserepressoche gli stessi in tutti i casi, e pertanto sono indipendenti in tal senso dal particolareworkload o dal tool impiegato. Da questo punto di vista, l’analisi dei codici di uscita dellesystem call puo essere considerata come valido approccio metodologico per l’individuazione dicomportamenti anomali del kernel. In tal senso uno sviluppo futuro potrebbe essere quello di

Page 125: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.3. Conclusioni Capitolo 4. Risultati sperimentali 124

Figura 4.16: Pdf delle chiamate ogni 10 secondi caso MEM bound.

tracciare una correlazione statistica tra workload impiegati e codici di uscita riportati, cosı dapoter riscontrare sulla base dei risultati ottenuti anomalie del kernel in maniera piu rapida.

Page 126: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

4.3. Conclusioni Capitolo 4. Risultati sperimentali 125

Figura 4.17: Percentuale di chiamata delle system call nel caso MEMORY bound.

Page 127: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Appendice A

Ulteriori esempi

A.1 Kprobes - Strumetazione di un character device driver

In questo esempio mostreremo come utilizzare kprobe per strumentare un modulo kernel. Ilmodulo in questione crea un dispositivo a caratteri che non supporta la scrittura, ma che ognivolta che si invoca l’operazione di lettura su di esso restituisce il numero di volte che e statoletto. Il dispositivo a caratteri di questo esempio e molto semplice; si compone di un unicofile C, simpledev.c, in cui sono implementate sei funzioni:

static int init prova module initialization(void); Procedura di inizializzazione delmodulo, invocata nel momento in cui si effettua insmod <nome modulo>.ko.

static void exit prova module cleanup(void); Procedura di terminazione del modu-lo, invocata nel momento in cui viene scaricato dal kernel tramite il comando rmmod<nome modulo>.ko.

static int device open(struct inode*, struct file*); Funzione invocata nel momen-to in cui qualche processo apre, tramite la system call open, il device file.

static int device release(struct inode*, struct file*); Funzione invocata nel mo-mento in cui un processo, che aveva aperto il device file, lo chiude con la system callclose.

static ssize t device read(struct file*, char *, size t, loff t *); Funzione in-vocata per la lettura dei dati, attraverso la system call read.

static ssize t device write(struct file*, const char *, size t, loff t *); Funzioneinvocata per la scrittura dei dati.

Le prime due funzioni sono necessarie per ogni modulo, in quanto ne rappresentano leprocedure di inizializzazione e terminazione. Le atre funzioni sono richieste per creare undevice driver, creando una variabile di tipo struct file operations che incapsula tutte leinformazioni necessarie per la registrazione del device. Tale registrazione avviene in manieradinamica attraverso la funzione register chrdev, che restituisce il Major Number del device.

Il listato del file simpledev.c viene riportato di seguito:

126

Page 128: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.1. Kprobes - Strumetazione di un character device driver Capitolo A. Ulteriori esempi 127

#include <linux/module.h>/* Necessario per i moduli */#include <linux/kernel.h>/* Header principale del Kernel */#include <linux/fs.h>/* Header del sottosistema filesystem */#include <asm/uaccess.h>/* Necessario per put_user */

/* Macro per definire le informazioni del modulo */MODULE_AUTHOR("Paolo Guadagnuolo, Cristofaro Gozzolino");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Prova di un semplice device driver");

/* Prototipi */static int __init prova_module_initialization(void);static void __exit prova_module_cleanup(void);static int device_open(struct inode*, struct file*);static int device_release(struct inode*, struct file*);static ssize_t device_read(struct file*, char *, size_t, loff_t *);static ssize_t device_write(struct file*, const char *, size_t, loff_t *);

#define SUCCESS 0#define PROVA_DEVICE_NAME "provadevice"#define BUF_LEN 80

/* Memorizza il Major Number */static int Major;

/* Flag per indicare che il device e occupato */static int Device_Open = 0;

/* Buffer di caratteri */static char msg[BUF_LEN];static char *msg_Ptr;

/* Strutture file_operations per definire le operazioni sul device */static struct file_operations fops = {

.read = device_read,

.write = device_write,

.open = device_open,

.release = device_release};

/* Routine di inizializzazione del modulo */static int __init prova_module_initialization(void) {

/* Tenta di ottenere dinamicamente il Major Number */Major = register_chrdev(0, PROVA_DEVICE_NAME, &fops);

if (Major < 0) {

Page 129: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.1. Kprobes - Strumetazione di un character device driver Capitolo A. Ulteriori esempi 128

/* L’assegnazione del Major e fallita */printk(KERN_ALERT "Impossibile registrare il device %d\n", Major);return Major;

}

printk(KERN_INFO "E’ stato assegnato il Major Number %d.\n", Major);

return SUCCESS;}

/* Routine di cleanup del modulo */static void __exit prova_module_cleanup(void) {

/* Rimuove il character device */int ret = unregister_chrdev(Major, PROVA_DEVICE_NAME);

if (ret < 0)/* La rimozione e fallita */

printk(KERN_ALERT "Impossibile deregistrare il device %d\n", ret);}

/* Invocata quando si accede al device */static int device_open(struct inode *inode, struct file *file) {

/* Contatore delle letture */static int counter = 0;

if (Device_Open)/* Il dispositivo e occupato */return -EBUSY;

/* Alza il flag di occupazione */Device_Open++;

sprintf(msg, "Il messaggio e stato letto %d volte.\n", counter++);msg_Ptr = msg;

/* Aumenta di 1 il contatore dei processi che attualmente utilizzanoil device */

try_module_get(THIS_MODULE);

return SUCCESS;}

/* Invocata quando viene rilasciato il device */static int device_release(struct inode *inode, struct file *file) {

/* Abbassa il flag di occupazione */

Page 130: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.1. Kprobes - Strumetazione di un character device driver Capitolo A. Ulteriori esempi 129

Device_Open--;

/* Decrementa il contatore dei processi che attualmente utilizzanoil device */

module_put(THIS_MODULE);return 0;

}

/* Invocata per la lettura */static ssize_t device_read(struct file *filp, char *buffer, size_t length,

loff_t * offset){

/* Numero di byte scritti nel buffer */int bytes_read = 0;

/* Se si e raggiunta la fine del messaggio ritorna 0 */if (*msg_Ptr == 0)

return 0;

while (length && *msg_Ptr) {/** Dal momento che il buffer in cui e memorizzato il messaggio* si trova nello spazio di indirizzamento del kernel, e necessario* prima di passarlo all’utente, copiarlo nello spazio di indirizzamento* dell’utente attraverso la funzione dipendente dall’architettura* put_user*/

put_user(*(msg_Ptr++), buffer++);length--;bytes_read++;

}

/* Restituisce il numero di byte letti */return bytes_read;

}

/* Invocata per la scrittura *//* Attualmente non implementata nel modulo */static ssize_tdevice_write(struct file *filp, const char *buff, size_t len, loff_t * off){

printk(KERN_ALERT "Spiacente, questa operazione non e supportata.\n");return -EINVAL;

}

/* Indica quali sono le routine di inizializzazione e di cleanup */module_init(prova_module_initialization);

Page 131: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.1. Kprobes - Strumetazione di un character device driver Capitolo A. Ulteriori esempi 130

module_exit(prova_module_cleanup);

Per poter compilare questo modulo come modulo esterno bisogna realizzare un file Makefiledi questo tipo:

obj-m += simpledev.o

all:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Eseguendo il comando make, il modulo verra compilato generando il file simpledev.ko.Utilizzando il comando insmod simpledev.ko, il modulo verra caricato e se non si sonoverificati errori, al termine del file /var/log/messages, apparira una riga di questo tipo:

Feb 1 12:30:37 localhost kernel: E’ stato assegnato il Major Number 253.

Questo ci indica che il kernel ha assegnato il Major Number n◦ 253 al nostro device driver.Per poterlo utilizzare, bisogna creare un file speciale attraverso un comando del tipo mknod/dev/prova c 253 0. Adesso siamo pronti ad utilizzare il device file.

Se proviamo ad utilizzare il comando cat /dev/prova, apparira un messaggio di questotipo:

Il messaggio e stato letto 6 volte.

A.1.1 Strumentazione del character device

Vogliamo adesso strumentare il modulo realizzato nella sezione precedente, in particolarevogliamo strumentare la funzione di lettura device read. Per poter utilizzare kprobe enecessario includere l’header linux/kprobes.h nel file simpledev.c.

Le funzioni che andremo ad aggiungere al file sono:

int handler pre(struct kprobe *kp, struct pt regs *regs); Routine di pre–handling.

void handler post(struct kprobe *kp, struct pt regs *regs, unsigned long flags);Routine di post–handling.

int handler fault(struct kprobe *kp, struct pt regs *regs, int trapnr); Routinedi fault–handling.

La registrazione del probing point si effettua in maniera molto semplice. Per prima cosasi riempiono i campi della struttura dati kprobes kp attraverso il codice:

static struct kprobe kp = {.pre_handler = handler_pre,.post_handler = handler_post,.fault_handler = handler_fault,

};

Page 132: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.1. Kprobes - Strumetazione di un character device driver Capitolo A. Ulteriori esempi 131

quindi si imposta la locazione del probing point:

kp.addr = (kprobe_opcode_t *) &device_read;

Fatto questo, bisogna semplicemente registrare il probing point nella routine di inizializ-zazione, e rimuoverlo in quella di cleanup:

/* Codice per la registrazione */register_kprobe(&kp);/* Codice per la cancellazione */unregister_kprobe(&kp);

Riportiamo quindi le righe del file simpledev.c in cui viene inserito il codice necessarioper la strumentazione:

...

#include <linux/kprobes.h> /* Neseccario per usare kprobes*/

...

/* Prototipi handler KPROBES */int handler_pre(struct kprobe *kp, struct pt_regs *regs);void handler_post(struct kprobe *kp, struct pt_regs *regs, unsigned long flags);int handler_fault(struct kprobe *kp, struct pt_regs *regs, int trapnr);

...

/* Struttura kprobe */static struct kprobe kp = {

.pre_handler = handler_pre,

.post_handler = handler_post,

.fault_handler = handler_fault,};

...

/* Routine di inizializzazione del modulo */static int __init prova_module_initialization(void) {

...

printk(KERN_INFO "E’ stato assegnato il Major Number %d.\n", Major);

kp.addr = (kprobe_opcode_t *) &device_read;if (register_kprobe(&kp)) {

printk(KERN_ALERT "Impossibile registrare il breakpoint.\n");return -1;

Page 133: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.1. Kprobes - Strumetazione di un character device driver Capitolo A. Ulteriori esempi 132

};

return SUCCESS;}

/* Routine di cleanup del modulo */static void __exit prova_module_cleanup(void) {

unregister_kprobe(&kp);

...}

/* Implementazione handler KPROBES */int handler_pre(struct kprobe *kp, struct pt_regs *regs) {

printk(KERN_INFO "Invocato PRE_HANDLER.\n");

printk(KERN_INFO "PID del processo accedente: %d\n", current->pid);printk(KERN_INFO "PID del padre del processo accedente: %d\n",

current->parent->pid);

printk(KERN_INFO "Contenuto dei registri general purpouse:\n");printk(KERN_INFO "EAX: 0x%lx\n", regs->eax);printk(KERN_INFO "EBX: 0x%lx\n", regs->ebx);printk(KERN_INFO "ECX: 0x%lx\n", regs->ecx);printk(KERN_INFO "EDX: 0x%lx\n", regs->edx);printk(KERN_INFO "ESP: 0x%lx\n", regs->esp);printk(KERN_INFO "EBP: 0x%lx\n", regs->ebp);printk(KERN_INFO "ESI: 0x%lx\n", regs->esi);printk(KERN_INFO "EDI: 0x%lx\n", regs->edi);printk(KERN_INFO "EFLAGS: 0x%lx\n", regs->eflags);printk(KERN_INFO "Contenuto dei segment selectors:\n");printk(KERN_INFO "CS: 0x%x\n", regs->xcs);printk(KERN_INFO "DS: 0x%x\n", regs->xds);printk(KERN_INFO "SS: 0x%x\n", regs->xss);printk(KERN_INFO "ES: 0x%x\n", regs->xes);

/* I selettori di segmento FS e GS non sono utilizzati da Linux */

return 0;}

void handler_post(struct kprobe *kp, struct pt_regs *regs, unsigned long flags) {printk(KERN_INFO "Invocato POST_HANDLER.\n");

}

int handler_fault(struct kprobe *kp, struct pt_regs *regs, int trapnr) {printk(KERN_INFO "Invocato FAULT_HANDLER.\n");

Page 134: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.2. SystemTAP - Probing delle operazioni su partizione ext3 Capitolo A. Ulteriori esempi 133

return 0;}

...

A questo punto, compilando e caricando il modulo, ogni volta che si tenta di leggere daldispositivo /dev/prova nel file /var/log/messages appariranno righe di questo tipo:

Feb 1 13:30:16 localhost kernel: PID del processo accedente: 5717Feb 1 13:30:16 localhost kernel: PID del padre del processo accedente: 4604Feb 1 13:30:16 localhost kernel: Contenuto dei registri general purpouse:Feb 1 13:30:16 localhost kernel: EAX: 0xcddca780Feb 1 13:30:16 localhost kernel: EBX: 0xcddca780Feb 1 13:30:16 localhost kernel: ECX: 0x1000Feb 1 13:30:16 localhost kernel: EDX: 0x804e858Feb 1 13:30:16 localhost kernel: ESP: 0xc0159898Feb 1 13:30:16 localhost kernel: EBP: 0x804e858Feb 1 13:30:16 localhost kernel: ESI: 0xdeab30c7Feb 1 13:30:16 localhost kernel: EDI: 0x1000Feb 1 13:30:16 localhost kernel: EFLAGS: 0x200282Feb 1 13:30:16 localhost kernel: Contenuto dei segment selectors:Feb 1 13:30:16 localhost kernel: CS: 0x60Feb 1 13:30:16 localhost kernel: DS: 0x43e3007bFeb 1 13:30:16 localhost kernel: SS: 0xd116ffa4Feb 1 13:30:16 localhost kernel: ES: 0x1f07007bFeb 1 13:30:16 localhost kernel: Invocato POST_HANDLER.

A.2 SystemTAP - Probing delle operazioni su partizione ext3

In questa sezione ci preoccupiamo di impiegare l’infrastruttura fornita da SystemTAP, attra-verso il proprio linguaggio di scripting, per monitorare alcune tra le piu frequenti operazioniche si eseguono su un file system: creazione/calcellazione di directory e spostamento file. Inparticolare non siamo interessati a probare le suddette operazioni su un qualunque filesystemma esclusivamente su quello di tipo ext3. Sia dato quindi il seguente file di scripting:

# stapex01.stp

/* Dichiarazione di tutte le variabili* globali che saranno usate nel file* per immagazzinare il numero di operazioni* (mk, rm, mv) e per memorizzare gli* istanti di inizio e fine.*/

global mk, rm, mv, start, end

Page 135: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.2. SystemTAP - Probing delle operazioni su partizione ext3 Capitolo A. Ulteriori esempi 134

/* Quando il modulo viene caricato* resettiamo tutte le variabili a zero.*/

probe begin{print("START PROBING\n")delete mkdelete rmdelete mvdelete startdelete endstart = gettimeofday_s()

}

/* Probe che cattura la creazione di* una directory sulla partizione ext3.*/

probe module("ext3").function("ext3_mkdir"){msg = sprintf(" E’ stata creata una

nuova directory con un nome di %d caratteri.\n",$dentry->d_name->len)

print(msg)mk++

}

/* Probe che cattura la cancellazione di* una directory sulla partizione ext3.*/

probe module("ext3").function("ext3_rmdir"){msg = sprintf(" E’ stata cancellata una

directory con un nome di %d caratteri.\n",$dentry->d_name->len)

print(msg)rm++

}

/* Probe che cattura lo spostamento* (move) di un file o directory* sulla partizione ext3.*/

probe module("ext3").function("ext3_rename"){

msg1 = sprint(" E’ stato rilevato lospostamento di un file (o di una directory)!\n")

Page 136: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.2. SystemTAP - Probing delle operazioni su partizione ext3 Capitolo A. Ulteriori esempi 135

msg2 = sprintf(" -Il file iniziale ha un nomecostituito da %d caratteri\n", $old_dentry->d_name->len)

msg3 = sprintf(" -Il file di destinazione ha un nome lungo%d caratteri\n", $new_dentry->d_name->len)

msg = msg1.msg2.msg3print(msg)mv++

}/* Alla fine viene mostrato il numero* totale di ciascuna operazione eseguita* sulla partizione ext3 nel tempo specificato.*/

probe end{end = gettimeofday_s()print("END PROBING\n")printf("Numero di operazioni eseguite sullapartizione ext3 in %d secondi:\n %d directorycreate\n %d directory cancellate\n %d file(s)spostato(i) o ridenominato(i).\n", (end-start), mk, rm, mv)

}

E’ abbastanza semplice descrivere il comportamento che ci aspettiamo. In pratica vieneinserito un punto di probe all’inizio di tre funzioni del modulo ext3. Mostriamo quindi l’elencodelle operazioni e il relativo comando da invocare per richiamarle dalla shell:

• funzione: static int ext3 mkdir(struct inode ∗ dir, struct dentry ∗ dentry,int mode)comando: mkdir <nome>

• funzione: static int ext3 rmdir (struct inode ∗ dir, struct dentry ∗ dentry)comando: rmdir <nome> oppure rm <nome> -rf su piu livelli

• funzione: static int ext3 rename (struct inode ∗ old dir, struct dentry ∗old dentry, struct inode ∗ new dir, struct dentry ∗ new dentry)comando: mv <nome1> <nome2>

Tutte le funzioni elencate sono implementate per il modulo di filesystem ext3 e si trovanoprecisamente nel sorgente fs/ext3/namei.c. E’ probabile che altri filesystem le implementi-no in maniera un po diversa, ma di sicuro sono operazioni messe a disposizione da qualunquefilesystem. Il file di scripting specificato quindi va a monitorare l’uso di queste tre funzionie fornisce ogni volta qualche piccola informazione relativa alla chiamata. Ad esempio vienemostrato ogni volta la lunghezza del nome del file o della directory che subisce l’operazio-ne. Questa informazione si ricava dal parametro di tipo dentry (che ha lo stesso nome deltipo nelle prime due funzioni) e piu precisamente dal campo len del campo d name (di tipoqstr) della struttura dentry1. Alla fine viene fatto un resoconto del numero di operazioni e

1Le strutture dentry e qstr sono definite in linux/dcache.h

Page 137: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.2. SystemTAP - Probing delle operazioni su partizione ext3 Capitolo A. Ulteriori esempi 136

sfruttiamo la chiamata speciale gettimeofday s() del linguaggio di scripting per valutare ladurata (in secondi) del monitoraggio.

Si provi quindi a digitare il seguente comando dove definiamo una lunghezza massima perle stringhe pari a 200 caratteri2.

stap stapex01.stp -DMAXSTRINGLEN=200

A questo punto non resta che provare ad eseguire qualche operazione. Ad esempio, appenacompare il messaggio START PROBING, eseguiamo la seguente sequenza di comandi su unapartizione formattata ext3:

# mkdir gennaio# mkdir dicembre# mkdir marzo# mv marzo ./dicembre/aprile# rmdir gennaio# rm dicembre -rf

Supponendo che nessun altro processo stia facendo qualche operazione sulla partizioneext3, digidando CTRL+C otterremo il seguente risultato:

START PROBINGE’ stata creata una nuova directory con un nome di 7 caratteri.E’ stata creata una nuova directory con un nome di 8 caratteri.E’ stata creata una nuova directory con un nome di 5 caratteri.E’ stato rilevato lo spostamento di un file (o di una directory)!-Il file iniziale ha un nome costituito da 5 caratteri-Il file di destinazione ha un nome lungo 6 caratteriE’ stata cancellata una directory con un nome di 7 caratteri.E’ stata cancellata una directory con un nome di 6 caratteri.E’ stata cancellata una directory con un nome di 8 caratteri.END PROBINGNumero di operazioni eseguite sulla partizione ext3 in 25 secondi:3 directory create3 directory cancellate1 file(s) spostato(i) o ridenominato(i).

che e perfettamente concorde con quanto fatto. Andrebbe comunque precisato che nelnostro esempio viene monitorata la chiamata delle funzioni e quindi anche nel caso in cuiun’operazione dovesse fallire (ad esempio se tentiamo un rmdir su una directory non vuota)essa verrebbe conteggiata (volendo potremmo evitare cio gestendo opportunamente il caso delfallimento ma l’esempio risulterebbe piu complicato). L’ultima cosa che e obbligo sottolinearee che il nostro esempio fa riferimento ad una partizione formato ext3; se proviamo ad eseguirela stessa sequenza di comandi su una partizione diversa non viene catturato nulla! Di seguitoecco il risultato in cui le stesse operazioni vengono invocate su una partizione formato FAT:

2Di default la lunghezza e 128, troppo poco per il nostro esempio!

Page 138: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

A.2. SystemTAP - Probing delle operazioni su partizione ext3 Capitolo A. Ulteriori esempi 137

START PROBINGEND PROBINGNumero di operazioni eseguite sulla partizione ext3 in 26 secondi:0 directory create0 directory cancellate0 file(s) spostato(i) o ridenominato(i).

Provare per credere! Se avessimo voluto ottenere lo stesso risultato anche per una par-tizione FAT sarebbe stato sufficiente sostituire le definizione dei probe points trasformandotutte le stringhe “ext3” in “vfat”.

Page 139: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Appendice B

Installazione

B.1 Kprobes e Jprobes

Per installare il framework di strumentazione Kprobes/Jprobes e necessario disporre di unkernel di linux con versione 2.6. Nel caso in cui tale kernel non sia gia predisposto perKprobes sara necessario aggiungere delle patch al codice. Le patch sono contenute in unpacchetto tar.gz disponibile al sito:

http://www-128.ibm.com/developerworks/linux/library/l-kprobes.html#Resources.

Scaricato il pacchetto adatto alla propria versione del kernel, e necessario eseguire iseguenti comandi da shell (supponendo che la versione sia ad esempio la 2.6.8-rc1):

$tar -xvzf kprobes-2.6.8-rc1.tar.gz$cd /usr/src/linux-2.6.8-rc1$patch -p1 < ../kprobes-2.6.8-rc1-base.patch

Fatto questo, dal momento che Kprobes sfrutta la SysRq key, e necessario abilitare questafunzionalita nel kernel1 attraverso un’altra patch disponibile sempre allo stesso sito:

$patch -p1 < ../kprobes-2.6.8-rc1-sysrq.patch

Adesso il kernel e pronto per essere compilato; eseguendo il comando make gconfig (omake menuconfig, make xconfig), bisogna abilitare CONFIG KPROBES e CONFIG MAGIC SYSRQ,come nella figura 1.1, tra le opzioni di compilazione. Una volta compilato il kernel e messoin esecuzione e possibile sfruttare Kprobes e Jprobes.

Alcune distribuzioni di Linux, come la Fedora 4, tuttavia gia hanno abilitato nel propriokernel Kprobes e Jprobes.

B.2 SystemTAP

SystemTAP, per poter essere utilizzato, necessita di Kprobes e Jprobes, quindi e necessarioinnanzitutto seguire i passi descritti in precedenza. Esso necessita inoltre delle informazioni

1Ovviamente solo nel caso in cui il kernel non sia gia predisposto.

138

Page 140: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

B.2. SystemTAP Capitolo B. Installazione 139

Figura B.1: Menu grafico di compilazione del kernel. Nella figura e evidenziata l’opzione diabilitazione di Kprobes e di SysRq.

simboliche di debugging del kernel; per tal motivo e necessario compilare il kernel con leinformazioni di debug come mostrato in figura B.2, aggiungendo inoltre l’opzione -g allavariabile di compilazione CFLAGS quando si utilizza il comando make. Se invece si disponedella distribuzione Fedora 4 e possibile scaricare direttamente dalla rete le informazioni didebugging senza dover necessariamente ricompilare il kernel; basta utilizzare il comando:

yum --enablerepo=development install kernel-debuginfo-$(uname -r)

Adesso e possibile installare SystemTAP. Si possono scaricare i sorgenti utilizzando ilsistema cvs:

cvs -d :pserver:[email protected]:/cvs/systemtap login{utilizzare "anoncvs" come password}cvs -d :pserver:[email protected]:/cvs/systemtap co -c

Scaricati i sorgenti e necessario compilarli attraverso la sequenza:

$ ./config$ make$ make install

Se invece si dispone di Fedora 4 e possibile utilizzare yum che, come nel caso delle infor-mazioni di debug viste prima, verifichera le dipendenze e installera SystemTAP in manieradel tutto automatica:

yum --enablerepo=development install systemtap

Fatto questo SystemTAP e pronto.

Page 141: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

B.2. SystemTAP Capitolo B. Installazione 140

Figura B.2: Menu grafico di compilazione del kernel. Nella figura e evidenziata l’opzione diabilitazione delle informazioni di debug.

Page 142: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Appendice C

Codici di errore

La tabella seguente riporta i codici d’errore maggiormente accorsi negli esperimenti descrittiin precedenza.

Tabella C.1: Codici d’errore ottenuti nei risultati sperimentali.Nome Errore DescrizioneEACCESS Permesso negatoEADDRNOTAVAIL Indirizzo non disponibileEAGAIN Risorsa temporaneamente occupataEBADF Descrittore di file erratoECHILD Nessun processo figlioEINTR Chiamata di funzione interrottaEINVAL Argomento non validoENOENT File o directory non esistenteENOEXEC Formato della exec erratoENOTSOCK L’entita non e una socketENOTTY Inappropriata operazione di controllo IOENXIO Dispositivo o indirizzo non esistenteEPERM Operazione non permessaESPIPE Ricerca non valida

141

Page 143: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

Bibliografia

[1] Cristofaro Gozzolino: Monitoring delle System Call del Sistema Operativo LinuxLibeRTOS

[2] Herbert Schildt: C/C++ Programmer’s Reference, 3rd edition, McGraw-Hill, 2003

[3] Robert Love: Linux Kernel Development, 2nd edition, Novell, 2005

[4] Daniel P. Bovet, Marco Cesati: Understanding the Linux Kernel, 3rd Edition, O’Reilly,2006

[5] Peter Jay Salzman, Michael Burian, Ori Pomerantz: The Linux Kernel ModuleProgramming Guide, Peter Jay Salzman, 2001

[6] Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman: Linux Device Drivers, 3rdEdition, O’Reilly, 2005

[7] Jialong He: LINUX System Call Quick Reference,http://www.bigfoot.com/∼jialong he

[8] Intel Corporation: IA-32 Intel Architecture Software Developer’s Manual, Volume 1:Basic Architecture, Intel Corporation, 2004

[9] Intel Corporation: IA-32 Intel Architecture Software Developer’s Manual, Volume 2A:Instruction Set Reference, A-M, Intel Corporation, 2004

[10] Intel Corporation: IA-32 Intel Architecture Software Developer’s Manual, Volume 2B:Instruction Set Reference, N-Z, Intel Corporation, 2004

[11] Intel Corporation: IA-32 Intel Architecture Software Developer’s Manual, Volume 3:System Programming Guide, Intel Corporation, 2004

[12] Agner Fog: C/C++ Calling conventions,http://www.agner.org/assem/calling convenctions.pdf, 2005

[13] William Cohen: Gaining insite into the Linux Kernel with Kprobes,http://www.redhat.com/magazine/005mar05/features/kprobes/, 2005

[14] Prasanna Panchamukhi: Kernel Debugging with Kprobes,http://www-128.ibm.com/developerworks/linux/library/l-kprobes.html, 2004

[15] R. Krishnakumar: Kernel Korner - Kprobes & mdash; a Kernel Debugger,http://www.linuxjournal.com/article/7905, 2005

142

Page 144: Studio e implementazione di meccanismi di probing del ... · Nel 1983, Richard Stallman, un fisico e informatico del MIT, frustrato dalla situazione venutasi a creare nella comunit`a

BIBLIOGRAFIA BIBLIOGRAFIA 143

[16] Red Hat: SystemTAP, http://www.sourceware.org/systemtap/, 2005

[17] Leslie Lamport: LATEX, A Document Preparation System, 2nd Edition, Addison-WesleyPublishing Company, 1994

[18] Michel Goossens, Sebastian Rahtz, Frank Mittelbach: The LATEXGraphics Companion,Addison-Wesley Publishing Company, 1997

[19] Tobias Oetiker, Hubert Partl, Irene Hyna, Elisabeth Schlegl: The Not So ShortIntroduction to LATEX2ε, ftp://ftp.unina.it/pub/TeX/info/italian, 2000