臨場(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環境はここまで面倒見てくれないって事で宜しいでしょうかね。

臨場のテーマソングになってる平原綾香『威風堂々』っていい曲だなあ。何度聞いても飽きないよ。 それにしてもこの曲、エルガー行進曲「威風堂々」のカバーとはしらなんだ。