aboutsummaryrefslogtreecommitdiff
path: root/ja_JP.eucJP/books/handbook/kerneldebug/chapter.sgml
blob: a1690a33c9ab324b8221376d71bdafcd30a8977f (plain) (blame)
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
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
<!--
     The FreeBSD Documentation Project
     The FreeBSD Japanese Documentation Project

     Original revision: 1.13
     $FreeBSD$
-->

<chapter id="kerneldebug">
  <title>カーネルデバッグ</title>

  <para><emphasis>原作 &a.paul; and &a.joerg;</emphasis></para>

  <para><emphasis>訳: &a.jp.yoshiaki;. <!-- <br> -->
      18 March 1997. </emphasis></para>

  <sect1>
    <title><command>kgdb</command>
      によるカーネルのクラッシュダンプのデバッグ</title>

    <para>ここではクラッシュダンプ (crash dump : 訳注 この文脈では
      kernel 自身
      の異常によって停止した場合に出力されるイメージを指します)
      によるカー ネルデバッグの方法を示します.</para>

    <para>ここではダンプするための十分なスワップ
      (swap) の容量があるものとします.
      もし複数のスワップパーティションを持ち,
      最初のパーティションがダンプ
      を保持するのに十分な大きさを持たない場合は
      別のダンプデバイスを使うよ
      うに (<literal>config kernel</literal> 行で)
      カーネルのコンフィグをおこなうか, &man.dumpon.8;
      コマンドを使って別のデバイスを示すことができます. &man.dumpon.8;
      を使うもっともよい方法は変数 <literal>dumpdev</literal><filename>/etc/rc.conf</filename> で設定することです. 一般的には
      <filename>/etc/fstab</filename> で設定されているスワップデバイスが
      使われるでしょう.
      スワップに使えないデバイスへのダンプ,
      例えばテープへのダンプは現在サポートさ
      れていません. カーネルのコンフィグは
      <command>config -g</command> によって行ってください.
      <link linkend="kernelconfig"> FreeBSD
	カーネルのコンフィグレーション </link>
      には FreeBSD のカーネルの設定の詳細がありますので
      参照してください.</para>

    <para>&man.dumpon.8; コマンドを使ってどこへダンプするか
      カーネルに伝えてください
      (&man.swapon.8; によってそのパーティションが
      スワップとして設定された
      後でなければならないことに注意してください). これは普通は
      <filename>/etc/rc.conf</filename><filename>/etc/rc</filename>
      で設定されます. あるいは
      別の方法としてカーネルコンフィグレーションファイルの
      <literal>config</literal> 行の <literal>dump</literal> 節 で
      ダンプデバイスをハードコードすることができます.
      この方法はあまりよくは
      ありません. カーネルがブート時に crash
      する場合のクラッシュダンプを取り
      たい時だけ使うべきです.</para>

    <note>
      <para>以下では <command>kgdb</command>という用語は
	<command>gdb</command>&ldquo;カーネルデバッグモード&rdquo;
	で動かしていることを意味します. <command>gdb</command><option>-k</option>オプションをつけて起動するか
	<command>kgdb</command>という名前でリン
	クして起動することでこのモードになります. デフォルトでは
	このリンク は作られていません. また, このアイデアは
	GNU関係者たちが彼らのツール
	を別の名前で呼び出した時に異なった動作をするということを
	好まない, と いう点で不評です.
	あるいは将来この機能を廃止することになるかもしれません.</para>
    </note>

    <para>カーネルを作った時にそのコピーを
      <filename>kernel.debug</filename> という名前で作 りましょう.
      また, オリジナルに対して <command>strip
	-d</command>を実行します.
      オリジナルを普通にインストールします. また strip
      していないカーネル も同様にインストールすることができますが,
      シンボルテーブルの参照時間
      がいくつかのプログラムでは劇的に増加するでしょう. また,
      カーネル全体 はブート時に読み込まれ
      スワップアウトされないため数メガバイトの物理メ
      モリが無駄になります.</para>

    <para>例えばブートプロンプトで
      新しいカーネルの名前をタイプすることによって,
      新しいカーネルをテストした場合で,
      再びシステムを動かすのに別のカーネ
      ルで立ち上げることが必要な場合はブートプロンプトで
      <option>-s</option>フラグ
      を使いシングルユーザの状態にしてください.
      そして以下のような操作をおこな います.</para>

    <screen>&prompt.root; <userinput>fsck -p</userinput>
