<!--
     The FreeBSD Documentation Project

     $FreeBSD$
-->

<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:
-->

