2009-06-15 18 views
8

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 de envoltura 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.interposición de funciones en Linux sin dlsym

Desafortunadamente, una de las funciones que quiero envolver, sbrk, se usa internamente por dlsym, por lo que el programa se bloquea cuando intento cargar el símbolo. sbrk no es una llamada al sistema en Linux, así que no puedo simplemente usar syscall para llamarlo indirectamente.

Así que 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?

Respuesta

14

ver la opción --wrap symbol de ld. Desde la página del manual:

--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" será resuelto al símbolo.

Esto se puede utilizar para proporcionar un contenedor para una función del sistema. La función de contenedor se debe llamar "__wrap_symbol". Si desea llamar al la función del sistema, debe llamar al "__real_symbol".

Aquí es un ejemplo trivial:

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

Si se enlaza otro código con este archivo usando malloc --wrap, a continuación, todas las llamadas a "malloc" llamará a la función " __wrap_malloc "en su lugar. La llamada a "__real_malloc" en
"__wrap_malloc" llamará a la función real "malloc".

Es posible que desee para proporcionar una función "__real_malloc" y, por lo que une sin la opción --wrap tendrá éxito. Si hace esto, no debe poner la definición de "__real_malloc" en el mismo archivo como "__wrap_malloc"; si lo hace, el ensamblador puede resolver la llamada antes de el enlazador tiene la posibilidad de ajustarlo al "malloc".

La otra opción es posiblemente mirar la fuente de ltrace, es más o menos lo mismo :-P.

Aquí hay una idea.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() aún se puede llamar desde su código de forma nativa.

+0

Esto es genial. Nunca había escuchado sobre la opción --wrap, pero esto es exactamente lo que necesito. Gracias. –

+0

Para aclarar, ¿se deben pasar los parámetros --wrap al vincular el ejecutable o al vincular la biblioteca LD_PRELOAD que contiene los wrappers? Además, ¿consideraría proporcionar más información sobre la modificación de las entradas PLT del ejecutable? –

+0

El caso de uso diseñado es para que vincule la aplicación * target * con --wrap. También es posible hacer que funcione para el caso LD_PRELOAD, no estoy seguro, tendré que probarlo. –

2

Puede examinar invocación de la función discretamente el uso de herramientas tales como:

  • GDB
  • ltrace
  • systemtap

Estas herramientas permiten a un programa monitor informar que cuando una función es llamada , y te permiten interrogar los argumentos.

Las principales diferencias son:

  • GDB es interactivo, pero potente
  • ltrace simple de usar, pero sólo se puede imprimir el nombre de la función
  • systemtap no es interactivo, pero puede ser muy rápido, y es poderoso.
0

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.

0

¿No funciona el truss en su sistema? Funciona perfectamente para este tipo de cosas aquí en Solaris.

+0

Eso suena exactamente como 'strace' en Linux. Esto funciona bien si solo necesita obtener una lista de las llamadas que se hicieron. En este proyecto, necesité agregar algunas funcionalidades a los contenedores, y creo que la interposición es la única manera de hacerlo. –

Cuestiones relacionadas