&prompt.root; <userinput>mount -a -t ufs</userinput>       # /var/crash 用のファイルシステムを書き込み可能にする
&prompt.root; <userinput>savecore -N /kernel.panicked /var/crash</userinput>
&prompt.root; <userinput>exit</userinput>                  # ...マルチユーザモードへ移行</screen>

    <para>ここに示した &man.savecore.8; は (現在動いているものとは別の)
      カーネルのシンボル名の抽出をおこなうために使っています.
      抽出はデフォルトで
      は現在動いているカーネルに対しておこなわれ,
      クラッシュダンプとカーネルシンボ
      ルのくい違いのためにまったく何もしません
      (訳注:そのためにオプション
      で実際にダンプをおこしたカーネルを指定します).</para>

    <para>クラッシュダンプの起きた後に
      <filename>/sys/compile/WHATEVER</filename>へ行き
      <command>kgdb</command>を動かします.  <command>kgdb</command>
      より次のようにします.</para>

    <screen><userinput>symbol-file kernel.debug</userinput>
<userinput>exec-file /var/crash/kernel.0</userinput>
<userinput>core-file /var/crash/vmcore.0</userinput></screen>

    <para>こうすると,
      クラッシュダンプを使ってカーネルソースを他のプログラムと同様に
      デバッグすることができます.</para>

    <para>次に <command>kgdb</command>
      での手順のセッションのログを示します. 長い行は読
      みやすくするために改行しました. また,
      参照のために行番号を入れてあり ます. ただし, これは実際の
      pcvtコンソールドライバの開発中の実際のエ
      ラーのトレースです.</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 &gt;= 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 &gt;= 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>上の出力についてのコメントをします.</para>

    <variablelist>
      <varlistentry><term>line 6:</term>
	<listitem>
	  <para>これは DDB (後述) からのダンプです. このため
	    &ldquo;because you said to!&rdquo; という
	    panicコメントがつき, ページフォルトのト ラップによって
	    DDBに入ったことが原因の, やや長いスタックトレー
	    スがあります.</para>
	</listitem>
      </varlistentry>

      <varlistentry><term>line 20:</term>
	<listitem>
	  <para>スタックトレースでのこれは
	    <function>trap()</function>関数の位置で す.</para>
	</listitem>
      </varlistentry>

      <varlistentry><term>line 36:</term>
	<listitem>
	  <para>新しいスタックフレームの使用を指定しています. これは現
	    在は必要ありません. trapの場合ではスタックフレームは正
	    しい場所を指していると考えられます. (私は新しいコアダンプ
	    を持っていません. 私のカーネルは長い間 panicを起こしていま
	    せん.)  ソースコードの
	    403行を見ると,&ldquo;tp&rdquo;ポインタのアク
	    セスが失敗しているか配列のアクセスが範囲外である可能性が高
	    いことがわかります.</para>
	</listitem>
      </varlistentry>

      <varlistentry><term>line 52:</term>
	<listitem>
	  <para>怪しいポインタですが,
	    アクセスは正常におこなえました.</para>
	</listitem>
      </varlistentry>

      <varlistentry><term>line 56:</term>
	<listitem>
	  <para>ところが, 明らかにポインタはゴミを指しています. これで
	    エラーを見つけました! (ここのコードの部分からはよくわかり
	    ませんが,
	    <literal>tp-&gt;t_line</literal>はコンソールデバイスの規定
	    する行を参照しているので,
	    もっと小さな整数でなければなりませ ん. )</para>
	</listitem>
      </varlistentry>
    </variablelist>
  </sect1>

  <sect1>
    <title>DDD によるクラッシュダンプのデバッグ</title>

    <para>カーネルのクラッシュダンプは <command>ddd</command>
      のようなグラフィカルなデバッガで調べることもできます.
      通常はコマンドラインで <option>-k</option> オプションをつけて
      <command>ddd</command> を起動します. たとえば:</para>

    <screen>&prompt.root; <userinput>ddd -k /var/crash/kernel.0 /var/crash/vmcore.0</userinput></screen>

    <para>クラッシュダンプを <command>ddd</command>
      のグラフィカルなインターフェースを使って
      見ることができます.</para>
  </sect1>

  <sect1>
    <title>突然ダンプした場合の解析</title>

    <para>カーネルが予想もしない時にコアダンプして <command>config
	-g</command>
      を行ってコンパイルされていなかった場合にはどうしたら
      よいでしょう. すべてが失われるわけではありません.
      パニックを起こさないでください.</para>

    <para>もちろん, クラッシュダンプを使えるようにする必要があります.
      使い方は前述の部分を見てください.</para>

    <para>カーネルのコンパイルディレクトリで, (Makefileの)
      <literal>COPTFLAGS?=-O</literal> とある行を編集します.
      <option>-g</option>オプショ ンをここに加えます
      (オプティマイズオプションのレベルは <emphasis>変更しな
	いでください</emphasis> ).
      もし大まかにコードのどこで問題が起きているか (例 えば,
      上の例では <devicename>pcvt</devicename>ドライバ)
      わかっているのでしたら, その部
      分のコードについてのすべてのオブジェクトファイルを
      消してください. カーネ ルを再構築しましょう.
      Makefileのタイムスタンプの変更により, 例えば  <!-- kuriyama -
      should be filename --> <emphasis remap=tt> trap.o
      </emphasis>などのいくつかの他のオブジェクトファイルも作り直さ
      れます. 少しの幸運があれば,
      <option>-g</option>オプションが追加されても作ら
      れるコードは変更されず, いくらかのデバッグシンボル以外には
      問題を
      起こしたコードとそっくりな新しいカーネルを手に入れることが
      できます. 少なくとも &man.size.1;
      コマンドで古い方と新しい方のサイズを比較すべ きです.
      これが食い違っていれば,
      多分あきらめなければならないでしょう.</para>

    <para>ダンプを使って前述のように動かして調べます.
      デバッグシンボルは 必ずしも十分ではありません.
      上の例ではスタックトレースでいくつかの関
      数の行番号や引数リストが表示されないかもしれません.
      もしより多くのデ バッグシンボルが必要であれば,十分になるまで
      適切なオブジェクトファイ ルを消して (makeして)
      <command>kgdb</command>セッションを繰り返してください.</para>

    <para>これは必ずしもうまく動くと保証はできません.
      しかしほとんどの場合でう まくいくでしょう.</para>
  </sect1>

  <sect1>
    <title>DDBを使ったオンラインカーネルデバッグ</title>

    <para><command>kgdb</command>
      は非常に高レベルのユーザインタフェースを提
      供するオフラインデバッガですが, いくつかのことはできません.
      (できないことの中で)
      極めて重要なことはカーネルコードへのブレークポイ
      ントの設定とシングルステップ実行です.</para>

    <para>カーネルの低レベルデバッグが必要であれば, DDBと呼ばれる
      on-lineデバッ ガが使えます. ブレークポイントの設定,
      シングルステップのカーネルの実 行,
      変数の検査と変更などができます.
      ただし,これはカーネルのソースファ
      イルにアクセスすることはできません.
      <command>kgdb</command>のようにすべてのデ
      バッグ情報にはアクセスできず, globalと
      staticのシンボルにアクセス することができるだけです.</para>

    <para>カーネルに DDB
      を含めるためにはコンフィグファイルに次のようなオプショ
      ンを加えて,</para>

    <programlisting>
