連載 / v6 の実装ー⑦ 図 6 既存のリンクローカル・アドレスに対する対応付けキャッシュの更新 220 225 226 227 228 229 230 232 233 234 235 236 239 240 242 243 244 245 215 else llmbc—>mbc—pcoa = bi—>mbc—pcoa; llmbc—>mbc—flags = bi—>mbc—flags ; llmbc—>mbc-seqno = bi->mbc-seqno; llmbc—>mbc_lifetime = bi—>mbc_lifetime; —>mbc_expire time_second + llmbc—>mbc_lifetime; 11mbc mip6—bc—encapcheck, &llmbc—>mbc—encap)) { if (mip6-tunne1-contr01 (MIP6-TUNNEL-CHANGE, llmbc , mip6-bc—settimer(11mbc, mip6-brr—time(11mbc) ) ; mip6—bc—settimer(IImbc, llmbc->mbc_state = MIP6_BC_FSM_STATE_BOUND ; 0x7fffffff ; llmbc—>mbc—expire if (llmbc->mbc—expire く time-second) llmbc—>mbc—flags ー = IP6MU—CLONED ; mip6—dad—start (llmbc) ; 206 行目で移動ノードのリンクローカル・アドレスに対 する対応付けキャッシュを作成し、 215 行目で重複アドレ スの検出 ( を開始します。 216 } else if (MIP6-IS-BC—DAD_WAIT(11mbc) ) { 217 218 219 llmbc—>mbc—pcoa = bi—>mbc—pcoa; llmbc—>mbc—seqno = bi—>mbc—seqno; busy + + ; 217 ~ 219 行目は、重複アドレス検出中に、同じリンク ローカル・アドレスに対する対応付けの更新要求がきた場 合の処理です。このとき、移動ノードの気付アドレスと、対 応付け更新メッセージの通し番号を更新し、重複アドレス 検出の終了を待ちます。 図 6 の 225 ~ 244 行目は、既存のリンクローカル・アド レスに対する対応付けキャッシュの更新です。 225 ~ 230 行目で、移動ノードの気付アドレス (mbc-pcoa) 、対応付 けキャッシュのフラグ (mbc-flags) 、通し番号 (mbc-seq- (o) 、有効時間 (mbc 」 ifetime) 、有効時間が切れる時刻 (mbc-expire) を更新します。なお、 232 ~ 233 行目で有 効時間が 32 ビット符号付き整数の上限を超えたときの対 応をおこないます。 234 ~ 236 行目は、キャッシュの : 大態の設定とタイマー 関数の設定です。対応付け更新を受信した直後は、 234 行 目で BOUND 状態となります。この状態は、時間カ騷過 して有効時間が短くなると、対応付け再更新要求メッセー 86 ジを送信するために WAITBI や WAITB2 状態に遷移 します。遷移までの時間は mip6-bc-settimer() で指定 されます。対応付け再更新メッセージを送信するタイミン グは、仕様では規定されていません。 KAME では、有効 時間の半分カ釜過したときと 4 分の 3 が経過したときに、 必要であれば送信します。 239 行目は移動ノードに対する = NULL) { 252 if (mbc かれば 274 行目の更新処理に進みます。 リを検索し、存在しなければ 254 行目の作成処理に、みつ 251 行目でホームアドレスに対するキャッシュ・エント (&mip6-bc—1ist , &bi—>mbc—phaddr) ; 251 mbc = mip6-bc-1ist—find-withphaddr ュ情報の作成 / 更新処理に進みます。 続いて、移動ノードのホームアドレスに対するキャッシ め、 IP6MU-CLONED フラグを設定します。 -LINK によって作成されたエントリであることを示すた 最後に 244 行目で、この対応付けキャッシュが IP6MU トンネルリンクの設疋です。 254 255 256 257 259 260 mbc = mip6—bc—create(&bi—> if mbc—phaddr, &bi—>mbc—pcoa, &bi—>mbc—addr, bi—>mbc—flags , bi—>mbc—seqno , bi->mbc—lifetime , hifp) ; = NULL ) { (mbc return ( ー 1 ) ; UN 工 X MAGAZINE 2004.4
連載 /FreeBSD のブートプロセスをみる 2 , 128 ~ 2 , 131 行目では、 gdp¯>gd—dpl = 3 ; 、カーネル・メッセージバッ アとは、 dmesg コマンドで表示される内容をイ尉寺している ファ " を初期化しています。カーネル・メッセージバッフ バッフアです。 コー丿レゲートの言聢 図 13 セグメント・セレクタの形式 lndex 羽 RPL 2134 : 2135 : 2136 : 2137 : 2138 : 2139 : 2140 : 2141 : 2142 : 2143 : gdp = &ldt [LSYS5CALLS—SEL] . gd; (int) &X1ca11—sysca11; X gdp—>gd—hioffset = x > > 16 ; SDT_SYS386CGT ; gdp—>gd—stkcpy = 1 ; selector = GCODE—SEL くく gdp—>gd—looffset = x; gdp¯>gd-p = 1 ; gdp—>gd—type = gdp->gd- 2160 : 2161 : 2162 : 2163 threadO. td—pcb—>pcb—ext = 0 ; threadO. td-frame = &procO—tf ; 3 ー 0 ; FreeBSD のユーザープロセスは、次の 2 つの方法でシ 略します。ただ、このようにしてサポートされているとい だけにかぎりませんが ) 、コールゲートについての説明は省 す。 a. out は FreeBSD では旧い形式なので (FreeBSD ポートするために、 LDT にコールゲートを設疋していま 2 , 134 ~ 2 , 143 行目は、 a. out 形式の実行ファイルをサ していました。 イルは、 LCALL 7 0 命令を実行するコールゲートを利用 Xint0x80-syscall です ) 。一方、以前の a. out 形式のファ 生させてシステムコールを呼び出します ( 2 , 060 行目の イルは、 INT 80H 命令によりソフトウェア割込みを発 最近の FreeBSD で使われている ELF 形式のファ ・コールゲート ・ソフトウェア割込み ステムコールを呼び出します。 うことだけ知っておくとよいでしよう。 PCB の言又疋 0150 : 0209 : 2151 : 2152 : 2153 : 2154 : 2155 : 2159 : 170 int _udatasel , static struct ucodesel = udatasel = _ucodesel; trapframe procO—tf ; LUDATA—SEL くく 3 ー 4 ー 3 ; LUCODE—SEL くく 3 ー 4 ー 3 ; / * setup proc O's pcb * / threadO. td—pcb—>pcb—flags threadO. td—pcb—>pcb—cr3 Id1ePTD ; 2 , 151 ~ 2 , 152 行目では、ユーザープロセスのコードと データ用のセグメント・セレクタ値を大域変数 - ucodesel と -udatasel に設疋しています。これら 2 つのセグメン トは LDT に登録されているため ( 1 , 421 ~ 1 , 440 行目 ) 、 LDT を参照するように下位 3 ビット目がセットされます ( 図 13 ) 。 2 , 155 ~ 2 , 161 行目は、 swapper のスレッドを管理す る構造体 thread0 の PCB を初期化しています ( 図 1 の struct pcb" です )。ところが、 2 , 159 行目の pcb-cr3 に ついては、前回説明した btext の以下の行ですでに設疋さ れているはずです。 0343 : movl 0344 : 0345 : movl (2*PAGE_SIZE—PCB_SIZE + PCB—CR3) (%eax) 2 , 159 行目を実行する直前に pcb-cr3 の値を調べてみる と、 IdIePTD の値が格納されています。この行は不要で はないかと思います。 工 d1ePTD, %esi ☆ 次回は、 getmemsize() をとりあげます。 ( しらさき・ひろお IIJ) [ 赭文献 ] [ 1 ] Jason Evans, Kernel-Scheduled Entities for Free- BSD, November 7 , 2000 UNIX MAGAZINE 2004.4
特集 デバッガの基礎知識 図 17 ブレークポイントの削除 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 (gdb) inf0 break Disp Enb Address What Num Typ e 1 breakpoint keep y 0X08048381 in main at samp1e3. c : 9 breakpoint already hit 1 time 2 breakpoint keep y 0X08048368 in main at samp1e3. c : 6 ( gdb ) run The program being debugged has been started already. Start it from the beginning? (y or Ⅱ ) y Starting program : /Programs/Samp1e3/a. out Breakpoint 2 , main ( ) at samp1e3. c : 8 sprintf (buf , " 7 8 (gdb) cl DeIeted breakpoint 2 (gdb) 図 18 番号指定によるブレークポイントの畭 (gdb) inf0 break Num Type 1 breakpoint (gdb) d 1 (gdb) info break Disp Enb Address What keep y 0X08048381 in main at samp1e3. c : 9 NO breakpoints or watchpoints . (gdb) えます ( 13 ~ 17 行目 ) 。しかし、実際に run コマンドでプ ログラムを実行してみると、プログラムは 8 行目で停止し ます ( 18 ~ 22 行目 ) 。 6 行目以降で最初にプレークポイン トが設定できる行は 8 行目ですから、プレークポイントが 自動的にこの行に変更されたわけです。 以下では、プログラムの先頭から動作を確認したいので、 こまでに設疋したプレークポイントをすべていったん削 除します。そして、 main 関数の入り口に新たにプレーク ポイントを設定してみます。 プレークポイントを削除するには、 clear ( 省略形は cl) か delete ( 省略形は d) コマンドを使います。 clear はプレークポイントで停止しているとき、そのプ レークポイントを削除する際にイリです。 図 17 を見てください。プレークポイント 2 でプログラ ムが止まっているときに clear コマンドを実行すると、プ レークポイント 2 だけカ哨リ除され ( 14 ~ 15 行目 ) 、プレー クポイント 1 はそのまま残ります。 一方、 delete コマンドでは、番号を指定して任意のプ レークポイントを削除することができます ( 図 18 ) 。 すべてのプレークポイントをまとめて削除したいとき は、引数を付けずに delete コマンドを指定します ( 図 19 ) 。 この場合は、、、本当にすべてのプレークポイントを削除して 44 いいですか ? " という確認メッセージが表示され、これに対 して、、 y " と入力すると実際に削除されます。事前に、、 set confirm 。仕 " というコマンドを実行しておけば、この確認 メッセージを表示せずに削除することもできます。 すべてのプレークポイントを削除したら、 main 関数に プレークポイントを設定します ( 図 20 ) 。 実際には、 main 関数のなかで最初にプレークポイント カ第又疋できる行、すなわち 8 行目にプレークポイントカ毅 定されます。プログラムを実行して、変数にどのように値 が本帑内されているのかを調べてみます。 (gdb) run The program being debugged has been started=> already. Start it from the beginning? (y or n) y Starting program : /Programs/Samp1e3/a. out Breakpoint 5 , main ( ) at samp1e3. c : 8 8 (gdb) sprintf (buf , このように、 gdb では任意の時点で繰り返し run コマン ドを実行し、プログラムを最初から実行しなおすことがで きます。すでに実行されている場合は、上例の 3 行目のよ うに、、本当に最初から実行してもいいですか ? " と訊かれま UNIX MAGAZINE 2004.4
連載 /FreeBSD のブートプロセスをみる 図 11 タスクステート・セグメント (TSS) ビット 図 12 create-pagetables() で作られるべージング 仮想アドレス 0 15 I/O マップアドレス 0000 0000 0000 0000 0000 0000 0000 0000 100 LDT セグメント・セレクタ 96 GS 92 FS 88 DS SS CS ES C0000000 84 バイト 0 6 2 6 2 EDI ESI EBP ESP EBX EDX ECX EAX EFLAGS EIP CR3 ESP2 ESPI ESPO 物理アドレス 48 44 00000000 40 36 がプロテクトモードで動作しているときは BIOS を呼び出 せないので、一時的にイ反想 8086 モードに移行して BIOS 28 SS2 24 サービスを呼び出します。 20 SSI 前回も述べたように、現在のページテープルでは、カー 12 ネルのコードとデータ領域力己置されているべージフレー SSO 8 4 ムが仮想アドレス空間にマッピングされています ( 図 12 ) 。 次のタスクへのリンク 0 図の灰色の部分はコードとデータ領域が収まる大きさにな っており、計算機に載っている物理メモリのサイズは考慮 目の設定は無意味のような気がします。このコードの意図 されていません。 も謎です ( 0 のままにしておいてよいと思います ) 。 getmemsize() は、 BIOS サービスを使って OS カ吏用 / * XXX unimplemented i/O permission bitmap * / できるメモリのサイズと配置を調べます ()C 互換機には システムに予約されている領域があります ) 。詳細は次回 2 , 099 行目は、デスクリプタ GPROCO-SEL ( 1 , 292 行 に解説します。 目 ) のアドレスを tss-gdt に設疋し、 2 , 100 行目では、デ スクリプタの内容を common-tssd にコピーしています。 2 , 123 行目の init-param2() は、 1 , 955 行目と同様に 以下の名前の塘竟変数を読み込んで丿け或変数に定します。 最後に、 2 , 102 行目で LTR 命令を実行して TSS を CPU にロードします。 ・ kern. nbuf ern. maxusers ペーシテーブルの再言又疋 kern. maxproc ・ kern. ncallotlt ・ kern. maxfiles vm86—initia1ize() ; 2121 : getmemsize(first) ; 2122 : カーネル・メッセージバッフアの初期化 init—param2 (physmem) ; 2123 : for (off = 0 ; 2 , 121 行目の vm86-initialize() は、イ磨誤 8086 モード off く round—page (MSGBUF—SIZE) ; を利用するためのセグメント・デスクリプタなどの環境を off + = PAGE—SIZE) pmap—kenter (msgbufp + Off , 2129 : 整えます。 avail—end + 0ff) ; 2 , 122 行目の getmemsize() は、 BIOS のサービスを 2130 : msgbufinit (msgbufp, MSGBUF—SIZE) ; 2131 : 利用して物理メモリサイズを取得します。ところが、 CPU 0000 0000 0000 0000 2128 : 169 UNIX MAGAZINE 2004.4
連載 /FreeBSD のブートプロセスをみる 図 6 カーネルとユーザー用のセグメント FFFFFFFF ん。 FreeBSD では、ユーザープロセス用のセグメント・ デスクリプタは LDT に設定します 2 。 GDT で設疋している TSS と LDT デスクリプタは、 それぞれのテープルの開始アドレスと大きさを表している だけで、内容はあとで作成されます。 カーネル用 コード セグメント GCODE SEL カーネル用 セグメント GDATA_SEL ユーザー用 コード セグメント LUCODE_SEL BFBFFFFF ユーザー用 セグメント LUDATA_SEL 00000000 0211 : 1973 : 1974 : 1975 : 1976 : 1977 : 1978 : static struct pcpu ——pcpu ; pc = &——pcptl; gdt—segs [GPRIV—SEL] . ssd—limit = atop(sizeof (struct pcpu) gdt—segs CGPRIV—SEL] . ssd-base = (int)pc ; gdt—segs [GPROCO—SEL] . ssd—base = (int) &pc—>pc—common—tss ; 表 1 カーネルが使用するセグメントとセグメント・レジスタ セグメント名 GCODE-SEL GDATA-SEL GPRIV-SEL セグメント・レジスタ CS SS 、 DS 、 ES 、 GS FS ス用のコードとデータセグメントカ又疋されます。 1 , 283 行目でも同様のデータセグメントを定義していま すが、このセグメントは CPU ごとの状態を管理するデー タ構造体 (struct pcpu) にアクセスするだけの用途に使 用されます。この記事で解説するカーネルは SMP を肩豺是 としていませんが、 CPU が 1 つの場合でも、℃ PU ごと (per-cpu)" のデータ構造を 1 つ作成します。 1 , 283 行目 で定義されているべースアドレスとリミット値は仮の値で、 杢するコードで書き換えられます。 以上 3 つのセグメントは、あとで表 1 に示すレジスタか らアクセスできるように言定されます。 1 , 292 行目は、 swapper 用の TSS (Task State Seg- ment) デスクリプタです。同じくべースアドレスは彳杢の コードで書き換えられます。最後の 1 , 302 行目は、 LDT (Local Descriptor Table) デスクリプタです。 こまでのデスクリプタの説明で、、、あれ ? " と思ったこ とはないでしようか。 GDT のなかには、ユーザープロセ スを実行するためのセグメント・デスクリプタがありませ 164 1 , 283 行目のセグメント GPRIV-SEL は、 211 行目 の pcpu 構造体 ( 図 7 ) の変数 --pcpu を参照できるだけ の範囲が 1 , 974 ~ 1 , 977 行目で設定されます。この構造 体は sys/PCPU. h (CPU 非依存部 ) と machine/pcpu. h (CPU 依存部 ) で定義され、 CPU の状態を管理するため に使用されます。図 7 には見るからに難しそうな名前が並 んでいますが、こではすべてを理解する必要はありませ ん。後述のコードに書かれている文字列と同じ名前をみつ けて、、、ふ ~ ん " と思うくらいでよいでしよう。 1 , 283 行目の最後のエントリ (G フラグ ) に 1 を設疋 しているので、セグメント・デスクリプタのリミット値は 4KB ページ単位で計算されます。 1 , 975 行目の atop() は、次のように定義されているマクロで、引数を 4 , 096 で 割った値を求めます ( 4 , 096 はページのサイズです ) 。 #define atop(x) ((x) > > 12 ) pcpu 構造体の大きさは 392 バイトなので、リミット 値には 0 カ第ス疋されます。しかし、デスクリプタのリミッ ト値には、、実際のサイズー 1 " を設定することになってい るので、けっきよく GPRIV-SEL セグメントの大きさは 4 , 096 バイトになります。 1 , 978 行目では、 TSS のべースアドレスを TSS デスク リプタに設疋しています。 1231 : union descriptor gdt [ 15 ] ; struct region—descriptor r—gdt ; 1926 : 2 Linux 2.4. x では、 GDT にカーネル用とユーザープロセス用のセグメン ト・デスクリプタを設定します。 UNIX MAGAZINE 2004.4
特集 デバッガの基礎知識 図 9 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 コアファイル名を指定して gdb をカ % gdb a. out core. 1779 GNU gdb Red Hat Linux ( 5 .3post—O .20021129.18r れ ) Copyright 2003 Free S0ftware Foundation, lnc . GDB is free software, covered by the GNU GeneraI Pub1ic License , and you are welcome tO change it and/or distribute copies Of it under certain conditions . Type " s れ 0 copying" tO see the conditions . There is absolutely Ⅱ 0 warranty for GDB. Type ” shO warranty" fO て details . This GDB was configured as " i386—redhat-1inux—gnu" Core was generated by . /a. out ' Program terminated with signal 11 , Segmentation fault . Reading symbols from /lib/tls/libc . SO. 6 ... done . Loaded symbols for /lib/tls/libc . so . 6 Reading symbols from /lib/ld—linux. SO. 2... done. # 0 0X0804836b in subl ( ) at samplel . c : 23 Loaded symbols for /lib/ld—linux. so . 2 23 *p = 10 ; -g オプションと一 0 オプションのラ # 0 0X0804836b in subl ( ) at samplel . c : 23 としか表示されていなかった行が、 時に才彳定しないように注意しましよう。 グがやりにくくなるので、慣れないうちは 2 つのオプションを同 す。ところが、 gcc では同時に指定することができます。デバッ ンと -O オプションは同時には指定できないようになっていま このようなことから、たいていのコンパイラでは—g オプショ デバッガの出力カ吩かりにくくなる場合があります。 と、デバッガカ毓み込んでいるコードとのあいだにずれが生じて、 ときにこのオプションを指定していると、ソースコード上の表記 えたりする場合があります。そのため、デバッガを利用している するために不要と判断したコードを削除したり、実行の川頁序を変 ションを指定すると、コンパイラはより効率のよいコードを生成 ション ( オプティマイザ ) " を指定する場合があります。このオプ ードを生成するために、コンパイラに -O などの、最適化オプ 実用的なプログラムをコンパイルするときには、効率のよいコ 23 *p = 10 ; と変わり、もうすこし詳しい情報が得られるようになって います。これによると、プログラムが異常終了したのは samplel. c というソースファイルの 23 行目、すなわち 、 *P = 10 ; " を実行しているときだったことが分かります。 さきほどと同様に、 bt コマンドでスタックトレースも表 示してみましよう。 (gdb) bt # 0 0X0804836b in subl ( ) at samplel . c # 1 0X0804833d in main ( ) at samplel . c # 2 0X42015574 in __libc_start_main ( ) 38 (gdb) from /lib/tls/libc . so . 6 : 23 : 11 別掲のコラム「一 g オプションと一 O オプションの混在」 にも書きましたが、プログラムがどこで停止したのかを調 べやすくするには、コンノヾイル時に一 g オプションを指定す る必要があります。再コンパイルカ材く可能な環境なら、と りあえず gdb を起動してどこで停止しているのかを関数レ ベルで確認することもできます。しかし、もっと詳しい情 報がほしいときは -g オプションの指定が必顎です。プロ グラムの開発中は、 -g オプションを指定する習慣をつけま しよう。 こまでで samplel. c の 23 行目でプログラム さて、 が停止したことは分かりました。次は、停止した原因を調 べる番です。さきほと第見明したように、セグメンテーショ ン・フォルトというのは、プログラムがアクセスしてはい けない領域にアクセスしようとしたときに発生します。と いうことは、 23 行目にある変数 p が、アクセスしてはい けない領域 " になっている可能性があるわけです。 この程度の短いプログラムなら、この行で何をしようと したのかは一目瞭然です。しかし、巨大なプログラムをデ バッグしているときは、 1 行だけを見て何をしようとして いるのかを思い出すのは大変です。 gdb の list コマンド を使うと、現在止まっている行の前後の行を表示してくれ ます。たとえば、 23 行目の近辺をみたい場合は、 list コマ ンドに行数を指定すれば、その前後の 10 行ぶんが表示さ れます ( 何行表小するかは、 set listsize コマンドで変更で きます ) 。 (gdb) list 23 18 19 subl() UNIX MAGAZINE 2004.4
連載 / UN Ⅸ便利帖ー 0 リスト 4 ラ立データを言泉するスクリプト $logfile fopen("position. 10g" $logline = date("U") $lat $ns $ew $ 10 Ⅱ . $acc if (flock($logfile , LOCK-EX) ) { fwrite($logfile, $logline) ; flock($logfile , LOCK—UN) ; fclose($logfile) ; greSQL を利用しています。たしかに、こうしておけばデ ータカ膨大になってもシステムは破綻しませんし、将来的 な拡張なども可能です。しかし、今回のシステムでは、、素 早く作って、とにかく試す " を重視したので、測位データ についてはテキスト形式でファイルに追記することにしま した。もちろん、後々のことを考えれば、 PostgreSQL や MySQL などのデータベース・システムを導入したほうが よいと思いますが、、、素早く " 作ることを優先させて、もっ とも簡単な方法で実現することにしました。 リスト 4 が、測位データをファイルに言泉するスクリプ トです。ここでは、記録するデータとして次のものを選び ました。 ・現在時刻 (UNIX 時刻 ) ・北緯を表す文字、、 N " ・緯度 を表す文字、、 E " ・測位レベル これらのデータをカンマで区切って並べ、最後に改行コ ードを入れて 1 回ぶんのデータを 1 行で表すようにしまし た。測地系については、おそらく世界測地系から切り替わ ることはないと考え、言泉からは省いてあります。 リスト 4 の 1 行目では position. 10g というファイル を追記型でオープンし、 2 ~ 4 行目で言泉のための行を作成 しています。このファイルのパーミッションは、もちろん WWW サーバーを動かしているユーザーの権限で中身の 追加ができるように設定しておく必要があります。 5 行目で、同時アクセスに備えて念のためファイルをロッ クします。そして、 6 行目でファイルに言泉を追加し、 7 行 目でロックを解除、 9 行目でファイルを閉じています。 の WWW ページには自分以外はアクセスしないはずです 142 から、同時アクセスの可能性はきわめて低いと思いますが、 念には念を入れて、ファイルに書き込んでいるあいだはロ ックするようにしています。 このスクリプトは、リスト 3 のスクリプトの後ろに挿入 1075791426 , N , 34.59.22.37 , E , 135.46.40.40 , 1 1075790597 , N , 34.59.22.44 , E , 135.46.40.22 , 2 1075790554 , N , 34.59.22.74 , E , 135.46.40.48 , 1 なかたちで行数カ社曽えていきます。 言泉を追記していくファイル position. 10g は、次のよう しておけばよいでしよう。 UNIX MAGAZ 工 NE 2004.4 カ灘点です。 ジにジャンプできます。ただ、携帯電話では画面カ鴃いの リンクをたどることで視覚的に分かりやすい WWW ペー の URI などを作成して一緒に表示するようにすれば、その しかし、測位データはそのまま残っているので、周辺地図へ このままでは、お世辭にも分かりやすいとはいえません。 番号カ賑られて表示されることになります。 結果としてもっとも旧いデータから順に 1 、 2 、 3 、 れ、個々のデータをく li 〉 ~ い i 〉で括って出力しているため、 プト全体を回〉 ~ 〈 / ol 〉 ( 番号付きの箇条書き ) のなかに入 タを取り込んで、それをほばそのまま表示します。スクリ sition.log を読取り専用で開き、地頁から順に 1 行すっデー するためのスクリプトをリスト 5 に示します。これは、 p 。ー このファイルを読み込んで、自分の居場所の履歴を表示 tion) とは国際字宙ステーションのことで、条件がよけれ ジを提供しています。 ISS (lnternational Space Sta- 発機構 ) が、、 ISS を見よう " という i モードの WWW ペー ほかにおもしろいところでは、 JAXA ( 宇宙航空研究開 様にして作れるでしよう。 辺地図や情報などの WWW ページへのリンクも、同 の URI はリスト 7 のようにすれば作れます。その他の周 のようなスクリプトで作成できますし、、、 AD 乗換案内 " へ たとえば、、、ゼンリン孑マップ " への URI はリスト 6 の URI を抜き出せば作れます。 、、 GPS リンク集 " のなかでイ財リだと感じた WWW ページ のリンクを表示するようにしましよう。これらの URI は、 最後に、周辺地図や青報のための WWW ページへ 実験その 4
特集 図 14 実彳研彡式のファイル名を指定して gdb を産カ % gcc —g samp1e3. c % gdb a. out GNU gdb Red Hat Linux ( 5.3post ー 0.20021129.18rh) Copyright 2003 Free S0ftware Foundation, lnc . デバッガの基礎知識 GDB is free software , covered by the GNU GeneraI PubIic License , and you are welcome tO change it and/or distribute copies Of it under certain conditions . Type " s 五 0 copying' tO see the conditions . There is absolutely no warranty f0 て GDB. Type " shOW warranty't fO て details . This GDB was configured as " i386—redhat—1inux-gnu" (gdb) 図 15 言聢されているすべてのブレークポイントを石忍 (gdb) info break Num Type 1 breakpoint Disp Enb Address What keep y 0X08048381 in main at samp1e3. c:9 breakpoint already hit 1 time 図 16 ブレークポイントの言綻 (gdb) 1 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 (gdb) list 9 10 11 12 13 main(void) char buf [ 5 ] ; char* p ; sprintf (buf , " プ p = buf ; printf("%s\n", p) ; return 0 ; (gdb) b 6 Breakpoint 2 at 0X8048368 : file samp1e3. c, line 6 . (gdb) inf0 break Num Type 1 breakpoint 2 breakpoint (gdb) run Disp Enb Address What keep y 0X08048381 in main at samp1e3. c : 9 keep y 0X08048368 in main at samp1e3. c : 6 Starting program : /Programs/Samp1e3/a. out Breakpoint 2 , main ( ) at samp1e3. c:8 sprintf (buf , 8 (gdb) 今度は、プレークポイントを設定した場所でプログラム の実行が停止しました。このとき表示されている 9 行目 は、この時点ではまだ実行されていません。 gdb はプログ ラムの停止した場所を示してプロンプトを表示し、入力待 ちの状態になります。 プレークポイントは、いくつでも設定することができま す。現在設定されているすべてのプレークポイントを確認 するには、 info break コマンドを実行します。 ( 図 15 ) 。 プレークポイントは、変数の宣言だけをおこなっている 行やコメント行には設疋できません。 gdb の break コマ UNIX MAGAZINE 2004.4 ンドを実行した時点では、一見設定できそうに思えますが、 実際にプレークポイントカ駁疋されている箇所は、次にプ レークポイントが設定できる行に自動的に変更されてしま います。 たとえば、 sample3. c では 6 行目や 7 行目にはプレー クポイントは設定できません。 図 16 では、 12 行目で sample3. c の 6 行目にプレー クポイントを設疋しています。 break コマンドの出力結果 も、 info break コマンドで確認してみても、一見したとこ ろは 6 行目にプレークポイントカ第ス疋されているようにみ 43
連載 / 旧 v6 の実装ー 図 7 対応付けキャッシュの更新 277 282 283 284 285 286 288 289 290 291 292 295 296 298 299 300 263 } else { mbc—>mbc mbc—>mbc mbc—>mbc mbc—>mbc _explre time_second 十 mbc—>mbc—lifetime ; mbc—>mbc_lifetime = bi—>mbc—lifetime; —seqno = bi—>mbc—seqno; —flags = bi—>mbc-flags ; —pcoa = bi¯>mbc—pcoa; mip6—bc—encapcheck, &mbc—>mbc—encap) ) { if (mip6—tunne1—contr01 (MIP6-TUNNEL-CHANGE, mbc , mip6—bc—settimer (mbc , mip6—brr—time (mbc) ) ; mip6—bc—settimer (mbc , mbc—>mbc_state = MIP6_BC_FSM_STATE—BOUND ; mbc—>mbc_expire 0x7fffffff; if (mbc—>mbc—expire く time—second) return ( ー 1 ) ; prim—mbc = mbc ; 254 ~ 260 行目で新しい対応付けキャッシュを作成しま 269 if (bi->mbc—flags & IP6MU-LINK) { 重複アドレス検出に利用します。 インタを prim-mbc に設疋します。 prim-mbc はあとで す。作成できたら、 263 行目で作成されたキャッシュのポ なので、解説は省略します。 if (busy) { 302 305 306 } return ( 0 ) ; 270 271 272 } mbc—>mbc_llmbc llmbc ; llmbc—>mbc_refcnt + + ; 302 ~ 306 行目は重複アドレス検出中のホーム登録の受 信処理です。以前受信したホーム登録を処理し、移動ノー ドのアドレスに対する重複アドレス検出をしているところ に、再度ホーム登録を受信すると busy が真になります。 この場合、以降の処理へは進まず、重複アドレス検出の終 了を待ちます。 308 if (prim—mbc) { 269 ~ 272 行目は、ホームアドレスに対応するリンク ローカル・アドレスのキャッシュとの関連付けです。 IP6 MU-LINK が指定されている場合、ホームアドレスに対 するキャッシュに加えて、リンクローカル・アドレスに対 するキャッシュも存在します。直前の処理で、リンクロー カル・アドレスに対する対応イ寸けキャッシュカ胙成もしく は更新されて llmbc に設疋されているので、 270 ~ 271 行 目で llmbc を参照し、参照カウントを増やします。 273 } else if (MIP6-IS—BC—DAD-WAIT(mbc) ) { 313 314 mip6—dad—start (prim—mbc) ; bi—>mbc_send_ba = 0 ; 274 275 276 mbc—>mbc—pcoa = bi—>mbc—pcoa; mbc—>mbc—seqno = bi—>mbc—seqno ; busy + + , 274 ~ 276 行目は、更新対象となった対応付けキャッシ ュの重複アドレス検出が終了していない場合の処理です。 リンクローカル・アドレスの場合と同様、気付アドレスと 通し番号を更新し、重複アドレス検出の終了を待ちます。 図 7 の 282 ~ 299 行目は対応付けキャッシュの更新処理 です。処理内容はリンクローカル・アドレスの場合と同じ UNIX MAGAZINE 2004.4 308 ~ 314 行目で、ホームアドレスの重複アドレス検出 処理を開始します。新しく対応付けキャッシュが作成され た場合、かならずホームアドレスの重複検出をしなければ なりません。 prim-mbc は対応付けキャッシュカ噺規作成 された場合に設疋されるので、 prim-mbc か奴疋されてい れば mip6-dad-start() を呼び出して重複アドレス検出を 開始します。この場合、対応付け応答は検出処理が終った あとでないと返送できないので、対応付け応答メッセージ の返送を才くする mbc-send-ba は 0 に設疋されます。 対応付けキャッシュカ噺規に作成されたのではなく、更 新されただけであれば、重複アドレス検出はすでに実施さ れているので不要です。図 8 の 320 ~ 323 行目で、再対 87
連載 / 旧 v6 の実装ー 図 5 リンクローカル・アドレスのプレフィックスの検索 147 148 149 151 152 154 155 156 157 158 159 167 168 169 170 166 171 } if ( (bi—>mbc—flags & IP6MU—LINK) ! = 0 ) { fo て ()r = nd-prefix. lh—first ; pr; pr continue ; if (hifp ! = pr—>ndpr-ifp) { pr—>ndpr—next) { if (IN6_IS_ADDR_LINKLOCAL (&pr—>ndpr_prefix) ) { llpr = pr; continue ; status IP6_MH_BAS_UNSPECIFIED ; bi—>mbc_send_ba = 1 ; lifetime refresh = 0 ; bi—>mbc bi—>mbc bi—>mbc return ( 0 ) ; / * XXX is 0 OK? * / 161 ~ 171 行目はプレフィックスの有効時間が短すぎな いかどうかの確認です。対応付け応答で返答する肩効時間 は 4 秒単位で指定されます。対応付けキャッシュの肩効時 間は、移動ノードのホームアドレスの有効時間 ( すなわち、 ホーム・プレフィックスの肩効時間 ) より長く誌定すること はできません。プレフィックスの有効時間が 4 秒に満たな い場合、対応イ寸け応答に含める肩効時間が 0 になってしま うため、未定義工ラーを示す IP6-MH-BAS-UNSPEC- IFIED を返します。 if (bi—>mbc—lifetime く 4 ) { 173 179 180 } return ( 0 ) ; / * XXX is 0 OK? * / 173 ~ 180 行目は、逆に対応付け更新に指定されていた 有効時間が 4 秒に満たない場合のチェックです。この場 合、エラーは返さずに、移動ノードから正しい対応付け更 新カ舸送されてくることを期待します。 183 if (bi—>mbc—lifetime > prlifetime) { きい値を指定してくるということは、移動ノードが管理し ているプレフィックスの有効時間と、ホーム・エージェン トカ理している有効時間にずれがあることを末します。 そこで、 185 行目でプレフィックス情報の再取得を意味す る IP6-MH-BAS-PRFX-DISCOV を返送します。 のステータスコードを受信した移動ノードは、プレフィッ クス探索メッセージを送信して、最新のホーム・プレフィッ クスの情報を取得しなければなりません。 if ( (bi—>mbc—flags & IP6MU_LINK) ! = 0 & & llpr ! = NULL) { 197 ~ 245 行目は、リンクローカル・アドレスに対する 対応付けキャッシュ情報の更新 / 作成処理です。対応付け 更新メッセージに IP6MU-LINK が指定されており、ホー ム・ネットワークにリンクローカル・プレフィックスが割 り当てられているときにのみ実行されます。 198 mip6—create—addr(&IIaddr, (const struct in6—addr *)&bi—> 199 mbc—phaddr , llpr) ; 200 llmbc = mip6—bc-1ist—find—withphaddr (&mip6—bc—1ist , &lladdr) ; 198 ~ 200 行目で、既存の対応付けキャッシュがないか どうかを確認します。なければ 206 行目の作成処理に、存 在すれば 217 行目の更新処理に進みます。 if (llmbc = = NULL) { 201 197 184 185 bi—>mbc—lifetime = prlifetime; bi—>mbc_status IP6_MH_BAS_PRFX_DISCOV ; 186 } 183 ~ 186 行目は、移動ノードカ鮨定してきた希望有効 時間が、ホーム・エージェントが管理しているプレフィッ クスの有効時間よりも長い場合の処理です。まず、 184 行 目で有効時間をプレフィックスの肩効時間まで減らします。 移動ノードがホーム・プレフィックスの有効時間よりも大 UNIX MAGAZINE 2004.4 206 207 208 209 211 212 mip6—bc—create(&11addr, llmbc &bi—>mbc-addr, bi—>mbc—flags , &bi—>mbc—pcoa, if bi—>mbc—seqno , bi—>mbc—lifetime, hifp) ; (llmbc = NULL ) { return ( ー 1 ) ; 85