2011-05-27 13 views
25

Estoy intentando depurar el módulo kernel. Sospecho que tiene algunas pérdidas de memoria. Para comprobarlo, he preparado la compilación con la depuración de fugas de memoria habilitada para kernel y módulos. Y me alguna advertencia de que:addr2line en el módulo kernel

[11839.429168] slab error in verify_redzone_free(): cache `size-64': memory outside object was overwritten 
[11839.438659] [<c005575c>] (unwind_backtrace+0x0/0x164) from [<c0116ca0>] (kfree+0x278/0x4d8) 
[11839.447357] [<c0116ca0>] (kfree+0x278/0x4d8) from [<bf083f48>] (some_function+0x18/0x1c [my_module]) 
[11839.457214] [<bf083f48>] (some_function+0x18/0x1c [my_module]) from [<bf08762c>] (some_function+0x174/0x718 [my_module]) 
[11839.470184] [<bf08762c>] (some_function+0x174/0x718 [my_module]) from [<bf0a56b8>] (some_function+0x12c/0x16c [my_module]) 
[11839.483917] [<bf0a56b8>] (some_function+0x12c/0x16c [my_module]) from [<bf085790>] (some_function+0x8/0x10 [my_module]) 
[11839.496368] [<bf085790>] (some_function+0x8/0x10 [my_module]) from [<bf07b74c>] (some_function+0x358/0x6d4 [my_module]) 
[11839.507476] [<bf07b74c>] (some_function+0x358/0x6d4 [my_module]) from [<c00a60f8>] (worker_thread+0x1e8/0x284) 
[11839.517211] [<c00a60f8>] (worker_thread+0x1e8/0x284) from [<c00a9edc>] (kthread+0x78/0x80) 
[11839.525543] [<c00a9edc>] (kthread+0x78/0x80) from [<c004f8fc>] (kernel_thread_exit+0x0/0x8) 

no hay ningún problema para traducir las direcciones que apunta al núcleo:

$ addr2line -f -e vmlinux.kmeml c0116ca0 
verify_redzone_free 
/[...]/kernel/mm/slab.c:2922 

pero no puedo hacer eso si las direcciones son de mi_módulo:

$ addr2line -f -e vmlinux.kmeml bf0a56b8 
?? 
??:0 

también estaba tratando con el archivo de módulo:

$ addr2line -f -e my_module.ko bf0a56b8 
?? 
??:0 

¿Cómo puedo traducir estas direcciones a archivos y números de línea?

Respuesta

23

Supongo que el módulo está construido con información de depuración incluida. De ser así, puede usar gdb u objdump para averiguar a qué archivo fuente y línea pertenece cada dirección. Algo como esto:

$ gdb "$(modinfo -n my_module)" 
(gdb) list *(some_function+0x12c) 

Gdb ahora le dirá el nombre del archivo de origen y la línea en ella.

También puede hacer algo similar con objdump, pero es un poco más difícil. En primer lugar, desmontar el módulo:

objdump -dSlr my_module.ko > my_module.disasm 

Cuando llama con -S opción, objdump incluirá las líneas de código en el listado resultante en su caso.

Ahora puede desplazar el listado hasta el código de some_function, encuentre las instrucciones en el desplazamiento 0x12c desde el comienzo de la función. La línea fuente se indicará arriba.

EDIT:

Después de muchos experimentos, he encontrado que a pesar de addr2line de hecho puede ser utilizado para los módulos del núcleo, eu-addr2line (una herramienta similar de elfutils) parece ser más confiable. Es decir, a veces addr2line genera líneas de origen incorrectas, pero eu-add2line hizo las cosas bien.

Para usar eu-addr2line, es posible que necesite instalar librerías libdw y libebl si aún no están instaladas junto con elfutils.

el uso es similar a la de addr2line:

eu-addr2line -f -e <path_to_the_module> -j <section_name> <offset_in_section> 

Si la información de depuración de un módulo del núcleo se almacena en archivos separados (esto es a menudo el caso de los núcleos proporcionados por las principales distribuciones de Linux), la ruta a ese archivo se debe usar como <path_to_the_module>.

+0

Una nota al margen. Si está trabajando en x86 y su kernel de Linux es 2.6.31 o posterior, puede encontrar un sistema KEDR más ligero (http://kedr.berlios.de/) útil para verificar si sus módulos tienen pérdidas de memoria. A diferencia de las instalaciones de kernel integradas como Kmemleak, KEDR no requiere la reconstrucción del kernel. Debería ser bastante fácil de configurar y usar. – Eugene

7

Es verdad que tenga que ejecutar addr2line en su módulo de núcleo y no del núcleo, pero hay un giro -

el archivo del módulo kernel usa direcciones relativas, la dirección de choque que tiene en realidad está compuesto de:

compensado la dirección de carga del módulo + módulo interior es memoria.

Lo que necesita hacer es encontrar la dirección de carga de módulo de kernel es la memoria primero haciendo cat/proc/modules, encontrando a qué módulo pertenece esa dirección, en caso de que no sepa, reste la dirección de carga del módulo desde la dirección de choque y de alimentación que a addr2line

buena suerte

-3

Tal vez debería utilizar el parámetro -g para compilar el módulo.

Cuestiones relacionadas