options DDB</programlisting>

    <para>再構築をおこないます. (
      FreeBSDのカーネルの設定の詳細については<link
	linkend="kernelconfig"> FreeBSD
	カーネルのコンフィグレーション</link>を参照してくださ
      い.</para>

    <note>
      <para>もしブートブロックが古いバージョンですと,
	デバッガのシンボルが完
	全にはロードされないかもしれませんので注意してください. DDB
	シンボル がロードされるようにブートブロックを
	最新の物にアップデートしてくださ い)</para>
    </note>

    <para>DDB カーネルの実行において,
      DDBに入るいくつかの方法があります. 最初 の,
      最も早い方法はブートプロンプトが出ている時に
      <option>-d</option>のブート フラグをタイプすることです.
      カーネルはデバッグモードで起動し, デバ イスのプローブ以前に
      DDBに入ります. したがって, デバイスのプローブ/初期
      設定ファンクションのデバッグができます.</para>

    <para>2つ目のシナリオはキーボードのホットキーで, 通常は
      Ctrl-Alt-ESCです. syscons ではホットキーは再設定することができ,
      配付されているいくつかの キーマッピングでは別のキーに
      再設定されていますので確認しておいてください. シリアルラインの
      BREAKを使って シリアルコンソールから DDBへ入ることを可
      能にするオプションもあります
      (カーネルコンフィグレーションファイルの  <literal>options
	BREAK_TO_DEBUGGER</literal>). これは 多くのつまらないシリ
      アルアダプタが, 例えばケーブルを引き抜いた時に
      BREAK状態を意味もなく
      作り出してしまうのでデフォルトでは無効になっています.</para>

    <para>3つ目は, DDB
      を使うようになっているカーネルがパニック状態になると DDB
      へ入るというものです. このため,
      無人運転するマシンのカーネルにDDBを
      入れるのは賢明ではありません.</para>

    <para>DDB のコマンドはおおまかには <command>gdb</command>
      のいくつかのコマンドと似て
      います. おそらく最初にブレークポイントを
      設定する必要があるでしょう.</para>

    <screen><userinput>b function-name</userinput>
