gdb活用
SEGV
Go to トラベルが、Go to トラブルになりつつある現状。外に旅行に行くなんて、もっての他だ。巣ごもりしましょ。バーチャル旅行で我慢しましょ。
ってなわけで、旅行を考え、無理矢理捻りだす。前回やった、スタックオーバーフローって、どんな仕組みで動いてるの? 目的を持ったカーネル観光なら、オロオロする事は無いだろう。 自分の野生の勘を頼りに、うろつき回るのさ。
手がかりは、ulimit -s ですよ。
vbox$ man -k ulimit man: nothing appropriate vbox$ man -k limit quota(1) - display disk usage and limits getrlimit, setrlimit(2) - control maximum system resource consumption :
公式文書のmanから探す。見つからず。そりゃそうだわな。ulimitはshellの組み込みコマンドだから、出てこないのだ。気を取り直して、それらしい語句で探す。setrlimit(2) の2は、システムコールの章を表している。ggと違って、作為が無いのでありがたい。ぐぐるは、村八分とかあるし、今後はスマホ優先にシフトするらしい。金儲けFirstですからね。
リソース制限は色々な種類が有るけど、カーネルへの依頼は、getrlimitと対になるsetrlimitだ。どちらでmanを引いても、同じ所に案内される。 getrlimit(2)
RLIMIT_STACK The maximum size (in bytes) of the stack segment for a process, which defines how far a process's stack segment may be extended. Stack extension is performed automatically by the system, and is only used by the main thread of a process. The system refuses to extend the data or stack space when the limits would be exceeded in the normal way: a brk(2) call fails if the data space limit is reached. When the stack limit is reached, the process receives a segmentation fault (SIGSEGV); if this signal is not caught by a handler using the signal stack, this signal will kill the process.
もう答えが出ちゃったけど、現場視察をしてみる。どのあたりを視察したら良いかは、航空写真で眺めるかわりに、キーワードを頼りにして、カーネルのソースを探ってみる。
grep --color -nH --null -e RLIMIT_STACK *.c exec_subr.c:354: epp->ep_ssize = round_page(lim_cur(RLIMIT_STACK)); kern_resource.c:272: case RLIMIT_STACK: kern_resource.c:295: if (which == RLIMIT_STACK) {
exec_subr.c
の方だろうね。だって、execってexecveの関連ソースだからね。execveはOSがアプリを読み込んで、起動するシステムコールだ。そのシステムコールの中で、当然stackの準備もなされるから。
exec_setup_stack(struct proc *p, struct exec_package *epp) { vaddr_t sgap; #ifdef MACHINE_STACK_GROWS_UP epp->ep_maxsaddr = USRSTACK; epp->ep_minsaddr = USRSTACK + MAXSSIZ; #else epp->ep_maxsaddr = USRSTACK - MAXSSIZ - MAXSSIZ_GUARD; epp->ep_minsaddr = USRSTACK; #endif epp->ep_ssize = round_page(lim_cur(RLIMIT_STACK)); :
gdbで観光すると、else句の方が実行されてた(駆動プログラムは何でもいいんだけど、前回のオーバーフローさせる奴を流用)。恒例の履歴。
(gdb) bt 5 #0 exec_setup_stack (p=0xd17e3a84, epp=0xf1d33bf0) at /usr/src/sys/kern/exec_subr.c:351 #1 0xd03a685e in exec_elf_makecmds (p=0xd17e3a84, epp=0xf1d33bf0) at /usr/src/sys/kern/exec_elf.c:760 #2 0xd0903d1c in check_exec (p=0xd17e3a84, epp=0xf1d33bf0) at /usr/src/sys/kern/kern_exec.c:189 #3 0xd090412e in sys_execve (p=0xd17e3a84, v=0xf1d33e24, retval=0xf1d33e1c) at /usr/src/sys/kern/kern_exec.c:298 #4 0xd06bae59 in mi_syscall (p=0xd17e3a84, code=59, callp=0xd10f916c <sysent+708>, argp=0xf1d33e24, retval=0xf1d33e1c) at /usr/src/sys/sys/syscall_mi.h:92 (More stack frames follow...) (gdb) p epp->ep_ssize ### in case ulimit -s 4096 $1 = 4194304 : (gdb) p epp->ep_ssize ### in case ulimit -s 8192 $3 = 8388608
ダメだしで、スタックリミットを変えた時の値も確認して。確かに連動してる。
NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr), epp->ep_maxsaddr, NULLVP, 0, PROT_NONE); => NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize, (epp->ep_minsaddr - epp->ep_ssize), NULLVP, 0, PROT_READ | PROT_WRITE, VMCMD_STACK);
そして白眉は、上記2つの実行。仮想記憶のコントロールは難しいので、マクロになってる。 最初のコマンドは、指定したstackサイズ以下は、仮想記憶に属性を与えない。2番目は、スタックエリアにメモリーを割り当て、R/Wの許可を与えている。
属性が設定されていないエリアにspがアクセスすると、即SEGVになる訳だ(仮想記憶の管理機構から割り込みが発生するので、kernelは不正なアクセスを検知)。このエリアの事をレッドゾーンと言うとか。
勿論、mallocとかで、メモリー要求が来た場合、それが正当な要求なら(heap)、SEGVにしないで、こっそりとメモリーを割り当てて、すました顔で、どうぞメモリー使って下さいって、カーネルが振る舞うようになっている。
ここまで旅してきて、更に奥地への探検も思い付いたけど、それはまた今度。
Open hardware
Go to 食事券やりたくて、4人までねとか、食事中は声出すなとか言ってる。食事中は声出さない、イスラムの人になれって事だな。そのうちに、マスクしたまま食事出来るマスクを発明しろとか言い出さないか心配。これから忘年会シーズンですからね。ビールとかの飲料は、ビニールのチューブをマスクの脇から口に入れて、チュウチュウしましょ。
食事券に群がる人の気持ちも分からないでは無い。何しろゲインが1.25と言う破格の扱いだからね。オイラーは、食事に限定されない、藩札を入手した。地域限定かつ時限が来たら紙切れになるやつね。これで、地域に貢献しましょ。
久しぶりに雑誌でも買うかって事でCQ誌にした。ハード寄り、pythonに毒されていないからね。 新製品のトランシーバーが出てた。電波状況をリアルタイムにモニター、その画面にお触りして、拡大出来るって? 今風だなあ。若者なら手軽に扱えるだろうけど、高価だから買えるか? 金持ってるのは、じじいだけど、扱えるか? まあ、どうでもいいんだけど。
そんなメーカーの既製品には背を向けて、自作に励むじじいが居る。これなら昔取った杵柄で、なんとかなる。扱う部品はICとかトランジスタなんて言う、ちまちました部品じゃなく球だ。ああ、球って真空管の事ね。
回路図は、昔から公開されている。Open Hardwareな訳よ。部品を集めれば、誰でも組み立てられますよ。
凄い回路図が載ってた。1965年の6月に公開された、3球のSSB送信機。えーと、目を疑ったぞ。 よく見たら、PSNタイプのやつだった。 12AT7でマイクからの音声を増幅。6AU6で7MHzの水晶発振。AFとRFの信号は、RとCのブリッジ型移相器で、90度の位相差を作る。それをダイオード4本による、バランスド・モジュレーターで変調する。終段は2E26って球でやってる。
貧乏人のSSB送信機。懐かしいなあ。キャリー・サプレッションはどれぐらい? オイラーも試してみたくなったよ。事前検証が必要だな。
鍵はPSNだ。ちゃんと90度の位相差を持った信号を作れるのか? オシロスコープのX,Y入力に信号を入れて、真ん丸の線が描かればOK。リサージュ波形だな。
オシロなんて持っていないから、伝達関数を求めて、位相の差分を描かせればいいのか。どのアプリが楽? julia ?, octave ? GNU Radio ? 色々有って迷っちゃうぞ。
アマチュア無線は、回路図公開が原則、自慢の種だわな。電子工作もしかりだ。昔から技術の公開って当たり前のように行われていた。その裏には、部品を集めなくてはならない。回路図では表現出来ないようなノウハウが有るなんて言う、ハードルが有った。
その点、ソフトはどうよ。指先一本で、すいと複製出来ちゃうからねぇ。開発費をかけてやってるメーカーは、死活問題なんだな。
PSNタイプのSSB発生器の試作 Try it.
VMware update
いつも愛用してる仮想化ソフトのVMware Playerにアップデートの案内が来た。15.X から、どんなVerになるかな? 期待を込めてUpdate。
が、Update後、エラーになって起動しない。いつもの事よ。インストール用のexeを手に入れて、修復すれば良いはず。
こちらへ、取りに行った。 VMware Workstation Player そしたら、メジャーバージョンが上がってて、あれよあれよと言う間に、上書きでインストールが行われてしまった。かくして、Ver 16.1 になった。ゲストで入れたOpenBSD等は、当たり前に動いている。
仮想化ソフトは、他にもVertualBoxを入れているけど、性能的にはVMwareの方が勝っている。 (個人的な評価です。単に同じゲストOSを使ってのコンパイル速度比較をやっただけです) 個人で使う分には、無料だし、変な制限も無いので、お勧めです。
全く、良い世の中になったものだ能。
pp.plはどうなった?
また少し、nprologの続きをやる。気になっていた、example{lisp.pp,pp.pl} 。
まずはlisp.plだな。こちらの方が馴染みが有りますから。それに、作者様の癖を知れますから。本体のC語で書かれたソース、それから前回のfizzbuzz.plもそうなんだけど、まず主題と言うか主関数を定義し、それから下位の関数を定義するって方針だ。 lisp.plはどうかな?
repl :- repeat, write('> '), read(X), eval(X,Y,[]), write(Y),nl, (X=[quit]->true;fail).
いきなりのreplですよ。ぐるぐる回るために、リピートが一番最初に来てる。プロンプトを表示してから、S式を読んで、評価して、印刷して、最後にあるのは、右矢印だけど、これって if ~ then ~ else だろうね、と勝手に想像。まさにreplだ。
後はevalだな。巨大なやつが定義されてる。関数定義とdefunとか、setqも有るな。 走らせてみるか。
vbox$ pl -c example/lisp.pl N-Prolog Ver 1.2 ?- repl. > 123. 123 > (setq pl 12). Syntax error not one operand with no operator ?-
文法間違いが有ると、落ちるんだな。
vbox$ fgrep 'Syntax error not one operand with no operator' *.c vbox$ fgrep 'not one operand with no operator' *.c parser.c: error(SYNTAX_ERR,"not one operand with no operator ",1);
目を皿にしてlisp.plをみてたら
> [setq, pl, 12]. t Existence error fun(setq,v_83,v_84)
まだ、エラーだよ。ええい、伝家の宝刀gdbを出動させよう。
grep -nH -e EXISTENCE_ERR *.c error.c:151: case EXISTENCE_ERR: main.c:441: error(EXISTENCE_ERR,"", goal);
エラーを捕まえてみるかな。
vbox$ gdb -q pl Reading symbols from pl...done. (gdb) b main.c:441 Breakpoint 1 at 0xba9e: file main.c, line 441. (gdb) r -c example/lisp.pl Starting program: /home/sakae/bin/pl -c example/lisp.pl N-Prolog Ver 1.2 ?- repl. > [setq, pl, 12]. t Breakpoint 1, prove (goal=7000146, bindings=8, rest=7000139, n=2) at main.c:441 441 error(EXISTENCE_ERR,"", goal); (gdb) bt #0 prove (goal=7000146, bindings=8, rest=7000139, n=2) at main.c:441 #1 0x1a147700 in prove_all (goals=7000142, bindings=8, n=2) at main.c:370 #2 0x1a147cc8 in prove (goal=7000097, bindings=4, rest=7000053, n=1) at main.c:475 #3 0x1a147700 in prove_all (goals=7000090, bindings=4, n=1) at main.c:370 #4 0x1a147cc8 in prove (goal=7000076, bindings=1, rest=7000053, n=0) at main.c:475 #5 0x1a147700 in prove_all (goals=7000056, bindings=1, n=0) at main.c:370 #6 0x1a1478ef in prove (goal=7000069, bindings=0, rest=7000056, n=0) at main.c:408 #7 0x1a147700 in prove_all (goals=7000059, bindings=0, n=0) at main.c:370 #8 0x1a1478ef in prove (goal=7000067, bindings=0, rest=7000059, n=0) at main.c:408 #9 0x1a147700 in prove_all (goals=7000062, bindings=0, n=0) at main.c:370 #10 0x1a156b4b in b_repeat (arglist=0, rest=7000062) at builtin.c:246 #11 0x1a147958 in prove (goal=406, bindings=0, rest=7000062, n=2) at main.c:416 :
どうも、ゴールを間違えているな。深入りするのは止めて、もう一方の雄である pp.plを試してみるか。
vbox$ pl -c example/pp.pl N-Prolog Ver 1.2 ?- pp. : ?- 123. Existence error predicate_property(123,built_in)
これ以上簡単なものは無いという程、簡単なやつ。でもエラーを喰らった。大体 predicate_property
なんて関数無いしね。
ひょっとして、作りかけでまだインプリメントされていない可能性があるな。きっとそうだろう。作者様の性格が出てる気がする。曰く、こんなプログラムが動けばいいなって、主題だけを書いてみた。後は、すこしづつ版をあげながら、動くようにしてくって作戦(楽しみ方)。
余り長い間、版を上げないのも失礼かと思うので、最新版にするかな。
vbox$ ./npl -c example/lisp.pl N-Prolog Ver 1.48 ?- repl. > [setq, pl, 148]. t > pl. 148 > [quit]. t yes ?-
うん、lispの方はBugが治っている。じゃ、pp.plは?
あれれの、れである。私(もとえ、あの方)の、pp.pl は、どこに行ってしまったのでしょうか?
ハードウェアで言うなら、受信機を作っていて、将来はSメーター(信号強度表示用)を取り付けようと思って、シャーシををごりごり穴開けした。真空管を後で取り付けられるようにしておいたのさ。でも、やーめたと、途中で気分変更。折角開けた穴を、羽目板で塞いでしまった様。
作者様に、心境の変化を聞いてみたいものだ。