User Tools

Site Tools


linux-kernel-dev:capitole:capitol-02

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
linux-kernel-dev:capitole:capitol-02 [2015/09/08 11:28]
razvan [Modul nou din surse multiple]
linux-kernel-dev:capitole:capitol-02 [2016/08/30 12:18] (current)
razvan [Informații cscope]
Line 15: Line 15:
 ===== Resurse utile ===== ===== Resurse utile =====
  
-  * http://​www.tldp.org/​LDP/​lkmpg/​2.6/​html/​x323.html+  * [[http://​www.tldp.org/​LDP/​lkmpg/​2.6/​html/​x323.html|The Linux Kernel Module Programming Guide: Passing Command Line Arguments to a Module]] 
 +  * [[https://​lwn.net/​Kernel/​LDD3/​|Linux Device Drivers, 3rd Edition]] (free) 
 +  * [[https://​lwn.net/​images/​pdf/​LDD3/​ch02.pdf|Linux Device Drivers, 3rd Edition, Chapter 2: Building and Running Modules]] (free, PDF) 
 +  * [[http://​lxr.free-electrons.com/​|Linux Cross Reference (LXR) (Free Electrons)]] 
 ===== Exerciții ===== ===== Exerciții =====
  
Line 109: Line 113:
 Actualizați modulul ''​hello.c''​ pentru a afișa un mesaj și la descărcarea din kernel, la operația ''​rmmod''​. Actualizați modulul ''​hello.c''​ pentru a afișa un mesaj și la descărcarea din kernel, la operația ''​rmmod''​.
  
-Folosiți funcția ''​printk''​ astfel încât mesajele să fie afișate în bufferul kernel-ului (adică să fie afișate cu ''​dmesg''​) ​dar să nu fie afișate la consolă.+Folosiți funcția ''​printk''​ astfel încât mesajele să fie afișate ​atât în bufferul kernel-ului (adică să fie afișate cu ''​dmesg''​) ​cât șla consolă.
  
 <note tip> <note tip>
Line 123: Line 127:
 </​note>​ </​note>​
  
 +<note tip>
 +Pentru a include conținutul fișierului header ''​include/​linux/​sched.h''​ folosiți construcția
 +<​code>​
 +#include <​linux/​sched.h>​
 +</​code>​
 +La fel veți proceda și în cazul altor fișiere de tip header în care sunt definite structuri, tipuri de date sau macro-uri pe care le folosiți în modulul vostru.
 +</​note>​
 ==== Afișare comandă ==== ==== Afișare comandă ====
  
Line 146: Line 157:
  
 <note tip> <note tip>
-Pentru testare folosiți ''​ping''​ din mașina virtuală VirtualBox către mașina virtuală QEMU. Și apoi pe mașina virtuală QEMU încărcați ​șdescărcați modulul ''​hook.ko''​.+Pentru testare folosiți ''​ping''​ din mașina virtuală VirtualBox către mașina virtuală QEMU<​code>​ 
 +ping 172.20.0.2 
 +</​code>​ 
 +Adresa ''​172.20.0.2''​ este adresa interfeței ''​eth0''​ a mașinii virtuale QEMU. 
 + 
 +Urmăriți numerele de secvență ale mesajelor ICMP în output-ul comenzii ''​ping'',​ adică partea cu ''​icmp_seq''​. 
 + 
 +Și apoi pe mașina virtuală QEMU încărcați ​modulul ''​hook.ko''​. Observațacum care sunt numerele de secvență ale mesajelor ICMP. Observați că acum un pachet din două nu este afișat, pentru că este filtrat de modul. 
 + 
 +Descărcați modulul ''​hook.ko'' ​și observați că acum numerele de secvență revin la numere consecutive,​ nemaifiind filtrate de modul.
 </​note>​ </​note>​
 ==== Modul din surse multiple ==== ==== Modul din surse multiple ====
Line 157: Line 177:
 Urmăriți fișierele intermediare și fișierul modul final. Urmăriți fișierele intermediare și fișierul modul final.
  
-Copiați fișierul modul final în mașina virtuală QEMU, porniți mașina virtuală QEMU și încarcați și descărcați modululul din kerkel.+Copiați fișierul modul final în mașina virtuală QEMU, porniți mașina virtuală QEMU și încărcați și descărcați modululul din kernel.
  
 ==== Modul nou din surse multiple ==== ==== Modul nou din surse multiple ====
  
-Creați un modul care să aibă două fișiere cod sursă. Într-un fișier cod sursă sunt implementate funcțiile de inițializare și ieșire ale modulului. În celălalt fișier implementați o funcție care face dump în hexacimal la cel mult 4096 de octeți de la o adresă dată. Adresa dată trebuie să fie adresă de kernel space (>= ''​0xc0000000''​). Funcția este apelată din primul modul.+Creați un modul care să aibă două fișiere cod sursă. Într-un fișier cod sursă sunt implementate funcțiile de inițializare și ieșire ale modulului. În celălalt fișier implementați o funcție care face dump în hexacimal la cel mult 4096 de octeți de la o adresă dată. Adresa dată trebuie să fie adresă de kernel space (>= ''​0xc0000000''​). Funcția este apelată din primul modul în cadrul funcției de inițializare a acestuia.
  
 Compilați modulul, copiați-l în mașina virtuală QEMU și testați-l. Compilați modulul, copiați-l în mașina virtuală QEMU și testați-l.
Line 170: Line 190:
  
 <note tip> <note tip>
-Pentru pachetele care pleacă folosiți ca ''​hooknum''​ valoarea ''​NF_INET_LOCAL_OUT''​.+Pentru pachetele care pleacă folosiți ca ''​hooknum''​ valoarea ''​NF_INET_LOCAL_OUT''​. Este vorba de câmpul ''​hooknum''​ din cadrul structura ''​icmp_nf_ops''​. 
 + 
 +Pachetele de tipul ''​echo reply''​ au câmpul ''​icmp_type''​ al structurii ''​icmp_hdr''​ egal cu valoarea ''​ICMP_ECHOREPLY''​. 
 + 
 +Puteți găsi definițiile de tipuri de câmpuri cu ajutorul ''​cscope''​ cu o comandă de genul<​code>​ 
 +vi -t ICMP_ECHO 
 +</​code>​ 
 +</​note>​ 
 + 
 +==== Informații cscope ==== 
 + 
 +[[http://​cscope.sourceforge.net/​|Cscope]] este un program pentru parcurgerea eficientă a surselor C.  Pentru a-l folosi, trebuie generată o bază de date cscope din sursele existente. ​ Într-un tree Linux, este suficientă folosirea ''​make ARCH=x86 cscope''​. ​ Precizarea arhitecturii prin variabila ARCH este opțională,​ dar recomandată;​ altfel, unele funcții dependente de arhitectură vor apărea de mai multe ori în baza de date. 
 + 
 +Cscope poate fi folosit și stand-alone,​ dar este mult mai util în combinație cu un editor. ​ Pentru a folosi cscope cu Vim, este necesar să instalați ambele pachete și să adăugați următoarele linii în fișierul ''​.vimrc''​ (mașina din laborator are deja configurările făcute): 
 + 
 +<code vim> 
 +if has("​cscope"​) 
 +        " Look for a '​cscope.out'​ file starting from the current directory,​ 
 +        " going up to the root directory. 
 +        let s:dirs = split(getcwd(),​ "/"​) 
 +        while s:dirs != [] 
 +                let s:path = "/"​ . join(s:​dirs,​ "/"​) 
 +                if (filereadable(s:​path . "/​cscope.out"​)) 
 +                        execute "cs add " . s:path . "/​cscope.out " . s:path . " -v" 
 +                        break 
 +                endif 
 +                let s:dirs = s:​dirs[:​-2] 
 +        endwhile 
 + 
 +        set csto=0 "​ Use cscope first, then ctags 
 +        set cst " Only search cscope 
 +        set csverb "​ Make cs verbose 
 + 
 +        nmap <​C-\>​s :cs find s <​C-R>​=expand("<​cword>"​)<​CR><​CR>​ 
 +        nmap <​C-\>​g :cs find g <​C-R>​=expand("<​cword>"​)<​CR><​CR>​ 
 +        nmap <​C-\>​c :cs find c <​C-R>​=expand("<​cword>"​)<​CR><​CR>​ 
 +        nmap <​C-\>​t :cs find t <​C-R>​=expand("<​cword>"​)<​CR><​CR>​ 
 +        nmap <​C-\>​e :cs find e <​C-R>​=expand("<​cword>"​)<​CR><​CR>​ 
 +        nmap <​C-\>​f :cs find f <​C-R>​=expand("<​cfile>"​)<​CR><​CR>​ 
 +        nmap <​C-\>​i :cs find i ^<​C-R>​=expand("<​cfile>"​)<​CR>​$<​CR>​ 
 +        nmap <​C-\>​d :cs find d <​C-R>​=expand("<​cword>"​)<​CR><​CR>​ 
 + 
 +        " Open a quickfix window for the following queries. 
 +        set cscopequickfix=s-,​c-,​d-,​i-,​t-,​e-,​g- 
 +endif 
 +</​code>​ 
 + 
 +Script-ul caută un fișier numit ''​cscope.out''​ în directorul curent, sau în directoarele părinte ale acestuia. ​ Dacă Vim găsește acest fișier, puteți folosi combinația ''​Ctrl+]''​ sau ''​Ctrl+\ g''​ (combinația control-\, urmată de tasta g) pentru a sări direct la definiția cuvântului de sub cursor (funcție, variabilă, structură etc.). ​ Similar, puteți folosi ''​Ctrl+\ s''​ pentru a merge la locurile unde este folosit cuvântul de sub cursor. 
 + 
 +Puteți lua un fișier ''​.vimrc''​ cscope-enabled (and other goodies) de la [[https://​github.com/​ddvlad/​cfg/​blob/​master/​_vimrc]]. ​ Următoarele indicații se bazează pe acest fișier, dar au listate și comenzile de bază vim care obțin același efect. 
 + 
 +Dacă există mai multe rezultate (de obicei există) vă puteți deplasa între ele folosind ''​F6''​ și ''​F5''​ ('':​cnext''​ și '':​cprev''​) sau deschizând o subfereastră nouă cu rezultatele,​ folosind '':​copen''​. Ca să închideți subfereastra folosiți comanda '':​cclose''​. 
 + 
 +Pentru a vă întoarce la locația precedentă,​ folosiți ''​Ctrl+o''​ (litera o, nu cifra zero). ​ Comanda poate fi invocată de mai multe ori și funcționează chiar dacă cscope a schimbat fișierul pe care îl editați. 
 + 
 +Pentru a merge la definiția unui simbol direct când porniți vim, folosiți ''​vim -t task_struct''​. Sau, dacă ați deschis Vim și vreți ulterior să căutați un simbol după nume, puteți folosi comanda '':​cs find g <​symbol_name>''​ (unde ''<​symbol_name>''​ este numele simbolului. 
 + 
 +Dacă ați găsit mai multe match-uri și dacă ați deschis o subfereastră cu toate match-urile (folosind '':​copen''​) și dacă sunteți în căutarea unui simbol de tip structură, este indicat să căutați în subfereastră (folosind ''/''​ -- //slash//) caracterul ''​{''​ (acoladă deschisă). 
 + 
 +<note important>​ 
 +Un sumar al comenzilor ''​cscope''​ îl puteți obține folosind '':​cs help''​. 
 + 
 +Pentru mai multe informații,​ folosiți help-ul integrat al Vim: '':​h cscope''​ sau '':​h copen''​. 
 +</​note>​ 
 + 
 +Dacă sunteți utilizatori emacs, [[http://​www.emacswiki.org/​emacs/​CScopeAndEmacs|wiki-ul emacs]] conține informații relevante pentru configurarea cscope. 
 + 
 +Pentru o interfață mai simplă, [[http://​sourceforge.net/​projects/​kscope/​|Kscope]] este un frontend pentru cscope care foloseşte QT. Este lightweight,​ foarte rapid și foarte ușor de folosit. Permite căutare folosind expresii regulate, grafuri de apel etc. Kscope nu mai este, în momentul de fața, menținut. Există şi un [[https://​opendesktop.org/​content/​show.php/​Kscope4?​content=156987|port]] al versiunii 1.6 pentru Qt4 şi KDE 4 care păstrează integrarea editorului Kate şi este mai uşor de folosit decât ultima versiune prezentă pe SourceForge. 
 + 
 +<note important>​ 
 +Dacă nu există deja un fișier ''​cscope.out''​ generat sau dacă s-a stricat, îl puteți genera folosind 
 +<​code>​ 
 +make ARCH=x86 cscope 
 +</​code>​ 
 +</​note>​ 
 +==== cscope spelunking ==== 
 + 
 +Folosiți direct Vim și comenzile cscope pentru parcurgerea codului sursă cu indicațiile de mai jos. 
 + 
 +Determinați fișierul în care sunt definite următoarele tipuri de date: 
 +  * ''​struct task_struct''​ 
 +  * ''​struct semaphore''​ 
 +  * ''​struct list_head''​ 
 +  * ''​spinlock_t''​ 
 +  * ''​struct file_system_type''​ 
 + 
 +<note tip> 
 +Pentru o structură se caută doar numele ei. Spre exemplu, în cazul ''​struct task_struct''​ se caută șirul ''​task_struct''​. 
 + 
 +De obicei veți obține mai multe match-uri caz în care: 
 +  - Listați toate match-urile folosind, în Vim, comanda '':​copen''​. Vă apare o fereastră secundară cu toate match-urile. 
 +  - Căutați match-ul potrivit (în care este definită structura) căutând după acoladă deschisă (''​{''​),​ un caracter sigur pe linia de definire a structurii. Pentru căutarea acoladei deschise folosiți, în Vim, construcția ''/​{''​. 
 +  - Pe linia aferentă apăsați ''​Enter''​ ca să vă ajungă editorul în codul sursă unde e definită variabila. 
 +  - Închideți fereastra secundară folosind coamanda '':​cclose''​. 
 +</​note>​ 
 + 
 +Determinați fișierul în care sunt declarate următoarele variabile globale la nivelul nucleului:​ 
 +  * ''​sys_call_table''​ 
 +  * ''​file_systems''​ 
 +  * ''​current''​ 
 +  * ''​chrdevs''​ 
 + 
 +<note tip> 
 +Pentru aceasta folosiți în Vim o comandă de forma '':​cs f g <​symbol>''​ (unde construcția ''<​symbol>''​ reprezintă numele simbolului căutat). 
 +</​note>​ 
 + 
 +Determinați fișierul în care sunt declarate următoarele funcții: 
 +  * ''​copy_from_user''​ 
 +  * ''​vmalloc''​ 
 +  * ''​schedule_timeout''​ 
 +  * ''​add_timer''​ 
 + 
 +<note tip> 
 +Pentru aceasta folosiți în Vim o comandă de forma '':​cs f g <​symbol>''​ (unde construcția ''<​symbol>''​ reprezintă numele simbolului căutat). 
 +</​note>​ 
 + 
 +Parcurgeți secvența de structuri:​ 
 +  - ''​struct task_struct''​ 
 +  - ''​struct mm_struct''​ 
 +  - ''​struct vm_area_struct''​ 
 +  - ''​struct vm_operations_struct''​ 
 +Adică parcurgeți din aproape în aproape structurile:​ accesați o structură și apoi găsiți câmpuri cu tipul de date al următoarei structuri, accesați-o pe aceasta etc. Rețineți în ce fișiere sunt definite; o să vă fie utile la alte laboratoare. 
 + 
 +<note tip> 
 +Pentru a căuta un simbol în Vim (cu suport ''​cscope''​) atunci când sunteți plasați cu cursorul pe acesta, folosiți construcția ''​Ctrl+]''​. 
 + 
 +Pentru a reveni în match-ul anterior (înante de căutare/​salt) folosiți construcția ''​Ctrl+o''​. Pentru a avansa în căutare (pentru a reveni la match-urile de dinainte de ''​Ctrl+o''​) folosiți construcția ''​Ctrl+i''​. 
 +</​note>​ 
 + 
 +La fel ca mai sus, parcurgeți secvența de apeluri de funcții: 
 +  - ''​bio_alloc''​ 
 +  - ''​bio_alloc_bioset''​ 
 +  - ''​bvec_alloc''​ 
 +  - ''​kmem_cache_alloc''​ 
 +  - ''​slab_alloc''​ 
 + 
 +<note tip> 
 +Aveți în vedere indicațiile din secțiunea [[#​informatii-cscope|Informații cscope]] de mai sus.
 </​note>​ </​note>​
 ==== [BONUS] Afișarea unui șir primit ca parametru pentru modul ==== ==== [BONUS] Afișarea unui șir primit ca parametru pentru modul ====
Line 177: Line 334:
  
 <note tip> <note tip>
-Inidicații sunt în directorul ''​cap-02-doc/''​ din arhiva capitolului.+Indicații sunt în directorul ''​cap-02-doc/''​ din arhiva capitolului ​și la link-urile din [[#​resurse-utile|secțiunea de resurse]]:​ 
 +  * [[http://​www.tldp.org/​LDP/​lkmpg/​2.6/​html/​x323.html|The Linux Kernel Module Programming Guide: Passing Command Line Arguments to a Module]] 
 +  * [[https://​lwn.net/​images/​pdf/​LDD3/​ch02.pdf|Linux Device Drivers, 3rd Edition, Chapter 2: Building and Running Modules]], secțiunea ''​Module Parameters''​ 
 </​note>​ </​note>​
  
linux-kernel-dev/capitole/capitol-02.1441700899.txt.gz · Last modified: 2015/09/08 11:28 by razvan