Delete old kernel* chapters.

This commit is contained in:
J. Vicente Carrasco 2008-11-22 14:01:17 +00:00
parent 07951ab095
commit ca1745d9e6
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=33274
2 changed files with 0 additions and 841 deletions

View file

@ -1,625 +0,0 @@
<!--
The FreeBSD Documentation Project
The FreeBSD Spanish Documentation Project
%SOURCE% en_US.ISO8859-1/books/handbook/kerneldebug/chapter.sgml
%SRCID% 0.0
$FreeBSD$
$FreeBSDes: doc/es_ES.ISO8859-1/books/handbook/kerneldebug/chapter.sgml,v 1.2 2004/10/08 22:14:26 jesusr Exp $
-->
<chapter id="kerneldebug">
<title>Depurando el Kernel</title>
<para><emphasis>Contribuci&oacute;n de &a.paul; y &a.joerg;</emphasis></para>
<sect1>
<title>Depuraci&oacute;n de un Kernel Crash Dump con <command>kgdb</command></title>
<para>Aqu&iacute; se dan instrucciones para hacer funcionar la depuraci&oacute;n del
kernel sobre un crash dump. En ellos se asume que usted tiene suficiente
espacio de swap para un crash dump. Si usted tiene varias particiones
de swap y la primera es demasiado peque&ntilde;a para albergar un dump, puede
configurar su kernel para que use un dispositivo alternativo (en la l&iacute;nea
<literal>config kernel</literal>=, o puede especificar una alternativa
usando el comando &man.dumpon.8;. La mejor manera de usar &man.dumpon.8;
es asignar la variable <literal>dumpdev</literal> en
<filename>/etc/rc.conf</filename>. Generalmente usted va a querer
especificar uno de los dispositivos de swap especificados en
<filename>/etc/fstab</filename>. Actualmente no se soportan dumps a
dispositivos que no sean de swap, como por ejemplo una unidad de cinta.
Configure su kernel usando <command>config -g</command>. Vea <link
linkend="kernelconfig">Configuraci&oacute;n del Kernel</link> para m&aacute;s detalles
sobre la configuraci&oacute;n del kernel FreeBSD.</para>
<para>Use el comando &man.dumpon.8; para decirle al kernel donde hacer
el dump (Tenga en cuenta que esto debera hacerse luego de configurar
la partici&oacute;n como dispositivo de swap usando &man.swapon.8;). Esto se
hace normalmente usando los archivos <filename>/etc/rc.conf</filename>
y <filename>/etc/rc</filename>. Como alternativa se puede fijar el
dispositivo usando la cl&aacute;usula <literal>dump</literal> en la l&iacute;nea
<literal>config</literal> de su archivo de configuraci&oacute;n del kernel.
Esta pr&aacute;ctica esta en desuso y s&oacute;lo deber&iacute;a ser usada para obtener
un dump de un kernel que falla durante el inicio.</para>
<note>
<para>En adelante, el t&eacute;rmino <command>kgdb</command> se referir&aacute; al
<command>gdb</command> corriendo en &ldquo;kernel debug mode&rdquo;.
Esto puede lograrse ya sea iniciando al <command>gdb</command> con
la opci&oacute;n <option>-k</option>, o enlazandolo y arrancandolo con el
nombre <command>kgdb</command>. Esto no se hace por default, y
la idea est&aacute; basicamente en desuso ya que a la gente de GNU no le
gusta que sus herramientas se comporten distinto cuando se las llama
por otro nombre. Esta posibilidad podr&aacute; perfectamente ser descontinuada
en futuras versiones.</para>
</note>
<para>Una vez que el kernel ha sido compilado haga una copia, digamos
<filename>kernel.debug</filename>, y luego corra <command>strip
-g</command> sobre el original. Instale el original normalmente. Usted
tambien podr&iacute;a instalar el kernel sin hacer el <command>strip</command>,
pero los tiempos de busqueda de algunos programas en la tabla de
s&iacute;mbolos aumentar&aacute;n sensiblemente, y dado que el kernel se carga completo
en memoria durante el inicio y no puede intercambiarse a disco luego,
se desperdiciar&aacute;n varios megabytes de memoria.</para>
<para>Si usted esta probando un nuevo kernel, por ejemplo tipeando el
nombre del nuevo kernel en el prompt de inicio, pero necesita arrancar
otro para tener su sistema funcionando de nuevo, arranquelo solo en modo
monousuario usando la opci&oacute;n <option>-s</option> en el prompt de inicio
, y luego siga los siguientes pasos:</para>
<screen>&prompt.root; <userinput>fsck -p</userinput>
&prompt.root; <userinput>mount -a -t ufs</userinput> # asi su file system para /var/crash se puede escribir
&prompt.root; <userinput>savecore -N /kernel.panicked /var/crash</userinput>
&prompt.root; <userinput>exit</userinput> # ...a modo multiusuario</screen>
<para>Esto instruye a &man.savecore.8; que use otro kernel para la
extracci&oacute;n de nombres de s&iacute;mbolo. De otro modo usaria el kernel en uso
y probablemente no haga nada ya que los s&iacute;mbolos del kernel y los del
dump son diferentes.</para>
<para>Ahora, luego de un crash dump, vaya a
<filename>/sys/compile/WHATEVER</filename> y corra
<command>kgdb</command>. desde <command>kgdb</command> haga:
<screen><userinput>symbol-file kernel.debug</userinput>
<userinput>exec-file /var/crash/kernel.0</userinput>
<userinput>core-file /var/crash/vmcore.0</userinput></screen>
y voila, ya puede depurar el crash dump usando las fuentes
del kernel como lo hace con cualquier otro programa.</para>
<para>A continuaci&oacute;n se muestra el log de una sesi&oacute;n de
<command>kgdb</command> que ilustra el procedimiento. Las l&iacute;neas
fueron numeradas para referencia, y las largas fueron cortadas para
mejorar la legibilidad. Mas alla de esto es el registro de un error real
tomado durante el desarrollo del driver pcvt de consola.</para>
<screen> 1:Script started on Fri Dec 30 23:15:22 1994
2:&prompt.root; <userinput>cd /sys/compile/URIAH</userinput>
3:&prompt.root; <userinput>kgdb kernel /var/crash/vmcore.1</userinput>
4:Reading symbol data from /usr/src/sys/compile/URIAH/kernel
...done.
5:IdlePTD 1f3000
6:panic: because you said to!
7:current pcb at 1e3f70
8:Reading in symbols for ../../i386/i386/machdep.c...done.
9:<prompt>(kgdb)</prompt> <userinput>where</userinput>
10:#0 boot (arghowto=256) (../../i386/i386/machdep.c line 767)
11:#1 0xf0115159 in panic ()
12:#2 0xf01955bd in diediedie () (../../i386/i386/machdep.c line 698)
13:#3 0xf010185e in db_fncall ()
14:#4 0xf0101586 in db_command (-266509132, -266509516, -267381073)
15:#5 0xf0101711 in db_command_loop ()
16:#6 0xf01040a0 in db_trap ()
17:#7 0xf0192976 in kdb_trap (12, 0, -272630436, -266743723)
18:#8 0xf019d2eb in trap_fatal (...)
19:#9 0xf019ce60 in trap_pfault (...)
20:#10 0xf019cb2f in trap (...)
21:#11 0xf01932a1 in exception:calltrap ()
22:#12 0xf0191503 in cnopen (...)
23:#13 0xf0132c34 in spec_open ()
24:#14 0xf012d014 in vn_open ()
25:#15 0xf012a183 in open ()
26:#16 0xf019d4eb in syscall (...)
27:<prompt>(kgdb)</prompt> <userinput>up 10</userinput>
28:Reading in symbols for ../../i386/i386/trap.c...done.
29:#10 0xf019cb2f in trap (frame={tf_es = -260440048, tf_ds = 16, tf_\
30:edi = 3072, tf_esi = -266445372, tf_ebp = -272630356, tf_isp = -27\
31:2630396, tf_ebx = -266427884, tf_edx = 12, tf_ecx = -266427884, tf\
32:_eax = 64772224, tf_trapno = 12, tf_err = -272695296, tf_eip = -26\
33:6672343, tf_cs = -266469368, tf_eflags = 66066, tf_esp = 3072, tf_\
34:ss = -266427884}) (../../i386/i386/trap.c line 283)
35:283 (void) trap_pfault(&amp;frame, FALSE);
36:<prompt>(kgdb)</prompt> <userinput>frame frame-&gt;tf_ebp frame-&gt;tf_eip</userinput>
37:Reading in symbols for ../../i386/isa/pcvt/pcvt_drv.c...done.
38:#0 0xf01ae729 in pcopen (dev=3072, flag=3, mode=8192, p=(struct p\
39:roc *) 0xf07c0c00) (../../i386/isa/pcvt/pcvt_drv.c line 403)
40:403 return ((*linesw[tp-&gt;t_line].l_open)(dev, tp));
41:<prompt>(kgdb)</prompt> <userinput>list</userinput>
42:398
43:399 tp-&gt;t_state |= TS_CARR_ON;
44:400 tp-&gt;t_cflag |= CLOCAL; /* cannot be a modem (:-) */
45:401
46:402 #if PCVT_NETBSD || (PCVT_FREEBSD >= 200)
47:403 return ((*linesw[tp-&gt;t_line].l_open)(dev, tp));
48:404 #else
49:405 return ((*linesw[tp-&gt;t_line].l_open)(dev, tp, flag));
50:406 #endif /* PCVT_NETBSD || (PCVT_FREEBSD >= 200) */
51:407 }
52:<prompt>(kgdb)</prompt> <userinput>print tp</userinput>
53:Reading in symbols for ../../i386/i386/cons.c...done.
54:$1 = (struct tty *) 0x1bae
55:<prompt>(kgdb)</prompt> <userinput>print tp-&gt;t_line</userinput>
56:$2 = 1767990816
57:<prompt>(kgdb)</prompt> <userinput>up</userinput>
58:#1 0xf0191503 in cnopen (dev=0x00000000, flag=3, mode=8192, p=(st\
59:ruct proc *) 0xf07c0c00) (../../i386/i386/cons.c line 126)
60: return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
61:<prompt>(kgdb)</prompt> <userinput>up</userinput>
62:#2 0xf0132c34 in spec_open ()
63:<prompt>(kgdb)</prompt> <userinput>up</userinput>
64:#3 0xf012d014 in vn_open ()
65:<prompt>(kgdb)</prompt> <userinput>up</userinput>
66:#4 0xf012a183 in open ()
67:<prompt>(kgdb)</prompt> <userinput>up</userinput>
68:#5 0xf019d4eb in syscall (frame={tf_es = 39, tf_ds = 39, tf_edi =\
69: 2158592, tf_esi = 0, tf_ebp = -272638436, tf_isp = -272629788, tf\
70:_ebx = 7086, tf_edx = 1, tf_ecx = 0, tf_eax = 5, tf_trapno = 582, \
71:tf_err = 582, tf_eip = 75749, tf_cs = 31, tf_eflags = 582, tf_esp \
72:= -272638456, tf_ss = 39}) (../../i386/i386/trap.c line 673)
73:673 error = (*callp-&gt;sy_call)(p, args, rval);
74:<prompt>(kgdb)</prompt> <userinput>up</userinput>
75:Initial frame selected; you cannot go up.
76:<prompt>(kgdb)</prompt> <userinput>quit</userinput>
77:&prompt.root; <userinput>exit</userinput>
78:exit
79:
80:Script done on Fri Dec 30 23:18:04 1994</screen>
<para>Comentarios al listado anterior:</para>
<variablelist>
<varlistentry>
<term>l&iacute;nea 6:</term>
<listitem>
<para>Este es un dump tomado desde el DDB (vea abajo), a partir del
comentario del panic &ldquo;because you said to!&rdquo;, y un
listado de la pila bastante largo; la raz&oacute;n incial para entrar al
DDB fue un trap de falta de pagina.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>l&iacute;nea 20:</term>
<listitem>
<para>Esta es la ubicaci&oacute;n de la funci&oacute;n <function>trap()</function>
en el listado de la pila.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>l&iacute;nea 36:</term>
<listitem>
<para>Se fuerza el uso de un nuevo marco de pila; esto ya no es
necesario ahora. Actualmente se supone que los marcos de pila apuntan a
las ubicaciones correctas, aun en caso de un trap. (No tengo un
dump m&aacute;s nuevo a mano &lt;g&gt;, mi kernel no ha hecho un panic
desde hace bastante tiempo.) Mirando al c&oacute;digo en la l&iacute;nea 403
del c&oacute;digo fuente, hay una alta probabilidad de que la referencia
al puntero &ldquo;tp&rdquo; sea erronea, o el acceso al arreglo
estuviera fuera de sus l&iacute;mites.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>l&iacute;nea 52:</term>
<listitem>
<para>El puntero se ve sospechoso, pero contiene una direcci&oacute;n
v&aacute;lida.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>l&iacute;nea 56:</term>
<listitem>
<para>De todos modos, obviamente apunta a basura, asi que encontramos
nuestro error! (Para los que no esten familiarizados con esa pieza
de c&oacute;digo en particular: <literal>tp-&gt;t_line</literal> hace
referencia a la disciplina de l&iacute;nea de este dispositivo de consola,
el cual debe ser un entero por dem&aacute;s peque&ntilde;o)</para>
</listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1>
<title>Depurando un crash dump con DDD</title>
<para>Tambien es posible examinar un crash dump del kernel con un debugger
gr&aacute;fico como <command>ddd</command>. Agregue la opci&oacute;n <option>-k
</option> a la l&iacute;nea de comando del <command>ddd</command> que usar&iacute;a
normalmente. Por ejemplo;</para>
<screen>&prompt.root; <userinput>ddd -k /var/crash/kernel.0 /var/crash/vmcore.0</userinput></screen>
<para>De esta manera usted deber&iacute;a poder analizar el crash dump usando
la interfaz gr&aacute;fica del <command>ddd</command>.</para>
</sect1>
<sect1>
<title>Analisis Post-mortem de un Dump</title>
<para>Que sucede si un kernel hace un dump de su memoria que usted
no esperaba, y por lo tanto no estaba compilado usando <command>
config -g</command>? No todo esta perdido aqu&iacute;. Do not panic!</para>
<note>
<para>N.del T.: El autor hace un juego con la palabra panic! que
prefiero dejar sin traducir.</para>
</note>
<para>Por supuesto, aun necesita habilitar los crash dumps. Vea m&aacute;s arriba
las opciones que debe especificar para esto.</para>
<para>Vaya a su directorio de configuraci&oacute;n del kernel
(<filename>/usr/src/sys/<replaceable>arq</replaceable>/conf</filename>)
y edite su archivo de configuraci&oacute;n. Quite las marcas de comentario
(o agregue, si no existe) la siguiente l&iacute;nea</para>
<programlisting>
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols</programlisting>
<para>Recompile el kernel. Algunos otros archivos seran recompilados,
por ejemplo <filename>trap.o</filename>, a causa del cambio de la fecha
del archivo Makefile. Con un poco de suerte, la opci&oacute;n <option>-g
</option> no cambiar&aacute; nada del c&oacute;digo generado, al final usted tendra
un kernel con el mismo c&oacute;digo que tiene problemas ahora pero con ciertos
s&iacute;mbolos para depuraci&oacute;n. Por lo menos usted deber&iacute;a verificar el tama&ntilde;o
anterior y el nuevo con el comando &man.size.1;. Si hay diferencia
probablemente sea el momento de darse por vencido.</para>
<para>Ahora puede examinar el dump como se describi&oacute; anteriormente. Los
s&iacute;mbolos pueden estar incompletos para algunas partes, como se puede ver
en el listado de pila del ejemplo anterior donde algunas funciones
se muestran sin numeros de l&iacute;nea ni listas de argumentos. Si necesita
m&aacute;s s&iacute;mbolos borre los archivos objeto apropiados y repita la sesi&oacute;n de
<command>kgdb</command> hasta que haya averiguado lo suficiente.</para>
<para>No se garantiza que todo esto funcione, pero ir&aacute; bastante bien la
en mayor&iacute;a de los casos.</para>
</sect1>
<sect1>
<title>Depuraci&oacute;n En-l&iacute;nea del Kernel Usando DDB</title>
<para>Si bien el <command>kgdb</command> provee un muy alto nivel de
interfaz de usuario como depurador post-mortem, hay cosas que no puede
hacer. Siendo las m&aacute;s importantes poder marcar puntos de interrupci&oacute;n
y ejecutar c&oacute;digo del kernel paso a paso.</para>
<para>Si usted necesita hacer una depuraci&oacute;n a bajo nivel de su kernel hay
disponible un debugger en-l&iacute;nea llamado DDB. Permite poner puntos de
interrupci&oacute;n, ejecutar paso a paso las funciones del kernel, examinar y
cambiar variables, etc. Sin embargo, no puede acceder al c&oacute;digo fuente
del kernel y s&oacute;lo tiene acceso a los s&iacute;mbolos globales y est&aacute;ticos, no
a toda la informaci&oacute;n de depuraci&oacute;n como el <command>kgdb</command>.</para>
<para>Para configurar su kernel para que incluya el DDB, agregue la opci&oacute;n
<programlisting>
options DDB</programlisting>
a su archivo de configuraci&oacute;n, y recompile (vea <link
linkend="kernelconfig">Configuraci&oacute;n del Kernel</link> para m&aacute;s
detalles sobre como configurar el kernel de FreeBSD.)</para>
<note>
<para>Notese que si usted tiene una versi&oacute;n vieja del boot block,
sus s&iacute;mbolos de debugger podr&iacute;an no ser cargados. Actualize su
boot block; los mas recientes cargan los s&iacute;mbolos del DDB
autom&aacute;gicamente.</para>
</note>
<para>Una vez que su kernel con DDB esta corriendo, hay varias maneras
de entrar al DDB. La primera y m&aacute;s temprana es tipear la opci&oacute;n
<option>-d</option> directamente en el prompt de inicio. El kernel
se iniciar&aacute; en modo de depuraci&oacute;n e ingresar&aacute; al DDB antes de cualquier
detecci&oacute;n de dispositivos. De aqu&iacute; en adelante usted podr&aacute;
depurar hasta las funciones probe/attach de los dispositivos.</para>
<para>El segundo escenario es una combinaci&oacute;n de teclas, generalmente
Ctrl-Alt-Esc. En el caso de las syscons, esto puede modificarse,
algunos mapas de teclado distribuidos lo hacen, por lo que hay que
prestar atenci&oacute;n. Hay disponible una opci&oacute;n para consolas en puertos
serie que permite el uso de la se&ntilde;al BREAK en la l&iacute;nea para entrar al
DDB (<literal>options BREAK_TO_DEBUGGER</literal> en el archivo de
configuraci&oacute;n del kernel). Esto no es el default ya que hay un mont&oacute;n
de adaptadores serie dando vueltas que generan condiciones BREAK
sin necesidad, por ejemplo cuando se desenchufa el cable.</para>
<para>La tercera forma es que un panic salte al DDB si el kernel est&aacute;
configurado para usarlo. Por este motivo, no es recomendable configurar
un kernel con DDB para una m&aacute;quina funcionando sin atenci&oacute;n.</para>
<para>Los comandos del DDB se asemejan remotamente a algunos de los
del <command>gdb</command>. Lo primero que usted probablemente
necesite hacer es poner un punto de interrupci&oacute;n:</para>
<screen><userinput>b nombre-de-funci&oacute;n</userinput>
<userinput>b direcci&oacute;n</userinput></screen>
<para>Por default los n&uacute;meros se toman en hexadecimal, pero para
distinguirlos de los nombres de s&iacute;mbolo los n&uacute;meros hexadecimales
que empiezan con las letras <literal>a-f</literal> se deben preceder
con <literal>0x</literal> (para los dem&aacute;s n&uacute;meros esto es opcional).
Tambien se admiten expresiones sencillas, por ejemplo:
<literal>nombre-de-funci&oacute;n + 0x103</literal>.</para>
<para>Para que el kernel interrumpido continue ejecutandose, solo
tipee:</para>
<screen><userinput>c</userinput></screen>
<para>Para ver un listado de la pila, use:</para>
<screen><userinput>trace</userinput></screen>
<note>
<para>Notese que cuando se entra al DDB con una combinaci&oacute;n de teclas
el kernel est&aacute; atendiendo una interrupci&oacute;n, por lo que el listado
de la pila podr&iacute;a no serle de mucha utilidad.</para>
</note>
<para>Si quiere quitar un punto de interrupci&oacute;n, use</para>
<screen><userinput>del</userinput>
<userinput>del expresi&oacute;n-direcci&oacute;n-de-memoria</userinput></screen>
<para>La primera forma se aceptar&aacute; inmediatamente despues de llegar
a un punto de interrupci&oacute;n, y borra el punto actual. La segunda
puede quitar cualquier punto de interrupci&oacute;n, pero se debe
especificar la direcci&oacute;n exacta; esta se puede obtener de:</para>
<screen><userinput>show b</userinput></screen>
<para>Para ejecutar el kernel paso a paso, intente:</para>
<screen><userinput>s</userinput></screen>
<para>Esto entrar&aacute; dentro de las funciones, pero puede hacer
que DDB las siga hasta llegar a la instrucci&oacute;n de retorno
correspondiente usando:</para>
<screen><userinput>n</userinput></screen>
<note>
<para>Esto es distinto de la instrucci&oacute;n <command>next</command>
del <command>gdb</command>; es m&aacute;s parecido a la instrucci&oacute;n
<command>finish</command>.</para>
</note>
<para>Para examinar los datos en la memoria use (por ejemplo):
<screen><userinput>x/wx 0xf0133fe0,40</userinput>
<userinput>x/hd db_symtab_space</userinput>
<userinput>x/bc termbuf,10</userinput>
<userinput>x/s stringbuf</userinput></screen>
para acceder a palabras/medias palabras/bytes, y para mostrar
en hexadecimal/decimal/caracteres/strings. El n&uacute;mero luego de la coma
es la cantidad de objetos. Para mostrar los siguientes 0x10
items, simplemente use:</para>
<screen><userinput>x ,10</userinput></screen>
<para>Del mismo modo, use
<screen><userinput>x/ia foofunc,10</userinput></screen>
para desensamblar las primeras 0x10 instrucciones de
<function>foofunc</function>, y mostrarlas junto con su
desplazamiento desde el comienzo de <function>foofunc</function>.</para>
<para>Para modificar memoria, use el comando write:</para>
<screen><userinput>w/b termbuf 0xa 0xb 0</userinput>
<userinput>w/w 0xf0010030 0 0</userinput></screen>
<para>El modificador
(<literal>b</literal>/<literal>h</literal>/<literal>w</literal>)
especifica el tama&ntilde;o de los datos a ser escritos, la primera expresi&oacute;n
a continuaci&oacute;n es la direcci&oacute;n donde escribir y el resto es interpretado
como datos para escribir en las direcciones de memoria sucesivas.</para>
<para>Si quiere conocer el valor actual de los registros del
procesador, use:</para>
<screen><userinput>show reg</userinput></screen>
<para>O, puede mostrar un solo registro usando:
<screen><userinput>p $eax</userinput></screen>
y modificarlo haciendo:</para>
<screen><userinput>set $eax new-value</userinput></screen>
<para>Si usted quisiera llamar alguna funci&oacute;n del kernel desde
el DDB, solo debe decir:</para>
<screen><userinput>call func(arg1, arg2, ...)</userinput></screen>
<para>El valor devuelto ser&aacute; impreso en la pantalla.</para>
<para>Para un resumen de los procesos corriendo al estilo &man.ps.1;
use:</para>
<screen><userinput>ps</userinput></screen>
<para>Usted ya ha examinado la causa de que su kernel falle, y quiere
reiniciar su equipo. Recuerde que, dependiendo de lo severo de las
fallas que ocurrieron, algunas partes del kernel podr&iacute;an no funcionar
como se espera. Siga una de las siguientes acciones para apagar y
reiniciar su equipo:</para>
<screen><userinput>call diediedie()</userinput></screen>
<para>Esto causar&aacute; que su kernel haga un crash dump y reinicie, asi
luego podr&aacute; analizar el dump a un nivel m&aacute;s alto con el kgdb. Este
comando suele tener que acompa&ntilde;arse por otra instrucci&oacute;n <command>
continue</command>. Para hacer esto hay un alias:
<command>panic</command>.</para>
<screen><userinput>call boot(0)</userinput></screen>
<para>La cual podr&iacute;a ser una buena manera de apagar ordenadamente el
sistema, hacer un <function>sync()</function> de todos los discos,
y finalmente reiniciar. En tanto las interfaces de disco y de
filesystem del kernel no esten da&ntilde;adas, esta podr&iacute;a ser una buena
manera de hacer un apagado bastante prolijo.</para>
<screen><userinput>call cpu_reset()</userinput></screen>
<para>Es la ultima salida de los desastres y es practicamente lo
mismo que presionar el Gran Boton Rojo.</para>
<para>Si usted necesita un breve sumario de los comandos, tipee:</para>
<screen><userinput>help</userinput></screen>
<para>De todos modos, es altamente recomendable tener una copia impresa
de la p&aacute;gina &man.ddb.4; del manual a mano antes de la sesi&oacute;n de
depuraci&oacute;n. Recuerde que es bastante dif&iacute;cil leer el manual en l&iacute;nea
mientras se est&aacute; ejecutando el kernel paso a paso.</para>
</sect1>
<sect1>
<title>Depuraci&oacute;n En-L&iacute;nea Usando El GDB remoto</title>
<para>Esta caracter&iacute;stica ha sido soportada desde FreeBSD 2.2, y ya est&aacute;
en verdad muy bien pulida.</para>
<para>El GDB ha soportado <emphasis>depuraci&oacute;n remota</emphasis> desde
hace mucho tiempo. Esto se hace usando un protocolo muy simple a
traves de una l&iacute;nea serie. A diferencia de los otros metodos descriptos
anteriormente, hacen falta dos m&aacute;quinas para hacer esto. Una va a
proveer el entorno de depuraci&oacute;n, incluyendo todos los archivos fuente,
y una copia del ejecutable del kernel con todos los s&iacute;mbolos y la otra
ser&aacute; la m&aacute;quina a depurar que simplemente corre una copia de exactamente
el mismo kernel (pero sin los s&iacute;mbolos de depuraci&oacute;n).</para>
<para>Usted deber&iacute;a configurar el kernel en cuesti&oacute;n con <command>config
-g</command>, incluir <option>DDB</option> en la configuraci&oacute;n, y
compilarla como siempre. Esto arrojar&aacute; un ejecutable enorme, debido a la
informaci&oacute;n de depuraci&oacute;n. Copie este kernel a la m&aacute;quina a depurar,
quitele los simbolos con <command>strip -x</command>, e inicielo usando
la opci&oacute;n <option>-d</option> en el prompt de inicio. Conecte el primer
puerto serie de la m&aacute;quina a cualquier puerto serie de la m&aacute;quina que
correr&aacute; el debugger. Ahora en la m&aacute;quina que corre el debugger, vaya al
directorio de compilaci&oacute;n del kernel a depurar, y arranque el gdb:</para>
<screen>&prompt.user; <userinput>gdb -k kernel</userinput>
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.16 (i386-unknown-freebsd),
Copyright 1996 Free Software Foundation, Inc...
<prompt>(kgdb)</prompt> </screen>
<para>Inicie la sesi&oacute;n de depuraci&oacute;n remota haciendo
(asumiendo que se usa el primer puerto serie):</para>
<screen><prompt>(kgdb)</prompt> <userinput>target remote /dev/cuaa0</userinput></screen>
<para>Ahora en la m&aacute;quina a depurar (que entr&oacute; al DDB justo antes de
empezar a detectar los dispositivos), tipee:</para>
<screen>Debugger("Boot flags requested debugger")
Stopped at Debugger+0x35: movb $0, edata+0x51bc
<prompt>db&gt;</prompt> <userinput>gdb</userinput></screen>
<para>El DDB responder&aacute; diciendo:</para>
<screen>Next trap will enter GDB remote protocol mode</screen>
<para>Cada vez que tipee <command>gdb</command>, el modo se alternar&aacute;
entre el GDB remoto y el DDB local. Para forzar un siguiente trap
inmediatamente, simplemente tipee <command>s</command> (avanza un paso).
la m&aacute;quina del debugger ahora ganará control sobre el kernel a depurar:
</para>
<screen>Remote debugging using /dev/cuaa0
Debugger (msg=0xf01b0383 "Boot flags requested debugger")
at ../../i386/i386/db_interface.c:257
<prompt>(kgdb)</prompt></screen>
<para>Esta sesi&oacute;n puede usarse casi como cualquier otra sesi&oacute;n de GDB,
incluyendo acceso completo al c&oacute;digo fuente, ejecutarlo en modo-gud
dentro de una ventana de Emacs (lo cual brinda la posibilidad de
mostrar autom&aacute;ticamente el c&oacute;digo fuente en otra ventana de Emacs)
etc.</para>
<para>El GDB remoto tambien puede usarse para depurar LKMs. Primero
compile el LKM con los simbolos de depuraci&oacute;n:</para>
<screen>&prompt.root; <userinput>cd /usr/src/lkm/linux</userinput>
&prompt.root; <userinput>make clean; make COPTS=-g</userinput></screen>
<para>Luego instale esta versi&oacute;n del m&oacute;dulo en la m&aacute;quina a depurar,
carguelo y use <command>modstat</command> para averiguar donde fue
cargado:</para>
<screen>&prompt.root; <userinput>linux</userinput>
&prompt.root; <userinput>modstat</userinput>
Type Id Off Loadaddr Size Info Rev Module Name
EXEC 0 4 f5109000 001c f510f010 1 linux_mod</screen>
<para>Tome la direcci&oacute;n de carga (loadaddr) del m&oacute;dulo y sumele
0x20 (probablemente para contar el encabezado a.out). Esta es la
direcci&oacute;n donde el c&oacute;digo del m&oacute;dulo fue reubicado. Use el comando
<command>add-symbol-file</command> en el GDB para informarle al
debugger acerca del m&oacute;dulo:</para>
<screen><prompt>(kgdb)</prompt> <userinput>add-symbol-file /usr/src/lkm/linux/linux_mod.o 0xf5109020</userinput>
add symbol table from file "/usr/src/lkm/linux/linux_mod.o" at
text_addr = 0xf5109020? (y or n) <userinput>y</userinput>
<prompt>(kgdb)</prompt></screen>
<para>Ahora tiene acceso a todos los s&iacute;mbolos en el LKM.</para>
</sect1>
<sect1>
<title>Depurando Un Driver de Consola</title>
<para>Dado que el DDB necesita un driver de consola sobre el que correr,
las cosas son mas complicadas si lo que falla es el propio driver de
consola. Usted podr&iacute;a entonces recordar el uso de una consola en puerto serie
(ya sea con un sector de inicio modificado, o especificando <option>-h
</option> en el prompt <prompt>Boot:</prompt>) y colgar una terminal
est&aacute;ndar en su primer puerto serie. El DDB funciona en cualquier
driver de consola configurado, por supuesto tambien en una consola de
puerto serie.</para>
</sect1>
</chapter>
<!--
Local Variables:
mode: sgml
sgml-declaration: "../chapter.decl"
sgml-indent-data: t
sgml-omittag: nil
sgml-always-quote-attributes: t
sgml-parent-document: ("../book.sgml" "part" "chapter")
End:
-->

