gdb, lldb
サツマイモ
隣家からサツマイモを6本も頂いた。今年はサツマイモの病気が流行っていて不作のはずなのに、剛毅なものだ。田舎はいいなあ。
先月、実家の柿が余りに沢山出来すぎて、いやと言う程収穫したんで、食べてくださいって、周りに配ったんだった。みんな律儀だから、お返しは気にしないでって一言添えたんだけどね。
まあ、家では食べ切れないので、実家にもおすそ分け。柿も一杯取ったししね。取り切れなかった柿は、鳥が来てみんな綺麗にしたらしい。それはいいんだけど、ひよ鳥だったみたいで、柿をついばむ順番待ちを電線に止まってしてたらしい。糞を落とすので、慌てて柿を叩き落として、埋めてしまったとか。10月頃は、まだ熟さない柿がボタボタ落下して、諦めていたのに、時期が来れば、なんとかなるのね。
で、くだんのさつまいも、まずは天ぷらで美味しく頂いた。勿論、薩摩の芋焼酎と友にね。次は、電子レンジでチンしてから、バターで絡めた。柔らかくなりすぎたと言って、次は生からのバター炒め。味に変化が無いとか言って、ブランデーを振りかけた。
まだ芋があるんで、今度は、細かく刻み、ふかしパンに混ぜ込んだ。料理は工夫だな。勿論、料理する人は女房。オイラーは、ひたすら食べる人だけど。
lldb
Windows 10で始めるC言語開発 第5回 Windows 10でC言語開発をしよう! Visual Studio Code デバッグ編
ob$ which lldb /usr/bin/lldb
突然こんな書出しで始めたのには訳がある。そう、前回wyhashをgdbにかけた所、使いにくかった。でふと、lldbなんてコマンドを思い出したのさ。但し、OpenBSD(32Bit)には、どういう訳だか入っていない。標準提供だと言うのにね。じわじわi386はオワンコですよって圧力がかかっているんだな。
上にあげたリンクのごとくpythonと組合せるのが普通みたい。まあ、そんなのはどうでもよくて、
ob$ lldb a.out (lldb) target create "a.out" Current executable set to '/tmp/t/a.out' (x86_64). (lldb) b main Breakpoint 1: where = a.out`main + 31 at qq.cpp:20:20, address = 0x0000000000003a1f (lldb) r Process 2445 launched: '/tmp/t/a.out' (x86_64) Process 2445 stopped * thread #1, stop reason = breakpoint 1.1 frame #0: 0x000006c37a6afa1f a.out`main at qq.cpp:20:20 17 } 18 19 int main () { -> 20 const uint64_t size = 1ull << 20; ^ 21 wyhashmap_t *idx = (wyhashmap_t *) calloc (size, sizeof (wyhashmap_t)); 22 vector < int > value (size); 23 vector < string > keys (size);
ソース行が出てくるのは、便利なんだか余計なお世話だか微妙。続けてnで先へ進める。
Process 2445 stopped * thread #1, stop reason = step over frame #0: 0x000006c37a6afb92 a.out`main at qq.cpp:32:17 29 else { 30 idx[pos] = hash_of_key; 31 keys[pos] = key; -> 32 value[pos] = 0; ^ 33 } 34 free (idx); 35 } (lldb) p key (std::string) $0 = "dhskfhdsj" (lldb) p pos (uint64_t) $1 = 881675 (lldb) p keys[$1] error: Can't evaluate the expression without a running target due to: Interpreter doesn't handle one of the expression's opcodes
なんか言い掛かりを付けられたな。これが出来無いと価値が半減ってか、使う理由が無くなっちゃうぞ。
(lldb) p keys (std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char > >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocat or<char> > > >) $2 = { std::__1::__vector_base<std::__1::basic_string<char, std::__1::char_traits<cha r>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char , std::__1::char_traits<char>, std::__1::allocator<char> > > > = { __begin_ = "" __end_ = "" __end_cap_ = { std::__1::__compressed_pair_elem<std::__1::basic_string<char, std::__1::ch ar_traits<char>, std::__1::allocator<char> > *, 0, false> = (__value_ = "") } } }
そして、相変わらずの困ったちゃんであります。もう、素直にFreeBSDでlldbしとけって事かな。
lldb in FreeBSD
(lldb) p keys[pos] (std::__vector_base<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::value_type) $0 = "dhskfhdsj" (lldb) p value (std::vector<int, std::allocator<int> >) $2 = { std::__1::__vector_base<int, std::__1::allocator<int> > = { __begin_ = 0x21401200 __end_ = 0x21801200 __end_cap_ = { std::__1::__compressed_pair_elem<int *, 0, false> = { __value_ = 0x21801200 } } } }
これがlldbのデフォの挙動なの? gdbの方が扱い易いな。emacsと連携させるにも楽だし。
new gdb in OpenBSD
OpenBSDのgdbは古い。超が付く程古い。ならば駄目元で最新のgdbをコンパイルしてみる。 configのパラメータは、portsのそれを丸写し。
ob$ ./configure --disable-nls --disable-sim --without-guile --without-lzma
待つこと25分で、どうにか出来上がった。
ob$ ./gdb ./a.out GNU gdb (GDB) 11.1 Copyright (C) 2021 Free Software Foundation, Inc. : Reading symbols from ./a.out... (gdb) b main Breakpoint 1 at 0x3a00: file qq.cpp, line 19. (gdb) r Starting program: /tmp/t/a.out Abort trap (core dumped)
が、憐な事にエラーである。一応検死しとく。同僚の検死って辛いものがあるな。
ob$ gdb gdb gdb.core GNU gdb (GDB) 7.12.1 Copyright (C) 2017 Free Software Foundation, Inc. : Reading symbols from gdb...done. [New process 303198] [New process 426110] [New process 100637] [New process 520266] [New process 497738] Core was generated by `gdb'. Program terminated with signal SIGABRT, Aborted. #0 thrkill () at /tmp/-:3 3 /tmp/-: No such file or directory. [Current thread is 1 (process 303198)]
スレッドのハンドリングに難があるのは、gaucheで合点承知の介。ここでも頭をもたげてきたか。
(gdb) bt #0 thrkill () at /tmp/-:3 #1 0x000001653cd6482e in _libc_abort () at /usr/src/lib/libc/stdlib/abort.c:51 #2 0x000001632897ff25 in handle_sigsegv (sig=11) at event-top.c:893 #3 <signal handler called> #4 0x0000000000000000 in ?? () #5 0x0000016328a68655 in x86_dr_stopped_data_address (state=0x165a23e9d90, addr_p=0x7f7ffffcc570) at nat/x86-dregs.c:608 #6 0x0000016328a68893 in x86_dr_stopped_by_watchpoint (state=0x165a23e9d90) at nat/x86-dregs.c:650 #7 0x000001632881af97 in x86_nat_target<obsd_nat_target>::stopped_by_watchpoint (this=0x165a23e9d90) at ./x86-nat.h:100 #8 0x000001632884633f in watchpoints_triggered (ws=0x165a23e9d90) at breakpoint.c:4791 #9 0x0000016328a04331 in handle_signal_stop (ecs=0x7f7ffffcc990) at infrun.c:6122 #10 0x00000163289fac07 in handle_inferior_event (ecs=<optimized out>) at infrun.c:5740 #11 0x00000163289f98f5 in fetch_inferior_event () at infrun.c:4111 #12 0x0000016328829f9a in check_async_event_handlers () at async-event.c:335 #13 0x0000016328ce4b25 in gdb_do_one_event () at event-loop.cc:216 #14 0x0000016328a30cf5 in start_event_loop () at main.c:421 #15 captured_command_loop () at main.c:481 #16 0x0000016328a2d795 in captured_main (data=<optimized out>) at main.c:1353 #17 gdb_main ( args=<error reading variable: Unhandled dwarf expression opcode 0xa3>) at main.c:1368 #18 0x00000163287db078 in main ( argc=<error reading variable: Unhandled dwarf expression opcode 0xa3>, argv=0x7f7ffffcc570) at gdb.c:32
多分、そういう事なんだろうね。だから、portsでも、7.12.1止まりなんだろうね。あーあ、これで諦めがついた。OpenBSDではCフラフラするな。末期までね。
check lldb
一応、OpenBSDなlldbが出したエラーを見ておく。どうもソースはひとくくりにgnuって所にまとめられている。こんな分類で文句がこないのかね?
ob$ cd /usr/src/gnu/ ob$ ls Makefile README gcc/ lib/ llvm/ share/ usr.bin/ usr.sbin/ ob$ grep "Interpreter doesn't handle one of the expression's opcodes" -rIl . ./llvm/lldb/source/Expression/IRInterpreter.cpp
README
このディレクトリには、「巨大で汚いけど、避けられない」ソフトウェアが含まれています。 このサブツリーに含まれるソフトウェアの中には、特別なルールに従ったものもありますが、 すべてではありません。すなわち、BSD以外のライセンスです。
ほー、斜め上の目線ってか、OpenBSD的な解釈だな。この後更に言い訳が続いている。興味ある人は、読んでみるといいよ。何たって零細企業ゆえの選択だからね。 こういう機微は、DeepL DeepL logo 翻訳ツール と言う所にお世話になると良い。
static const char *unsupported_opcode_error = "Interpreter doesn't handle one of the expression's opcodes"; static const char *unsupported_operand_error = "Interpreter doesn't handle one of the expression's operands";
こんな所に定義されてた。それじゃ前半のエラー説明文は?
at lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls(); can_interpret = IRInterpreter::CanInterpret( *execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error, interpret_function_calls); if (!can_interpret && execution_policy == eExecutionPolicyNever) { err.SetErrorStringWithFormat( "Can't evaluate the expression without a running target due to: %s", interpret_error.AsCString());
at FreeBSD
一応確認しとく。
[sakae@fb /usr/src]$ grep "Interpreter doesn't handle one of the expression's opcodes" -rIl . ./contrib/llvm-project/lldb/source/Expression/IRInterpreter.cpp
寄贈品のエリアに展示されてた。他にどんな物を受け入れてるか見ると、bc,bzip2,diff,less,lua,nvi,pf,sqlite3等、その数は87個に及んでいる。いずれも重要なものばかり。それがFreeBSDの大地にしっかりと根を張っているんだな。
まあ、lldbにしろllvmにしろ、中に飛び込んで行ったら、討死する事間違い無しなので、もう忘れる事にしよう。それよりリナのユーザーっぽく実用分野の探求だな。
file read by c++
実用と言えば、ファイルからデータを読み込むのが浮んでくる。ハロワじゃ無意味だからね。 網羅的には、 Programming Place Plus 新C++編 さんぐらいかな。
でも、もっと身近にあった。それをえさにしてみる。
#include <fstream> #include <vector> using namespace std; vector < string > v; int main (void) { string file = "/usr/share/dict/words", s; ifstream qfi(file.c_str()); for (qfi >> s; !qfi.eof(); qfi >> s) if (s.size ()) v.push_back (s); qfi.close (); }
単語帳からデータを読み込んで、文字列ヴェクターに格納するって奴。文字列の格納場所とか長さがドータラコータラと五月蝿い事は言われないのがC言語より進化した証だろう。
それから、string fileって言う変数名。いかにもファイルって事で、特別な意味を宿しているかと思ったら違った。fileをhogeって名前に変更しても、普通に動く。これって、型の自動推測が働いているんだな。曰く、ifstreamって型名から、ファイルに関する事だなと推測。すると、 hoge.c_str()
のhogeは、きっとファイル名を示す文字列に違いない。
他に感心したのが、ifstreamで宣言してるqfiって言う変数もどきみたいな奴(初学者ゆえ、正式名は知らん)。C言語の文字列だよって教えてあげるだけで、Cフラフラ語の世界へと導いてくれる。
これ、最初関数ってかメソッドかと思って、一生懸命にマニュアルを探してしまったのは、内緒だぞ。
まて、そんなのschemeで言うportじゃん。gaucheなんて凄いぞ。読み込む時に、文字列のエンコーディング変換ぐらいは、平気で押しつけられるからね。
Cフラフラで悩んだら、まずはgaucheの機能を思い出せ、かな。で、うろうろしてたら、
例を示しましょう。以下のコードは未知のCES(但しEUC-JP, SJIS, ISO2022-JP, UTF8の いずれかであることは分かっている)で書かれたテキ ストファイル‘unknown.txt’を 読みだし、文字エンコーディングを EUC-JPに変換して‘eucjp.txt’に書き出します。 (call-with-output-file "eucjp.txt" (lambda (out) (copy-port (open-input-conversion-port (open-input-file "unknown.txt") "*jp" ;guess code :to-code "eucjp" :owner? #t) ;close unknown.txt afterwards out)))
nkfもとえiconv内蔵してます。それをさりげなくportに紐付けられます。とか
NAMEキーワード引数はGaucheの拡張です。 デフォルトでは、作られるポー トの名前は‘(input string port)’になります。 ポートの名前は主にデバ ッグのために使われます。この引数で代わりの名前を指定できます。 Gaucheの慣習として、ファイルポートは元ファイルのパス名を名前に持つ ので、 ポート名にデバッグ用途の情報を載せる場合はパス名と区別しやす いよう括弧に入れるのが良いでしょう。 gosh> (open-input-string "") #<iport (input string port) 0x215c0c0> gosh> (open-input-string "" :name "(user input)") #<iport (user input) 0x22a4e40>
親切過ぎる機能を見付けてしまった。もう、炬燵に入ってヌクヌク気分になりそうだな。Cフラフラで少し頑張ってみんしゃい。
(gdb) p qfi $1 = <incomplete type> (gdb) p v $2 = std::vector of length 6, capacity 8 = {"A", "A's", "AMD", "AMD's", "AOL", "AOL's"}
gdbで確認するも、ちゃんと正体を明かさない、つつましさであります。
この短かいコードを見るにつけ、golangよりは馴染が有るような気分になったよ。幻想かもしれんけど。
rust
Rustは本当に動作が高速なのか? Pythonとの比較で分かる、Rustのパフォーマンス特性
今一番人気のものらしい。って、一番が2つは無いわな。コンパイル系とインタープリタ系って事です。世間に遅れを取らないようにせいよ。