<userinput>b address</userinput></screen>

    <para>数値はデフォルトでは16進数で,
      シンボル名とはまったく異ります. 16進数で <literal>a-f</literal>
      の文字で始まる場合は, 先頭に <literal>0x</literal>
      をつける必要があります(それ以外の数字の場合はどちらでもか
      まいません).  <literal>function-name +
	0x103</literal>のような単純な式を使うこ とができます.</para>

    <para>割り込みされたカーネルから処理を続行するためには, </para>

    <screen><userinput>c</userinput></screen>

    <para>とタイプするだけです.
      スタックのトレースには</para>

    <screen><userinput>trace</userinput></screen>

    <para>とします.</para>

    <note>
      <para>DDB にホットキーで入った場合は, カーネルはその
	(ホットキーの) 割り込み
	の処理を行っていますのでスタックトレースは
	あまり役にたたないことに注 意してください.</para>
    </note>

    <para>ブレークポイントを削除したい場合は,</para>

    <screen><userinput>del</userinput>
<userinput>del address-expression</userinput></screen>

    <para>とします.
      最初の形式はブレークポイントにヒットしたすぐ後で使うことが でき,
      現在のブレークポイントを削除します. 2番目の形式では任意のブレー
      クポイントを削除することができますが,
      次の形式で得られるような正確な
      アドレスを与えることが必要です.</para>

    <screen><userinput>show b</userinput></screen>

    <para>カーネルをシングルステップ実行させるには</para>

    <screen><userinput>s</userinput></screen>

    <para>としてみてください. これは関数呼出し先までステップ実行 (step
      into function) するでしょう.
      次のステートメントが終了するまでのDDBトレースは</para>

    <screen><userinput>n</userinput></screen>

    <para>によっておこなうことができます.</para>

    <note>
      <para>これは <command>gdb</command><command>next</command>
	命令とは異ります. <command>gdb</command><command>finish</command>命令と似ています.</para>
    </note>

    <para>メモリ上のデータを調べるには (例として) 次のようにします.

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

      word/halfword/byte 単位でアクセスをおこない, hex (16進)
      /dec (10進) /
      char (文字) /string (文字列) で表示します.
      カンマの後ろの数字はオブジェク
      トカウントです. 次の 0x10個の要素を表示するには, 単純に</para>

    <screen><userinput>x ,10</userinput></screen>

    <para>とします. 同様に次のように使うことができます.

      <screen><userinput>x/ia foofunc,10</userinput></screen>

      <function>foofunc</function>
      の最初の 0x10個の命令語をディスアセンブルし,
      <function>foofunc</function>
      の先頭からのオフセットとともに表示します.</para>

    <para>メモリの内容を変更するには writeコマンドを使います.</para>

    <screen><userinput>w/b termbuf 0xa 0xb 0</userinput>
