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