View file

@ -1,216 +0,0 @@
<!--
The FreeBSD Documentation Project
The FreeBSD Spanish Documentation Project
%SOURCE% en_US.ISO8859-1/books/handbook/kernelopts/chapter.sgml
%SRCID% 0.0
$FreeBSD$
$FreeBSDes: doc/es_ES.ISO8859-1/books/handbook/kernelopts/chapter.sgml,v 1.2 2004/10/08 22:14:26 jesusr Exp $
-->
<chapter id="kernelopts">
<chapterinfo>
<authorgroup>
<author>
<firstname>J&ouml;rg</firstname>
<surname>Wunsch</surname>
<contrib>Contribuido por </contrib>
</author>
</authorgroup>
</chapterinfo>
<title>A&ntilde;adiendo Opciones a la Configuraci&oacute;n de un Nuevo Kernel</title>
<note>
<para>Es importante que antes de leer este documento, usted este
familiarizado con la secci&oacute;n de <link
linkend="kernelconfig">configuraci&oacute; del kernel</link>.</para>
</note>
<sect1>
<title>&iquest;Qu&eacute; son las <emphasis>Opciones del Kernel</emphasis>?</title>
<para>B&aacute;sicamente el uso de las opciones del kernel se
encuentran descritas en la secci&oacute;n de <link
linkend="kernelconfig-options">configuraci&oacute;n del kernel</link>.
Tambi&eacute;n existe una explicaci&oacute;n de opciones
<quote>hist&oacute;ricas</quote> y de <quote>nuevo-estilo</quote>. La
meta final es que eventualmente todas las opciones soportadas por el
kernel sean del nuevo-estilo, de tal forma que para las personas que
acertadamente ejecutan <command>make depend</command> en el directorio
de compilaci&oacute;n de su kernel, despu&eacute;s de ejecutar
&man.config.8;, el proceso de compilaci&oacute;n detectar&aacute;
autom&aacute;ticamente las opciones modificadas, y s&oacute;lo
recompilar&aacute; los ficheros donde sea necesario. Eliminando el
anterior directorio de compilaci&oacute;n en cada ocasi&oacute;n que
se ejecute &man.config.8; como es llevado a cabo ahora.</para>
<para>B&aacute;sicamente, una opci&oacute;n del kernel no es otra cosa
que la definici&oacute;n de un macro del preprocesador C para el
proceso de compilaci&oacute;n del kernel. Para efecto de hacer que la
compilaci&oacute;n sea realmente opcional, la parte que corresponde a
la fuente del kernel (o bien el fichero kernel<filename>.h</filename>),
debe ser escrita teniendo en mente, el uso de
las opciones del kernel, por ejemplo, las opciones por omisi&oacute;n
pueden modificarse con la opci&oacute;n config. Esto normalmente se
lleva a cabo con algo como esto:</para>
<programlisting>#ifndef ESTA_OPCION
#define ESTA_OPCION (algun_valor_por_default)
#endif /* ESTA_OPCION */</programlisting>
<para>De esta forma cuando un administrador indica otro valor en su
fichero de configuraci&oacute;n, deja sin efecto el valor que se
tiene originalmente por default, y lo substituye con este nuevo
valor. Claramente el nuevo valor ser&aacute; utilizado como
substituto en el c&oacute;digo fuente, cuando el preprocesador se
ejecute, por lo que debe de tratarse de una expresi&oacute;n
v&aacute;lida para el lenguaje C, sin importar el contexto en el que
se haya estado usando el valor por default.</para>
<para>Tambi&eacute;n es posible crear opciones de menor valor, que
simplemente habilitan o deshabilitan una parte particular del
c&oacute;digo, al encerrarlo en &eacute;l</para>
<programlisting>#ifdef ESTA_OPCION
[su c&oacute;digo aqui]
#endif</programlisting>
<para>Simplemente al incluir <literal>ESTA_OPCION</literal> en su
fichero de configuraci&oacute;n (con o sin valor alguno), activar&aacute;
la parte del c&oacute;digo que haya ingresado.</para>
<para>Para la gente que este familiarizada con el lenguaje C, inmediatamente
podr&aacute; darse cuenta de que todo pudiera ser tratado como una
<quote>opci&oacute;n de configuraci&oacute;n</quote>, donde cuando menos
se tiene una simple referencia del tipo <literal>#ifdef</literal>...
Por otro lado, es poco probable que alguien especifique</para>
<programlisting>options aunno,nodefinida</programlisting>
<para>en su fichero de configuraci&oacute;n, y que posteriormente
se pregunten por que fallo la compilaci&oacute;n del kernel.</para>
<para>Es claro que, el uso de nombres arbitrarios para las opciones,
hacen muy dif&iacute;cil el poder rastrear su uso en el c&oacute;digo
del kernel. Lo anterior es el razonamiento detr&aacute;s del esquema
de opciones de <emphasis>nuevo-estilo</emphasis>, donde cada opci&oacute;n
se localiza en un fichero <filename>.h</filename> diferente dentro del
directorio de compilaci&oacute;n del kernel, los cuales por
convicci&oacute;n son llamados
<filename>opt_<replaceable>foo</replaceable>.h</filename>. De esta
manera se pueden crear las dependencias dispuestas por Makefile, y el
comando <command>make</command> puede determinar que debe ser
recompilado, cuando una opci&oacute;n ha cambiado.</para>
<para>Aun con esto los mecanismos del estilo-viejo, tienen una ventaja
para las opciones locales o quiz&aacute;s para las opciones de
experimentaci&oacute;n, que cuentan con un periodo de vida corto:
en virtud de que es f&aacute;cil a&ntilde;adir un nuevo
<literal>#ifdef</literal> al c&oacute;digo fuente del kernel, lo cual
ya lo ha hecho una opci&oacute;n de configuraci&oacute;n del kernel. En
este caso, al utilizar esta opci&oacute;n, el administrador, es
responsable por completo, al tener conocimiento de las implicaciones
que tiene usarla (y probablemente el forzar la recompilaci&oacute;n de
ciertas partes del kernel). Una vez que la transici&oacute;n de
todas las opciones soportadas por el kernel ha finalizado, &man.config.8;
advertir&aacute; cuando una opci&oacute;n no soportada aparezca en el
fichero de configuraci&oacute;n, y no proceder&aacute; a incluirlo
en el fichero Makefile del kernel.</para>
</sect1>
<sect1>
<title>Ahora, &iquest;Qu&eacute; Debo Hacer?</title>
<para>Lo primero es, editar el fichero <filename>sys/conf/options</filename>
(o bien <filename>sys/<replaceable>&lt;arch&gt;</replaceable>/conf/options.
<replaceable>&lt;arch&gt;</replaceable></filename>, por ejemplo;
<filename>/sys/i386/conf/options.i386</filename>), y seleccionar un
fichero <filename>opt_<replaceable>foo</replaceable>.h</filename> que
mejor describa la nueva opci&oacute;n, para su inclusi&oacute;n.</para>
<para>Si ya existiese alguno, que se acerce al prop&oacute;sito de la
nueva opci&oacute;n, debe elegir ese. Por ejemplo, opciones que
modifiquen el comportamiento global del subsistema SCSI, pueden
incluirse en <filename>opt_scsi.h</filename>. Por default, con el simple
hecho de mencionar una opci&oacute;n en el fichero apropiado, digamos
<literal>FOO</literal>, implica que el valor correspondiente a esta
opci&oacute;n se localiza en el fichero correspondiente
<filename>opt_foo.h</filename>. Por otro lado, esto puede modificarse
al especificar el nombre de otro fichero.</para>
<para>Si el fichero
<filename>opt_<replaceable>foo</replaceable>.h</filename> para la
nueva opci&oacute;n no existiera, invente un nuevo nombre. Creelo de
manera que sea intuitivo, con significado, y comente la nueva
secci&oacute;n en el fichero
<filename>options[<replaceable>.&lt;arch&gt;</replaceable>]</filename>.
En la ejecuci&oacute;n de &man.config.8;, este autom&aacute;gicamente
reconocer&aacute; los cambios, y crear&aacute; ese fichero, la
pr&oacute;xima vez que se ejecute. La mayor&iacute;a de las opciones
deber&aacute;n incluirse como encabezados por si mismos..</para>
<para>El hecho de incluir muchas opciones, dentro de un solo fichero
<filename>opt_<replaceable>foo</replaceable>.h</filename>,
tendr&aacute; como resultado la creaci&oacute;n de un buen numero de
ficheros del kernel, durante la compilaci&oacute;n, cuando s&oacute;lo
se haya realizado un cambio en alguna de las opciones del fichero de
configuraci&oacute;n del kernel, por esta
raz&oacute;n es conveniente conservar cada opci&oacute;n en su
propio fichero <filename>opt_</filename>.</para>
<para>Finalmente, averigue las dependencias que existen para la
nueva opci&oacute;n. A menos que la nueva opci&oacute;n sea de
nueva creaci&oacute;n, y no exista en ninguna parte, la siguiente
alternativa es su amiga, para efecto de encontrar dependencias:</para>
<screen>&prompt.user;
<userinput>find /usr/src/sys -type f | xargs fgrep NUEVA_OPCION</userinput>
</screen>
<para>El comando anterior dar&aacute; como resultado un listado de
ficheros que tienen dependecia, dirijase a todos esos ficheros y
a&ntilde;ada lo siguiente, en la parte <emphasis>superior</emphasis>
(como encabezado), antes de todo lo que se refiere a
<literal>#include &lt;xxx.h&gt;</literal>.</para>
<programlisting>#include "opt_foo.h"</programlisting>
<para>El seguir este orden es de suma importancia, en virtud de que las
opciones pueden modificar el comportamiento, por omisi&oacute;n, de los
ficheros normales del tipo <quote>#include</quote>
(N de T: librer&iacute;s de encabezado), si
estos son del tipo:</para>
<programlisting> #ifndef NUEVA_OPCION #define NUEVA_OPCION (algo)
#endif</programlisting>
<para>El a&ntilde;adir una opci&oacute;n que substituye alg&uacute;n
encabezado, en ficheros del sistema (por ejemplo; un fichero que se
localiza en <filename>/usr/include/sys/</filename>) da como resultado
casi siempre un error. El fichero <filename>opt_<replaceable>foo
</replaceable>.h</filename> no puede ser incluido en esos ficheros,
en virtud de que generaran un conflicto m&aacute;s serio, con sus
propios encabezados, pero si no son incluidos, al momento de que se
deseen utilizar, se puede obtener un valor inconsistente para esta
opci&oacute;n. Si, existen antecedentes de esto en este momento,
pero eso no lo hace m&aacute;s correcto.</para>
</sect1>
</chapter>
<!--
Local Variables:
mode: sgml
sgml-declaration: "../chapter.decl"
sgml-indent-data: t
sgml-omittag: nil
sgml-always-quote-attributes: t
sgml-parent-document: ("../book.sgml" "part" "chapter")
End:
-->