<userinput>w/w 0xf0010030 0 0</userinput></screen>

    <para>コマンドモディファイアの
      (<literal>b</literal>/<literal>h</literal>/<literal>w</literal>)
      はデータを 書くサイズを定義し,
      これに続く最初の式は書き込むアドレス, 残りがこれ
      に続く連続するメモリアドレスに書き込まれるデータになります.
    </para>

    <para>現在のレジスタ群の内容を知りたい場合は</para>

    <screen><userinput>show reg</userinput></screen>

    <para>とします. また, 単一のレジスタの値を表示するには, 例えば

      <screen><userinput>p $eax</userinput></screen>

      とします. また値の変更は</para>

    <screen><userinput>set $eax new-value</userinput></screen>

    <para>とします.</para>

    <para>DDBからカーネルの関数を呼び出す必要がある場合は, 単に</para>

    <screen><userinput>call func(arg1, arg2, ...)</userinput></screen>

    <para>とします. return 値が出力されます.</para>

    <para>動いているプロセスの &man.ps.1; スタイルの概要は</para>

    <screen><userinput>ps</userinput></screen>

    <para>です.</para>

    <para>カーネルの失敗の原因の調査が終わったらリブートすべきです.
      それまでの 不具合によりカーネルのすべての部分が期待するような
      動作をしているわけ ではないということを忘れないでください.
      以下のうちいずれかの方法でシ
      ステムのシャットダウンおよびリブートを行ってください.</para>

    <screen><userinput>call diediedie()</userinput></screen>

    <para>カーネルをコアダンプしてリブートしますので, 後で
      kgdbによってコアの高 レベル解析をすることができます.
      このコマンドは通常
      <command>continue</command>命令にエイリアスされています.
      <command>panic</command>にエイリアスされている</para>

    <screen><userinput>call boot(0)</userinput></screen>

    <para> は動いているシステムを `clean' に shut
      downするよい方法です. すべて のディスクを
      <function>sync()</function>して最後にリブートします.
      ディスクとカー
      ネルのファイルシステムインタフェースが破損していない限り,
      ほぼ完全 に `clean'にシャットダウンするよい方法でしょう.</para>
    <!-- kuriyama - ldquo? -->

    <screen><userinput>call cpu_reset()</userinput></screen>

    <para>は大惨事を防ぐための最後の手段で 「赤い大きなボタン」
      を押すのとほとんど 同じです.(訳注:
      リセットボタンを押すのとほぼ同じであるという意味です)</para>

    <para>短いコマンドの要約は</para>

    <screen><userinput>help</userinput></screen>

    <para>をタイプします. ただし, デバッグセッションのために
	&man.ddb.4; の
      マニュアルページのプリントアウトを用意しておくことを
      強くお奨めします.
      カーネルのシングルステップ中にオンラインマニュアルを
      読むことは難しい ということを覚えておいてください.</para>
  </sect1>

  <sect1>
    <title>リモート GDB を使ったオンラインカーネルデバッグ</title>

    <para>この機能は FreeBSD 2.2 からサポートされました.
      これは本当にすばらし い機能です.</para>

    <para>GDB はすでにかなり以前より
      <emphasis>リモートデバッグ</emphasis> をサポートしてい ます.
      これはシリアル回線を使い非常に単純なプロトコルで行ないます.
      もちろん, この方法では今までに示した方法とは違い,
      2台のマシンが必 要になります. 1台はデバッグ環境のためのホストで,
      すべてのソースとす
      べてのシンボルを含んだバイナリのコピーを持っています. もう 1台は
      ターゲットマシンで, 同一のカーネルのコピー (ただしデバッグ情報は
      取り除いてあるもの) を単に実行するためのものです.</para>

    <para>この場合, カーネルのコンフィグレーションは <command>config
	-g</command> で行な い, <option>DDB</option>
      を含めなくてはなりません. そうして通常通りコンパイルし ます.
      こうして作ったバイナリファイルはデバッグ情報のために非常に大き
      くなります.  このカーネルをターゲットマシンにコピーして
      <command>strip -x</command> でデバッグシンボルを取り除きます.
      そして <option>-d</option>  ブートオプションを使いブートします.
      ターゲットマシンの 1番目の シリアル回線をデバッグホストの
      いずれかのシリアル回線につないでおきま しょう.
      それからデバッグ(訳注:ホスト)マシン上で, ターゲットとなって
      いるカーネルのコンパイルディレクトリで 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>リモートデバッグセッションの初期化
      (1番目のシリアルポートを使用する ことの設定)
      を以下のように行ないます.</para>

    <screen><prompt>(kgdb)</prompt> <userinput>target remote /dev/cuaa0</userinput></screen>

    <para>次にターゲットマシン (デバイスのプローブ直前で DDB
      に入っています) で次のように入力します:</para>

    <screen>Debugger("Boot flags requested debugger")
