1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
|
<!--
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ón de &a.paul; y &a.joerg;</emphasis></para>
<sect1>
<title>Depuración de un Kernel Crash Dump con <command>kgdb</command></title>
<para>Aquí se dan instrucciones para hacer funcionar la depuració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ña para albergar un dump, puede
configurar su kernel para que use un dispositivo alternativo (en la lí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ón del Kernel</link> para más detalles
sobre la configuració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ó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áusula <literal>dump</literal> en la línea
<literal>config</literal> de su archivo de configuración del kernel.
Esta práctica esta en desuso y sólo debería ser usada para obtener
un dump de un kernel que falla durante el inicio.</para>
<note>
<para>En adelante, el término <command>kgdb</command> se referirá al
<command>gdb</command> corriendo en “kernel debug mode”.
Esto puede lograrse ya sea iniciando al <command>gdb</command> con
la opción <option>-k</option>, o enlazandolo y arrancandolo con el
nombre <command>kgdb</command>. Esto no se hace por default, y
la idea está 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á 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ía instalar el kernel sin hacer el <command>strip</command>,
pero los tiempos de busqueda de algunos programas en la tabla de
símbolos aumentarán sensiblemente, y dado que el kernel se carga completo
en memoria durante el inicio y no puede intercambiarse a disco luego,
se desperdiciará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ó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ón de nombres de símbolo. De otro modo usaria el kernel en uso
y probablemente no haga nada ya que los sí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ón se muestra el log de una sesión de
<command>kgdb</command> que ilustra el procedimiento. Las lí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(&frame, FALSE);
36:<prompt>(kgdb)</prompt> <userinput>frame frame->tf_ebp frame->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->t_line].l_open)(dev, tp));
41:<prompt>(kgdb)</prompt> <userinput>list</userinput>
42:398
43:399 tp->t_state |= TS_CARR_ON;
44:400 tp->t_cflag |= CLOCAL; /* cannot be a modem (:-) */
45:401
46:402 #if PCVT_NETBSD || (PCVT_FREEBSD >= 200)
47:403 return ((*linesw[tp->t_line].l_open)(dev, tp));
48:404 #else
49:405 return ((*linesw[tp->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->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->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ínea 6:</term>
<listitem>
<para>Este es un dump tomado desde el DDB (vea abajo), a partir del
comentario del panic “because you said to!”, y un
listado de la pila bastante largo; la razón incial para entrar al
DDB fue un trap de falta de pagina.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>línea 20:</term>
<listitem>
<para>Esta es la ubicación de la función <function>trap()</function>
en el listado de la pila.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>lí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ás nuevo a mano <g>, mi kernel no ha hecho un panic
desde hace bastante tiempo.) Mirando al código en la línea 403
del código fuente, hay una alta probabilidad de que la referencia
al puntero “tp” sea erronea, o el acceso al arreglo
estuviera fuera de sus límites.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>línea 52:</term>
<listitem>
<para>El puntero se ve sospechoso, pero contiene una dirección
válida.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>lí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ódigo en particular: <literal>tp->t_line</literal> hace
referencia a la disciplina de línea de este dispositivo de consola,
el cual debe ser un entero por demás pequeñ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áfico como <command>ddd</command>. Agregue la opción <option>-k
</option> a la línea de comando del <command>ddd</command> que usarí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ía poder analizar el crash dump usando
la interfaz grá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í. 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ás arriba
las opciones que debe especificar para esto.</para>
<para>Vaya a su directorio de configuración del kernel
(<filename>/usr/src/sys/<replaceable>arq</replaceable>/conf</filename>)
y edite su archivo de configuración. Quite las marcas de comentario
(o agregue, si no existe) la siguiente lí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ón <option>-g
</option> no cambiará nada del código generado, al final usted tendra
un kernel con el mismo código que tiene problemas ahora pero con ciertos
símbolos para depuración. Por lo menos usted debería verificar el tamañ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ó anteriormente. Los
sí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ínea ni listas de argumentos. Si necesita
más símbolos borre los archivos objeto apropiados y repita la sesión de
<command>kgdb</command> hasta que haya averiguado lo suficiente.</para>
<para>No se garantiza que todo esto funcione, pero irá bastante bien la
en mayoría de los casos.</para>
</sect1>
<sect1>
<title>Depuración En-lí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ás importantes poder marcar puntos de interrupción
y ejecutar código del kernel paso a paso.</para>
<para>Si usted necesita hacer una depuración a bajo nivel de su kernel hay
disponible un debugger en-línea llamado DDB. Permite poner puntos de
interrupción, ejecutar paso a paso las funciones del kernel, examinar y
cambiar variables, etc. Sin embargo, no puede acceder al código fuente
del kernel y sólo tiene acceso a los símbolos globales y estáticos, no
a toda la información de depuración como el <command>kgdb</command>.</para>
<para>Para configurar su kernel para que incluya el DDB, agregue la opción
<programlisting>
options DDB</programlisting>
a su archivo de configuración, y recompile (vea <link
linkend="kernelconfig">Configuración del Kernel</link> para más
detalles sobre como configurar el kernel de FreeBSD.)</para>
<note>
<para>Notese que si usted tiene una versión vieja del boot block,
sus símbolos de debugger podrían no ser cargados. Actualize su
boot block; los mas recientes cargan los símbolos del DDB
automágicamente.</para>
</note>
<para>Una vez que su kernel con DDB esta corriendo, hay varias maneras
de entrar al DDB. La primera y más temprana es tipear la opción
<option>-d</option> directamente en el prompt de inicio. El kernel
se iniciará en modo de depuración e ingresará al DDB antes de cualquier
detección de dispositivos. De aquí en adelante usted podrá
depurar hasta las funciones probe/attach de los dispositivos.</para>
<para>El segundo escenario es una combinació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ón. Hay disponible una opción para consolas en puertos
serie que permite el uso de la señal BREAK en la línea para entrar al
DDB (<literal>options BREAK_TO_DEBUGGER</literal> en el archivo de
configuración del kernel). Esto no es el default ya que hay un montó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á
configurado para usarlo. Por este motivo, no es recomendable configurar
un kernel con DDB para una máquina funcionando sin atenció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ón:</para>
<screen><userinput>b nombre-de-función</userinput>
<userinput>b dirección</userinput></screen>
<para>Por default los números se toman en hexadecimal, pero para
distinguirlos de los nombres de símbolo los números hexadecimales
que empiezan con las letras <literal>a-f</literal> se deben preceder
con <literal>0x</literal> (para los demás números esto es opcional).
Tambien se admiten expresiones sencillas, por ejemplo:
<literal>nombre-de-funció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ón de teclas
el kernel está atendiendo una interrupción, por lo que el listado
de la pila podría no serle de mucha utilidad.</para>
</note>
<para>Si quiere quitar un punto de interrupción, use</para>
<screen><userinput>del</userinput>
<userinput>del expresión-dirección-de-memoria</userinput></screen>
<para>La primera forma se aceptará inmediatamente despues de llegar
a un punto de interrupción, y borra el punto actual. La segunda
puede quitar cualquier punto de interrupción, pero se debe
especificar la direcció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á dentro de las funciones, pero puede hacer
que DDB las siga hasta llegar a la instrucción de retorno
correspondiente usando:</para>
<screen><userinput>n</userinput></screen>
<note>
<para>Esto es distinto de la instrucción <command>next</command>
del <command>gdb</command>; es más parecido a la instrucció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ú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ño de los datos a ser escritos, la primera expresión
a continuación es la direcció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ón del kernel desde
el DDB, solo debe decir:</para>
<screen><userinput>call func(arg1, arg2, ...)</userinput></screen>
<para>El valor devuelto será 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í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á que su kernel haga un crash dump y reinicie, asi
luego podrá analizar el dump a un nivel más alto con el kgdb. Este
comando suele tener que acompañarse por otra instrucció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í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ñadas, esta podrí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ágina &man.ddb.4; del manual a mano antes de la sesión de
depuración. Recuerde que es bastante difícil leer el manual en línea
mientras se está ejecutando el kernel paso a paso.</para>
</sect1>
<sect1>
<title>Depuración En-Línea Usando El GDB remoto</title>
<para>Esta característica ha sido soportada desde FreeBSD 2.2, y ya está
en verdad muy bien pulida.</para>
<para>El GDB ha soportado <emphasis>depuración remota</emphasis> desde
hace mucho tiempo. Esto se hace usando un protocolo muy simple a
traves de una línea serie. A diferencia de los otros metodos descriptos
anteriormente, hacen falta dos máquinas para hacer esto. Una va a
proveer el entorno de depuración, incluyendo todos los archivos fuente,
y una copia del ejecutable del kernel con todos los símbolos y la otra
será la máquina a depurar que simplemente corre una copia de exactamente
el mismo kernel (pero sin los símbolos de depuración).</para>
<para>Usted debería configurar el kernel en cuestión con <command>config
-g</command>, incluir <option>DDB</option> en la configuración, y
compilarla como siempre. Esto arrojará un ejecutable enorme, debido a la
información de depuración. Copie este kernel a la máquina a depurar,
quitele los simbolos con <command>strip -x</command>, e inicielo usando
la opción <option>-d</option> en el prompt de inicio. Conecte el primer
puerto serie de la máquina a cualquier puerto serie de la máquina que
correrá el debugger. Ahora en la máquina que corre el debugger, vaya al
directorio de compilació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ón de depuració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áquina a depurar (que entró 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></prompt> <userinput>gdb</userinput></screen>
<para>El DDB responderá diciendo:</para>
<screen>Next trap will enter GDB remote protocol mode</screen>
<para>Cada vez que tipee <command>gdb</command>, el modo se alternará
entre el GDB remoto y el DDB local. Para forzar un siguiente trap
inmediatamente, simplemente tipee <command>s</command> (avanza un paso).
la má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ón puede usarse casi como cualquier otra sesión de GDB,
incluyendo acceso completo al código fuente, ejecutarlo en modo-gud
dentro de una ventana de Emacs (lo cual brinda la posibilidad de
mostrar automáticamente el có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ó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ón del módulo en la má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ón de carga (loadaddr) del módulo y sumele
0x20 (probablemente para contar el encabezado a.out). Esta es la
dirección donde el código del módulo fue reubicado. Use el comando
<command>add-symbol-file</command> en el GDB para informarle al
debugger acerca del mó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í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í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á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:
-->
|