Kernel hacking con: vim + cscope + ctags

El editor de texto VIM nos facilita la tarea de manejar los fuentes del kernel Linux de una manera simple y potente. En este pequeño tutorial, presentamos algunas de las características del editor VIM, que lo convierten en todo un IDE para hackear el kernel Linux sin dificultades.

Un poco de historia

El potente editor VI, se ha convertido en el editor de texto estándar de facto de los distintos sistemas Unix surgidos a lo largo de la historia. Fue creado por Bill Joy en 1976. Cuenta la historia que Bill Joy, actual vice presidente y cofundador de Sun Microsystems, creó VI a partir de los fuentes de las crípticas utilidades “ed” y “ex”, alcanzando gran popularidad al ser incluido en la unificación System V.

Vi Improved

Se han realizado muchas versiones del popular editor de textos VI, pero quizá la más potente y utilizada es la de Bram Moolenaar, VIM. El propio autor define a VIM como un clon de VI con un conjunto de características más completo, considerado por muchos como un editor para programadores, un completo IDE.

Este potente editor, tiene infinidad de opciones que lo hacen único, pero nos vamos a centrar sólo en las que nos harán la vida más fácil a los programadores en lenguaje C y en concreto, a los que pretendan sumergirse en la ingente cantidad de código fuente del kernel Linux.

Visualización del código

La primera ventaja de usar vim como editor para programar, es el potente motor de resaltado de sintaxis (syntax highlighting) que posee, existe un módulo de resaltado de sintaxis para casi cualquier lenguaje de programación existente, ya sea en el empaquetado de nuestra distribución favorita o en algún rincón de Internet.

Lo más habitual, es que por defecto se encuentre activada el resaltado de sintaxis, pero si no lo estuviera bastaría con usar el comando:

:syntax enable
Si queremos desactivar el resaltado, porque la combinación de colores nos impide ver algunos caracteres usaremos:

:syntax off
Para evitar tener que desactivar el resaltado de sintaxis, cuando nuestra configuración del terminal impide ver algunos colores con comodidad, existen algunas soluciones. Si nuestro terminal tiene fondo negro, como es habitual para no cansar la vista cuando programamos, podemos usar:

:set background=dark
Con ello, vim usa un esquema de colores que resalta los más oscuros para su fácil captación.

Otro molesto efecto visual que por defecto vim tiene activado, es el resaltado de las búsquedas. Es bueno que el resultado de las cadenas buscadas quede marcado de alguna manera, para encontrarlas fácilmente, pero cuando hemos terminado la búsqueda quedarán los resaltados incomodando la visualización del código. Para borrar estos resaltados, una vez concluida nuestra búsqueda bastará con ejecutar el comando:

:nohl
Muy útil para programar también resulta ver los números de línea del código, para ello usaremos el comando:

:set nu
Si queremos desactivar la numeración de línea usaremos:

:set nonu

Compilación

Para compilar nuestro programa C, generalmente usaremos un fichero Makefile. Vim tiene soporte para el uso de estos ficheros para la compilación. Bastará con ejecutar el comando make desde dentro del editor:

:make
Con ello, nuestro programa será compilado de manera habitual, con la ventaja de que la salida de make será parseada por vim, para facilitarnos algún tratamiento. Se nos mostrará los posibles errores cometidos en la compilación y hará una pausa hasta que pulsemos ENTER. Una vez pulsado ENTER, el editor posicionará el cursor en la línea del primer error. En este punto dispondremos de algunos comandos como:

:cn
Ver el siguiente error y desplazar el cursor a dicha línea.

:cp
Ir al error previo.

:cr
Irá de nuevo al primer error de la lista de errores.

:cc
Ver el actual error.

:cl
Visualizar toda la lista de errores.

Veamos un ejemplo. El siguiente código tiene claros errores. Vamos a compilarlo usando la orden make integrada en el editor.

#include <stdio.h>

int main(int argc, char *argv[])
{
        char *cadena = "con vim!"

        printf("hola mundo %s\n", cadena);

        return;
}
:make