Stopped at	Debugger+0x35: movb	$0, edata+0x51bc
<prompt>db&gt;</prompt> <userinput>gdb</userinput></screen>

    <para>DDB は次のような出力を返すでしょう. </para>

    <screen>Next trap will enter GDB remote protocol mode</screen>

    <para><command>gdb</command>と入力するたびに リモート GDB
      とローカル DDB が交互に切り替わ ります.
      トラップをすぐに起こすために単に ``s'' (step) と入力して下 さい.
      そうするとホストの GDB はターゲットのカーネルの制御を行なうよ
      うになります.</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>このセッションではソースコードへのフルアクセスや Emacs の
      window 上 の gud-mode (これは別の Emacs window
      に自動的にソースコードを表示し ます) で動かすなど, 通常の GDB
      セッションでできることのほとんどのこ とができます.</para>

	<para>リモート GDB は LKM のデバッグも行なうことができます.
      最初に LKM を デバッグシンボルを含めた形で作ります. </para>

    <screen>&prompt.root; <userinput>cd /usr/src/lkm/linux</userinput>
&prompt.root; <userinput>make clean; make COPTS=-g</userinput></screen>

    <para>そしてターゲットマシン上で
      モジュールのこのバージョンをインストールし ます.
      これをロードしてから, <command>modstat</command>
      を使ってロードされている ことを確認してください:</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>示されたロードアドレスに 0x20
      (a.outのヘッダはおそらくこの大きさでしょ う) を加えます.
      それがモジュールコードの再配置されるアドレスです.  GDB の
      <command>add-symbol-file</command>
      コマンドを使ってデバッガにモジュールの 情報をつたえます.</para>

<!-- kuriyama - This part of English is different caused by nik? -->
    <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>これで LKM
      のすべてのシンボルにアクセスできるようになります.</para>
  </sect1>

  <sect1>
    <title>コンソールドライバのデバッグ</title>

    <para>DDBを動かすためにはコンソールドライバが必要ですから,
      コンソールドラ イバ自身に不具合のある場合は複雑になります.
      シリアルコンソールを利 用する方法 (ブートブロックを変更するか
      <prompt>Boot:</prompt>プロンプトで
      <option>-h</option>と入力する) を思い出してください.
      そして標準ター ミナルを最初のシリアルポートに設定します.  DDBは,
      もちろんシリアルコ ンソールを含むいずれの
      コンソールドライバの設定でも動作します.</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: ("../handbook.sgml" "part" "chapter")
     End:
-->