2009-06-15 11 views
8

Attualmente sto lavorando a un progetto in cui devo monitorare l'utilizzo di più chiamate di sistema e funzioni di basso livello come mmap, brk, sbrk. Finora, l'ho fatto usando l'interposizione di funzioni: scrivo una funzione wrapper con lo stesso nome della funzione che sto sostituendo (ad esempio mmap) e la carico in un programma impostando la variabile di ambiente LD_PRELOAD. Chiamo la funzione reale attraverso un puntatore che carico con dlsym.Interposizione delle funzioni in Linux senza dlsym

Sfortunatamente, una delle funzioni che voglio avvolgere, sbrk, viene utilizzata internamente da dlsym, quindi il programma si blocca quando provo a caricare il simbolo. sbrk non è una chiamata di sistema in Linux, quindi non posso semplicemente usare syscall per chiamarlo indirettamente.

Quindi la mia domanda è, come posso chiamare una funzione di libreria da una funzione wrapper con lo stesso nome senza utilizzare dlsym? C'è qualche trucco del compilatore (usando gcc) che mi permette di fare riferimento alla funzione originale?

risposta

14

vedere l'opzione --wrap symbol. Dalla pagina man:

- simbolo di avvolgimento Utilizzare una funzione wrapper per il simbolo. Qualsiasi riferimento indefinito al simbolo verrà risolto da a "__wrap_symbol". Qualsiasi riferimento non definito a "__real_symbol" verrà risolto in simbolo .

Questo può essere utilizzato per fornire un wrapper per una funzione di sistema. La funzione wrapper deve essere chiamata "__wrap_symbol". Se desidera chiamare la funzione di sistema , dovrebbe chiamare "__real_symbol".

Ecco un esempio banale:

void * 
__wrap_malloc (size_t c) 
{ 
    printf ("malloc called with %zu\n", c); 
    return __real_malloc (c); 
} 

Se si collega altro codice con questo file usando malloc --wrap, allora tutti chiamate a "malloc" chiamerà la funzione " __wrap_malloc "invece. La chiamata a "__real_malloc" in
"__wrap_malloc" chiamerà la funzione reale "malloc".

Si potrebbe desiderare di fornire una funzione "__real_malloc" e, in modo che collega senza l'opzione --wrap avrà successo. Se lo fai, non devi inserire la definizione di "__real_malloc" nello stesso file di "__wrap_malloc"; se lo fai, l'assemblatore può risolvere la chiamata prima dello il linker ha la possibilità di inserirlo a "malloc".

L'altra opzione è possibilmente guardare la sorgente per ltrace, è più o meno la stessa cosa :-P.

Ecco un'idea.Potresti avere la tua libreria LD_PRELOAD 'modificare le voci PLT per puntare al tuo codice. Questo tecnicamente la funzione sbrk() è ancora richiamabile dal codice in modo nativo.

+0

Questo è fantastico. Non avevo mai sentito parlare dell'opzione --wrap, ma questo è esattamente ciò di cui ho bisogno. Grazie. –

+0

Per chiarire, i flag --wrap devono essere passati quando si collega l'eseguibile o quando si collega la libreria LD_PRELOAD che contiene i wrapper? Inoltre, prenderesti in considerazione di fornire maggiori informazioni sulla modifica delle voci PLT dell'eseguibile? –

+0

Il caso d'uso progettato è quello di collegare l'applicazione * target * con --wrap. Potrebbe essere possibile farlo funzionare anche per il caso LD_PRELOAD, non sono sicuro, dovrò testare. –

2

È possibile esaminare la funzione invocazione discretamente utilizzando strumenti come:

  • gdb
  • ltrace
  • systemtap

Questi strumenti consentono un programma monitor di informare quando viene chiamata una funzione e ti permettono di interrogare gli argomenti.

Le differenze principali sono:

  • gdb è interattivo, ma potente ltrace
  • semplice da usare, ma è possibile stampare solo il nome della funzione
  • systemtap non è interattivo, ma può essere molto veloce, ed è potente.
0

Se si esegue un sistema host con glibc, la libc ha un back-end interno al linker dinamico di runtime che ho utilizzato qualche tempo fa. Se ricordo bene, penso che si chiami '__libc_dlsym'. (Per verificare, "$ readelf -s /usr/lib/libc.a | grep dlsym" dovrebbe aiutare.) Dichiararlo come una funzione collegata esternamente con gli stessi argomenti e il valore di ritorno che ha dlsym e usarlo per avvolgere dlsym stesso.

0

truss non funziona sul sistema? Funziona perfettamente per questo genere di cose qui su Solaris.

+0

Sembra esattamente come 'strace' in Linux. Funziona bene se hai solo bisogno di ottenere un elenco di chiamate che sono state fatte. In questo progetto, avevo bisogno di aggiungere alcune funzionalità ai wrapper, e penso che l'interposizione sia l'unico modo per farlo. –

Problemi correlati