臨場(core)
散歩のお友にしてるUSBのプレーヤーが調子悪くなった。聞いてるのは、500Hz正弦波の断続 信号なんだけど、暫く聞いていると右チャンネルにノイズが乗ると言うか、しゃきしゃき音が 聞こえて来るんだ。
一度プレーヤーの電源を切ってから、入れなおすと暫くは正常に聞こえるんだけど、また しゃきしゃき音になってしまう。もう何年も使っているから、中に組み込まれているで あろうコンデンサーが容量抜けでも起こしてしまったのだろうか?
仮にそうだとしても、500HzのPureな正弦波だから、高調波だけが通過して低域がカット されてあんな音になるのだろうか?それとも、容量抜けで微分回路みたいになってしまって いるのだろうか?(そんな事ないだろう!正弦波を微分したって、正弦波しか出てこな かったはず。)
こんな事を散歩の間中考えていたら、堂々めぐりになってしまい。。。 ふと、イヤホンは 大丈夫か? という疑問が出てきた。翌日、パソコンで使ってたやつをプレーヤーに差し込んで 散歩に出た所。いくら聞いていてもしゃきしゃき音は発生しないのだ。翌日にも確かめて みたけど、問題無し。結論は、イヤホンの不良っぽい。
長年使っていたので、最初は柔らかかったコードも硬化して硬くなりかけている。コードを しごいてみたけど、しゃきしゃき音が発生する兆候は無かった。もうイヤホンを変えるしか。 このまま、パソコンからひっこぬいたやつを使ってもいいんだけど、耳かけ式のやつなんで サングラスと併用出来ない。(紫外線対策重要って事で)
耳の穴に突っ込むタイプ(カナリ式と言うそうだ)を買ってきた。いろいろあったけど コネクタからケーブルがストレートに出てるやつじゃなくて、90度に曲がっているやつに した。だってその方が、プレーヤーを首からぶら下げた時、コードの始末が良いんだもの。
gdb
前回はgdbを実現するためのptraceを見た。gdb関係で面白そうな記事はないかなと 探してみたら、ずばり、 gdb hacks なんてのに行き着いた。これ面白い。
ここまで深入りしなくても、breakをサポートしてないqumuのarm環境でgdbと遊べるだろう。 ああ、遊ぶと言ってもアセンブラーレベルの話ね。
armの資料を見てたら、浮動小数点の演算機構は持っていないようだ。それにMMUとかキャッシュ も素では入っていない。ユーザーが必要なオプションを選んで一つのチップに内蔵するようだ。 明日発売予定のiPadは、アップルがarmをコアCPUにして他に必要な周辺デバイスの コントローラ等もまとめて、A4とか言う石にしてるらしい。 で、FPUが無いarmで小数点を扱ったらどうなるかみてみる。Intelで言ったら、8086の時代かな。 あの頃は金が無くて、8087買えなかったんだ。で、どうしたかと言うと。
#include <stdio.h> #include <math.h> double hoge(double a){ return sqrt(a); } main (){ printf("%16.12g\n", hoge(2.0)); }
.syntax unified .arch armv7-a .eabi_attribute 27, 3 .fpu vfpv3-d16 .eabi_attribute 20, 1 .eabi_attribute 21, 1 .eabi_attribute 23, 3 .eabi_attribute 24, 1 .eabi_attribute 25, 1 .eabi_attribute 26, 2 .eabi_attribute 30, 6 .eabi_attribute 18, 4 .thumb .file "fftest.c" .text .align 2 .global hoge .thumb .thumb_func .type hoge, %function hoge: @ args = 0, pretend = 0, frame = 8 @ frame_needed = 1, uses_anonymous_args = 0 push {r7, lr} sub sp, sp, #8 add r7, sp, #0 strd r0, [r7] fldd d7, [r7, #0] fsqrtd d7, d7 fcmpd d7, d7 fmstat beq .L2 ldrd r0, [r7] bl sqrt fmdrr d7, r0, r1 .L2: fmrrd r2, r3, d7 mov r0, r2 mov r1, r3 add r7, r7, #8 mov sp, r7 pop {r7, pc} .size hoge, .-hoge .section .rodata .align 2 .LC0: .ascii "%16.12g\012\000" .text .align 2 .global main .thumb .thumb_func .type main, %function main: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 1, uses_anonymous_args = 0 push {r3, r4, r7, lr} add r7, sp, #0 movw r4, #:lower16:.LC0 movt r4, #:upper16:.LC0 adr r1, .L6 ldrd r0, [r1] bl hoge mov r2, r0 mov r3, r1 mov r0, r4 bl printf mov sp, r7 pop {r3, r4, r7, pc} .L7: .align 3 .L6: .word 0 .word 1073741824 .size main, .-main .ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3" .section .note.GNU-stack,"",%progbits
gdbで逆アセンブルしてみた。16Bitモードと32ビットモードが混在してるって事なのかな? ちと、ごちゃごちゃしてて醜いな。
(gdb) disas/r hoge Dump of assembler code for function hoge: 0x00008440 <+0>: 80 b5 push {r7, lr} 0x00008442 <+2>: 82 b0 sub sp, #8 0x00008444 <+4>: 00 af add r7, sp, #0 0x00008446 <+6>: c7 e9 00 01 strd r0, r1, [r7] 0x0000844a <+10>: 97 ed 00 7b vldr d7, [r7] 0x0000844e <+14>: b1 ee c7 7b vsqrt.f64 d7, d7 0x00008452 <+18>: b4 ee 47 7b vcmp.f64 d7, d7 0x00008456 <+22>: f1 ee 10 fa vmrs APSR_nzcv, fpscr 0x0000845a <+26>: 05 d0 beq.n 0x8468 <hoge+40> 0x0000845c <+28>: d7 e9 00 01 ldrd r0, r1, [r7] 0x00008460 <+32>: ff f7 a0 ef blx 0x83a4 <sqrt> 0x00008464 <+36>: 41 ec 17 0b vmov d7, r0, r1 0x00008468 <+40>: 53 ec 17 2b vmov r2, r3, d7 0x0000846c <+44>: 10 46 mov r0, r2 0x0000846e <+46>: 19 46 mov r1, r3 0x00008470 <+48>: 07 f1 08 07 add.w r7, r7, #8 0x00008474 <+52>: bd 46 mov sp, r7 0x00008476 <+54>: 80 bd pop {r7, pc}
こちらの方がすっきりしてる。-Sを付けると、Cのソースも(有れば)一緒に表示してくれる ようだ。
user@ubuntu:~$ objdump -d a.out : 00008440 <hoge>: 8440: b580 push {r7, lr} 8442: b082 sub sp, #8 8444: af00 add r7, sp, #0 8446: e9c7 0100 strd r0, r1, [r7] 844a: ed97 7b00 vldr d7, [r7] 844e: eeb1 7bc7 vsqrt.f64 d7, d7 8452: eeb4 7b47 vcmp.f64 d7, d7 8456: eef1 fa10 vmrs APSR_nzcv, fpscr 845a: d005 beq.n 8468 <hoge+0x28> 845c: e9d7 0100 ldrd r0, r1, [r7] 8460: f7ff efa0 blx 83a4 <_init+0x44> 8464: ec41 0b17 vmov d7, r0, r1 8468: ec53 2b17 vmov r2, r3, d7 846c: 4610 mov r0, r2 846e: 4619 mov r1, r3 8470: f107 0708 add.w r7, r7, #8 8474: 46bd mov sp, r7 8476: bd80 pop {r7, pc} 00008478 <main>: 8478: b598 push {r3, r4, r7, lr} 847a: af00 add r7, sp, #0 847c: f248 5400 movw r4, #34048 ; 0x8500 8480: f2c0 0400 movt r4, #0 8484: a106 add r1, pc, #24 ; (adr r1, 84a0 <main+0x28>) 8486: e9d1 0100 ldrd r0, r1, [r1] 848a: f7ff ffd9 bl 8440 <hoge> 848e: 4602 mov r2, r0 8490: 460b mov r3, r1 8492: 4620 mov r0, r4 8494: f7ff ef8c blx 83b0 <_init+0x50> 8498: 46bd mov sp, r7 849a: bd98 pop {r3, r4, r7, pc} 849c: f3af 8000 nop.w 84a0: 00000000 .word 0x00000000 84a4: 40000000 .word 0x40000000
上のアセンブラに出てくる命令 vldr等はarmの説明書には出ていない。なんとなく想像は 付くけど分からないと気分が悪い。探してみたら RealView Compilation Tools アセンブラガイド こんな所へ連れて行かれたよ。石の命令と同時に擬似命令も覚えろってか。おいらの頭は 揮発性が高いんだよ。volatile 必須だな!
core
gdbから簡単にcoreファイルが作成出来るというのをNetで見かけたんでやってみた。
sakae@ubuntu:~$ gdb a.out : (gdb) b hoge (gdb) run : (gdb) generate-core-file Saved corefile core.20447
でも、普通はゾンビっぽくなったやつを検査したいはず。殺してしまっていいなら、次のように 死してcoreを残すようにするのが簡単。
sakae@ubuntu:~$ kill -3 pid
ダイイングメッセージを残して、お亡くなりになりましたよ。
sakae@ubuntu:~$ ./a.out Quit (core dumped)
でも、場合によっては、生かしておいて検査したい場合もあろう。(これって、今の老人 医療みたいだな。死んでるけど死んでいない。寿命だけが延びていく)
sakae@ubuntu:~$ gdb --pid=20548 a.out : (gdb) bt #0 0x00f35832 in ?? () from /lib/ld-linux.so.2 #1 0x0059fe03 in read () from /lib/tls/i686/cmov/libc.so.6 #2 0x0054942b in _IO_file_underflow () from /lib/tls/i686/cmov/libc.so.6 #3 0x0054accb in _IO_default_uflow () from /lib/tls/i686/cmov/libc.so.6 #4 0x0054c0f8 in __uflow () from /lib/tls/i686/cmov/libc.so.6 #5 0x00541b6c in getchar () from /lib/tls/i686/cmov/libc.so.6 #6 0x080484e5 in main () at fftest.c:9 (gdb) generate-core-file Saved corefile core.20548 (gdb) detach Detaching from program: /home/sakae/a.out, process 20548 (gdb) q
生きているうちに検査すると、フレッシュな情報が得られるけど、coreになった後では ちゃんとした情報が得られないね。
sakae@ubuntu:~$ gdb a.out core.20548 : (gdb) bt #0 0x00f35832 in ?? () from /lib/ld-linux.so.2 #1 0x0059fe03 in ?? () #2 0x00637ff4 in ?? () #3 0x0054942b in ?? () #4 0x00000000 in ?? ()
臨場の人は大変だ。想像して想像して、だもんなぁ。もう執念なんですかね。
臨場の人
TVで今やってるね。出てくる度に、トマトだか胡瓜をかじっているあの人。おいらもちょっと まねをしてみる。 題材は、w3m -v すると、Segふぉー するやつ。
user@ubuntu:~$ gdb w3m qemu_w3m_20100518-163600_2963.core : (gdb) info reg r0 0x694 1684 r1 0x40080148 1074266440 r2 0x418 1048 r3 0x40080144 1074266436 r4 0x142ffc 1323004 r5 0x2154a08 34949640 r6 0x7fbd0b84 2143095684 r7 0x4007ff50 1074265936 r8 0x4007fd4c 1074265420 r9 0x7fbd0c00 2143095808 r10 0x139128 1282344 r11 0x1390a8 1282216 r12 0x4007f55c 1074263388 sp 0x4007f520 0x4007f520 lr 0x42125e23 1108500003 pc 0x42125c66 0x42125c66 <GC_mark_from+246> fps 0x0 0 cpsr 0x20000030 536870960 (gdb) p GC_mark_from $1 = {<text variable, no debug info>} 0x42125b70 <GC_mark_from> (gdb) disas/r 0x42125b70, 0x42125c66 : (gdb)
GC_mark_fromがどんなコードになってるか逆アセンブルしたら、画面が止まらずにサーと 流れていってしまった。途中で止めて(gdbにmoreが組み込まれているみたいに!)見て 行きたい。manしたら、term属性を引きついでくれるようなことが書いてあった。
user@ubuntu:~$ stty -a speed 38400 baud; rows 38; columns 80; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
これで良さそうなんだけど、だめだったんで、下記のような設定をしたよ。
user@ubuntu:~$ cat .gdbinit set height 38
これで安心。gdbもmoreっぽくなった。でもね、GCのルーチン一筋縄ではいかないね。
で、ふぃと、info regしてlrの値を見たら。。。 0x42125e23 これって奇数番地だよ。 命令のアライメントは偶数になっていなければならないはず。
lrレジスタって、サブルーチンからの戻り番地を保持するはずだから、戻った時に奇数番地を アクセスして、Segふぉー になったのかな。そうに違いない。そういう事にしておこう。
もう一つ疑問があって、info regした時に出てくる fspって名前が付いたもの。こやつ 何者? マニュアルを調べてもarmな石にそんなのは搭載されていない。でもgdbのソースを 見ると、arm-tdep.c にちゃんと定義されている。
/* Initial value: Register names used in ARM's ISA documentation. */ static char * arm_register_name_strings[] = {"r0", "r1", "r2", "r3", /* 0 1 2 3 */ "r4", "r5", "r6", "r7", /* 4 5 6 7 */ "r8", "r9", "r10", "r11", /* 8 9 10 11 */ "r12", "sp", "lr", "pc", /* 12 13 14 15 */ "f0", "f1", "f2", "f3", /* 16 17 18 19 */ "f4", "f5", "f6", "f7", /* 20 21 22 23 */ "fps", "cpsr" }; /* 24 25 */
gdbのinfoを調べてみたら、
The `org.gnu.gdb.arm.fpa' feature is optional. If present, it should contain registers `f0' through `f7' and `fps'.
どうやらgnuの拡張っぽい。浮動小数点演算のステータスレジスタ? でも、上記ソース上では、gdbがtargetの石に問い合わせするのに使っているようなので、 もう訳分からんわい。嗚呼、gdbでgdbの動きを追跡したくなったぞ。でも、そんな事は 駄目って, たしなめられるのだろうか? とか思いながら例の本を読んでいたら、浮動小数点 の演算で例外を上げる方法が出ていた。例外が上がれば、ステータスレジスタにbitが立つ だろうな。早速やってみる鹿。
#include <stdio.h> #include <math.h> #include <fenv.h> #define _GNU_SOURCE main (){ int e = FE_ALL_EXCEPT; feenableexcept(e); printf("%20.18g\n", sqrt(-2.0)); }
全てのfpu関係の例外でエラーに落ちるように設定し、負の平方根を取ってみる。
user@ubuntu:~$ ./a.out nan
あれ落ちないよ。間違ったかなと思って、インテル環境でやってみると
sakae@ubuntu:~$ ./a.out Floating point exception sakae@ubuntu:~$ gdb a.out core : Core was generated by `./a.out'. Program terminated with signal 8, Arithmetic exception. #0 0x080484e9 in main () 9 printf("%20.18g\n", sqrt(-2.0));
結論は、arm環境はここまで面倒見てくれないって事で宜しいでしょうかね。
臨場のテーマソングになってる平原綾香『威風堂々』っていい曲だなあ。何度聞いても飽きないよ。 それにしてもこの曲、エルガー行進曲「威風堂々」のカバーとはしらなんだ。