programas - script linux ejemplos
InterposiciĆ³n de funciones en Linux sin dlsym (4)
Puede examinar la invocación de funciones discretamente usando herramientas como:
- gdb
- ltrace
- systemtap
Estas herramientas permiten que un programa de monitoreo le informe cuando se llama a una función y le permite interrogar los argumentos.
Las principales diferencias son:
- gdb es interactivo, pero poderoso
- ltrace fácil de usar, pero solo puede imprimir el nombre de la función
- systemtap no es interactivo, pero puede ser muy rápido y potente.
Actualmente estoy trabajando en un proyecto donde necesito rastrear el uso de varias llamadas al sistema y funciones de bajo nivel como mmap
, brk
, sbrk
. Hasta ahora, he estado haciendo esto mediante la interposición de funciones: escribo una función envoltorio con el mismo nombre que la función que estoy reemplazando ( mmap
por ejemplo) y la cargo en un programa configurando la variable de entorno LD_PRELOAD
. Llamo a la función real a través de un puntero que cargo con dlsym
.
Desafortunadamente, una de las funciones que quiero envolver, sbrk
, es usada internamente por dlsym
, por lo que el programa falla cuando intento cargar el símbolo. sbrk
no es una llamada al sistema en Linux, por lo que no puedo usar simplemente syscall
para llamarlo indirectamente.
Entonces mi pregunta es, ¿cómo puedo llamar a una función de biblioteca desde una función de contenedor del mismo nombre sin usar dlsym
? ¿Hay algún truco de compilación (usando gcc) que me permita referirme a la función original?
Si está ejecutando un sistema host con glibc, la libc tiene algún back end interno para el enlazador dinámico en tiempo de ejecución que utilicé hace algún tiempo. Si recuerdo correctamente, creo que se llama ''__libc_dlsym''. (Para verificar, "$ readelf -s /usr/lib/libc.a | grep dlsym" debería ayudar.) Declararlo como una función externamente vinculada con los mismos argumentos y el valor de retorno que tiene dlsym y usarlo para envolver dlsym.
¿El truss
no funciona en su sistema? Funciona perfectamente para este tipo de cosas aquí en Solaris.
ver la opción de --wrap symbol
. Desde la página man:
- Símbolo de envoltura Use una función de envoltura para el símbolo. Cualquier referencia indefinida al símbolo se resolverá a "
__wrap_symbol
". Cualquier referencia indefinida a "__real_symbol
" se resolverá al símbolo.Esto se puede usar para proporcionar un contenedor para una función del sistema. La función de envoltura debe llamarse "
__wrap_symbol
". Si desea llamar a la función del sistema, debe llamar a "__real_symbol
".Aquí hay un ejemplo trivial:
void *
__wrap_malloc (size_t c)
{
printf ("malloc called with %zu/n", c);
return __real_malloc (c);
}
Si vincula otro código con este archivo usando --wrap malloc, entonces todas las llamadas a "
malloc
" llamarán a la función "__wrap_malloc
" en su lugar. La llamada a "__real_malloc" en
"__wrap_malloc
" llamará a la función real "malloc
".También puede proporcionar una función "
__real_malloc
" para que los enlaces sin la opción --wrap tengan éxito. Si hace esto, no debe poner la definición de "__real_malloc
" en el mismo archivo que "__wrap_malloc
"; si lo hace, el ensamblador puede resolver la llamada antes de que el enlazador tenga la posibilidad de envolverlo en "malloc".
La otra opción es posiblemente mirar la fuente de ltrace, es más o menos lo mismo :-P.
Aquí hay una idea sin embargo. Puede hacer que su biblioteca LD_PRELOAD
''ed cambie las entradas PLT para que apunten a su código. Esta, técnicamente, la función sbrk()
todavía se puede llamar desde su código de forma nativa.