interposizione funzione in Linux senza dlsym
-
14-09-2019 - |
Domanda
Al momento sto lavorando su un progetto in cui ho bisogno di monitorare l'utilizzo di diverse chiamate di sistema e funzioni di basso livello come mmap
, brk
, sbrk
. Finora, ho fatto questa funzione utilizzando interposizione: scrivo una funzione wrapper con lo stesso nome della funzione sto sostituendo (mmap
per esempio), e lo carico in un programma impostando la variabile d'ambiente LD_PRELOAD
. Chiamo la funzione reale attraverso un puntatore che si carica con dlsym
.
Purtroppo, una delle funzioni che voglio per avvolgere, sbrk
, è utilizzato internamente da dlsym
, in modo che il programma va in crash quando cerco di caricare il simbolo. sbrk
non è una chiamata di sistema in Linux, quindi non posso semplicemente utilizzare syscall
chiamarlo indirettamente.
Quindi la mia domanda è: come posso chiamare una funzione di libreria da una funzione wrapper con lo stesso nome senza usare dlsym
? C'è qualche trucco del compilatore (utilizzando GCC) che mi permette riferisco alla funzione originale?
Soluzione
sede di ld opzione --wrap symbol
. Dalla pagina man:
- simbolo involucro di utilizzare una funzione wrapper per simbolo. qualsiasi undefined riferimento al simbolo sarà risolto a "
__wrap_symbol
". qualsiasi undefined riferimento al "__real_symbol
" volontà essere risolto al simbolo.Questo può essere utilizzato per fornire un wrapper per una funzione di sistema. Il funzione involucro deve essere chiamata "
__wrap_symbol
". Se si desidera chiamare la funzione di sistema, occorre 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 il file utilizzando malloc --wrap, allora tutto chiamate a "
malloc
" chiamerà il Funzione "__wrap_malloc
" invece. Il chiamare a "__real_malloc" in
"__wrap_malloc
" chiamerà il vero funzione "malloc
".Si potrebbe desiderare di fornire un Funzione "
__real_malloc
" e, in modo che collega senza l'opzione --wrap avrà successo. Se si esegue questa operazione, non dovrebbe mettere la definizione di "__real_malloc
" nello stesso file come "__wrap_malloc
"; se lo fai, il assemblatore può risolvere la chiamata prima il linker ha la possibilità di avvolgerlo a "Malloc".
L'altra opzione è quella forse guardare il sorgente per ltrace, è più o meno fa la stessa cosa :-P.
: Ecco un'idea però. Si potrebbe avere la libreria LD_PRELOAD
'ed modificare le voci PLT per puntare al codice. Questo vi tecnicamente la funzione sbrk()
è ancora richiamabile dal codice nativly.
Altri suggerimenti
È 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 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.
Se si utilizza un sistema host con glibc, la libc ha qualche back-end interna al linker dinamico di runtime che ho usato qualche tempo fa. Se non ricordo male, mi pare si chiami '__libc_dlsym'. (Per controllare, "$ readelf -s /usr/lib/libc.a | grep dlsym" dovrebbe aiutare.) Dichiarare come una funzione legata esternamente con gli stessi argomenti e valore di ritorno che ha dlsym e usarlo per avvolgere dlsym sé.
La truss
non funziona sul vostro sistema? Funziona perfettamente per questo genere di cose qui su Solaris.