gdb, lldb

サツマイモ

隣家からサツマイモを6本も頂いた。今年はサツマイモの病気が流行っていて不作のはずなのに、剛毅なものだ。田舎はいいなあ。

先月、実家の柿が余りに沢山出来すぎて、いやと言う程収穫したんで、食べてくださいって、周りに配ったんだった。みんな律儀だから、お返しは気にしないでって一言添えたんだけどね。

まあ、家では食べ切れないので、実家にもおすそ分け。柿も一杯取ったししね。取り切れなかった柿は、鳥が来てみんな綺麗にしたらしい。それはいいんだけど、ひよ鳥だったみたいで、柿をついばむ順番待ちを電線に止まってしてたらしい。糞を落とすので、慌てて柿を叩き落として、埋めてしまったとか。10月頃は、まだ熟さない柿がボタボタ落下して、諦めていたのに、時期が来れば、なんとかなるのね。

で、くだんのさつまいも、まずは天ぷらで美味しく頂いた。勿論、薩摩の芋焼酎と友にね。次は、電子レンジでチンしてから、バターで絡めた。柔らかくなりすぎたと言って、次は生からのバター炒め。味に変化が無いとか言って、ブランデーを振りかけた。

まだ芋があるんで、今度は、細かく刻み、ふかしパンに混ぜ込んだ。料理は工夫だな。勿論、料理する人は女房。オイラーは、ひたすら食べる人だけど。

lldb

lldb で使えるコマンド一覧

LLDB: 「po」の先へ – WWDC2019

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つは無いわな。コンパイル系とインタープリタ系って事です。世間に遅れを取らないようにせいよ。


This year's Index

Home