gcc -Wall hola_mundo.c  -o hola_mundo
hola_mundo.c: En la función `main':
hola_mundo.c:7: error: error sintáctico before "printf"
hola_mundo.c:9: aviso: `return' with no value, in function returning non-void
hola_mundo.c:5: aviso: unused variable `cadena'
make: *** [hola_mundo] Error 1

Pulse INTRO o escriba un mandato para continuar
Vemos que el editor nos muestra la salida del comando make ejecutado, esta salida ya habrá sido procesada. Podemos usar los comandos antes vistos para navegar a través de los errores. Vemos como ejemplo el listado de los errores encontrados con el comando cl:

:cl
3 hola_mundo.c:7: error: error sintáctico before "printf"
4 hola_mundo.c:9: aviso: `return' with no value, in function returning non-void
5 hola_mundo.c:5: aviso: unused variable `cadena'
Pulse INTRO o escriba un mandato para continuar

Ayuda en la edición del código

El editor dispone de un potente módulo que indentará el código de una manera inteligente, lo activaremos con el comando:

:cindent
A medida que insertemos líneas de código se indentarán adecuadamente, según estemos dentro de bloques de código o estemos saliendo de ellos. Pero esto es para el código que insertamos, ¿qué ocurre si es estamos editando un programa no indentado?, podremos indentarlo completamente con sólo una orden:

gg=G
Otra interesante función que nos ayuda en la navegación, es saltar de una función a otra. Es decir, igual que con cntrl-f y con cntrl-b avanzamos y retrocedemos en el código página a página respectivamente. Podemos avanzar y retroceder en el código saltando de función a función con:

]] siguiente función
[[ anterior función

Es muy útil también conocer cuál es la correspondiente pareja de un paréntesis o llave, es típico perderse en bloques de código anidados. Para encontrar la pareja de alguno de estos caracteres, nos posicionaremos sobre el mismo y teclearemos:
%

Es muy interesante la siguiente opción. Con ella podremos crear comentarios de C de forma asistida. Es decir, cuando empecemos un comentario, cada vez que saltemos de línea, se añadirá un carácter líder de comentario automáticamente, hasta que cerremos el comentario.

:set fo=croq

Exuberant Ctags

Esta utilidad permite indexar de manera muy eficiente el código fuente de multitud de lenguajes. Se generará un fichero con el resultado de la indexación, en su terminología con los tags disponibles. Son tags en un fichero fuente de lenguaje C, las funciones, macros, etc.

Para su utilización bastará con ejecutar el comando siguiente en el directorio con nuestras fuentes.

ctags -R

La salida de este comando generará un fichero denominado tags. Cuando invoquemos nuestro editor vim en un directorio con ese fichero, tendremos todos los tags disponibles para navegar por el código fuente gracias al soporte directo de vim para esta herramienta.

El uso es simple. Situados sobre una función en el código pulsaremos:

ctrl-]

Este comando encontrará el tag sobre el cursor, es decir, si se trata de una función irá a su declaración. A medida que usemos este comando tendremos una lista de tags visitados, podremos ver esa lista invocando el comando:

:tags

Para retroceder en los tags que hemos visitado y para avanzar usaremos respectivamente los siguientes comandos:

ctrl-t
ctrl-o

Existen otras opciones, pero con estas tendremos suficiente para empezar a ser productivos.

Cscope

Esta herramienta también basa su potencia en al indexación con tags como la anterior. Pero aporta ventajas para la navegación de código en grandes árboles de fuentes, como puede ser el kernel Linux.

Fue desarrollada en los laboratorios Bell Labs para la mítica PDP-11. Desde sus inicios formó parte de la distribución oficial de Unix de AT&T. Gracias a la liberación del código en licencia BSD, por parte de Santa Cruz Operation (SCO) en el año 2000, podemos disponer de esta estupenda herramienta sin limitaciones.

Su funcionamiento básico es muy simple. Para empezar a trabajar con ello bastará con generar el fichero de tags, que se denominará por defecto cscope.out. Dicho fichero lo generaremos en la raíz de nuestro directorio de fuentes con la orden:

cscope -b

La propia herramienta tiene un interface para manejarla que la invocaremos con la orden:

cscope -d

Pero nos interesa el completo soporte que vim ofrece para el manejo de esta utilidad. Vim incorpora todas las opciones del interface de cscope. Bastará con ejecutar un simple comando desde el editor para acceder a todas las opciones disponibles integradas:

:cs
                                                                                                                                                                 
mandatos de «cscope»:
add  : Añadir una nueva base de datos (Usage: add file|dir [pre-path] [flags])
find : Petición de un patrón          (Usage: find c|d|e|f|g|i|s|t name)
      c: Find functions calling this function
      d: Find functions called by this function
      e: Find this egrep pattern
      f: Find this file
      g: Find this definition
      i: Find files #including this file
      s: Find this C symbol
      t: Find assignments to
help : Mostrar este mensaje          (Usage: help)
kill : Matar una conexión            (Usage: kill #)
reset: Reiniciar todas las conexiones (Usage: reset)
show : Mostrar las conexiones        (Usage: show)
Pulse INTRO o escriba un mandato para continuar

La primera opción a usar es cargar la base de datos de tags, para ello usaremos el comando:

:cs add cscope.out

Para ver si ha sido cargada ejecutaremos:

:cs show
                                                                                                                                                               
nº pid    base de datos                      prefijo ruta
0 5904  cscope.out                          <none>
Pulse INTRO o escriba un mandato para continuar

Veamos la potencia de esta herramienta con un ejemplo. Supongamos deseamos encontrar el fichero list.h en el árbol de fuentes del kernel Linux. Para ello ejecutaremos el comando:

:cs f f list.h

Cscope tag: list.h
  #  line  nombre del fichero / contexto / línea
  1      1  drivers/char/rio/list.h <<<unknown>>>

  2      1  drivers/eisa/devlist.h <<<unknown>>>

  3      1  drivers/md/dm-bio-list.h <<<unknown>>>
            1
  4      1  drivers/s390/cio/blacklist.h <<<unknown>>>
            "
  5      1  drivers/usb/core/otg_whitelist.h <<<unknown>>>
            ~A^I
  6      1  fs/jffs2/nodelist.h <<<unknown>>>

  7      1  fs/ntfs/runlist.h <<<unknown>>>
            "
  8      1  include/asm-i386/scatterlist.h <<<unknown>>>
            "
  9      1  include/linux/klist.h <<<unknown>>>

  10      1  include/linux/list.h <<<unknown>>>

  11      1  include/linux/scatterlist.h <<<unknown>>>

Introduzca el nº de la elección (<INTRO> para abortar):

Puesto que existen diversas localizaciones del fichero, o ficheros con nombre similares, el editor nos pregunta por cuál de los ficheros queremos editar, en nuestro caso, teclearemos el número 10, para que sea editado el fichero de TDA lista del kernel.

Podemos ver a través del menú, que podemos buscar funciones que llaman a una determinada función, la declaración de una función, realizar búsquedas con expresiones regulares en todo el árbol de fuentes, etc. Sin duda una potente extensión del editor vim.

Los fuentes del kernel

Como ya hemos observado, el uso conjunto de vim con ctags y cscope, permitirá una fácil navegación en un árbol de directorios repleto de ficheros fuente, como es el kernel Linux.

Estas herramientas son ampliamente usadas por la comunidad de desarrolladores del kernel y han sido integradas en el Makefile principal del árbol de fuentes del kernel. Por ello, invocando nuestro editor vim en la raíz del árbol de fuente, bastará con invocar:

:make tags
:make cscope

Con ello se invocarán las utilidades correspondientes, con los parámetros ideales para la navegación por el código del kernel.

Conclusión

Aunque, el editor vim puede resultar de difícil manejo para principiantes, una vez mecanizada su forma de trabajo y unido a estas herramientas, la productividad alcanzada con su uso es increible. Es posible editar con gran soltura, eficiencia y velocidad, gran cantidad de fuentes, con el simple movimiento de dos o tres dedos. Existen muchas características que no hemos abordado en el artículo, pero es una tarea que se deja a los lectores. En la sección de referencias se apuntan las fuentes principales de documentación.

Referencias

[1] “Sitio oficial de Vim” - www.vim.org
[2] “Sitio oficial de Ctags” - ctags.sourceforge.net
[3] “Sitio oficial de Cscope” - cscope.sourceforge.net