.logbook

学んだことを書き綴る、言わば航海日誌です。

mrubyデバッガ(mrdb)の設定可能なブレイクポイント数を増やす

f:id:ylgbk:20150119222556p:plain

先日mrubyデバッガ(mrdb)に関する記事を書いたところ、そこそこ評判が良かったので、もう少し実用的な話題について書きます。

ETロボコン2015の準備。mrubyの開発環境を知る - .logbook

mrubyデバッガ(mrdb)を使ってみる - .logbook

突然ですが、mrdbのブレイクポイントは最大いくつまで登録できるか、知っていますか?

$ mrdb countdown.rb 
(countdown.rb:1) b 1
Breakpoint 1: file countdown.rb, line 1.
(countdown.rb:1) b 2
Breakpoint 2: file countdown.rb, line 2.
(countdown.rb:1) b 3
Breakpoint 3: file countdown.rb, line 3.
(countdown.rb:1) b 4
Breakpoint 4: file countdown.rb, line 4.
(countdown.rb:1) b 5
Breakpoint 5: file countdown.rb, line 5.
(countdown.rb:1) b 6
Exceeded the setable number of breakpoint.
(countdown.rb:1) i b
Num     Type           Enb What
1       breakpoint     y   at countdown.rb:1
2       breakpoint     y   at countdown.rb:2
3       breakpoint     y   at countdown.rb:3
4       breakpoint     y   at countdown.rb:4
5       breakpoint     y   at countdown.rb:5
(countdown.rb:1) 

このように、5個を超えると「Exceeded the setable number of breakpoint.(セット可能な上限を超えました)」というエラーが出力されます。そう、mrdbはデフォルトのままでは5個しかブレイクポイントを登録できないのです!

ブレイクポイント数の上限が存在する理由

mrubyはマイコンボードのようなプアな環境で動作することを想定したVMです。このような環境では湯水のようにメモリを使うことができません。現状、メモリ量が少ない環境でも安全に動作するようブレイクポイントの上限数を少なくしています。

ブレイクポイントを登録すると当然ながらそれだけメモリを消費します。もし、搭載しているメモリサイズが小さい環境でブレイクポイントの上限を大きくすると、実装されたメモリの大半をブレイクポイントの情報を記憶するためだけに消費してしまうかもしれません。

ちなみに、下記がブレイクポイントの構造体です。

mrdb.h

/* 省略 */

typedef struct mrb_debug_linepoint {
  const char *file;
  uint16_t lineno;
} mrb_debug_linepoint;

typedef struct mrb_debug_methodpoint {
  const char *class_name;
  const char *method_name;
} mrb_debug_methodpoint;

typedef struct mrb_debug_breakpoint {
  uint32_t bpno;
  uint8_t enable;
  mrb_debug_bptype type;
  union point {
    mrb_debug_linepoint linepoint;
    mrb_debug_methodpoint methodpoint;
  } point;
} mrb_debug_breakpoint;

/* 省略 */

単純計算するとメモリ量は下記となります。(アラインメントを4[byte]と想定)

行番号指定ブレイクポイント(mrb_debug_linepoint)

4 + 4 = 8[byte]

メソッド名指定ブレイクポイント(mrb_debug_methodpoint)

4 + 4 = 8[byte]

ブレイクポイント1つあたり(mrb_debug_breakpoint)

4 + 4 + 4 + 8 = 20[byte]

実際にはこれに加えて、ファイル名、メソッド名、クラス名を記憶するエリアが文字長分allocateされるので、1つのブレイクポイントを記憶するために20[byte]+αのメモリを消費することとなります。

2015/1/20 12:30追記

厳密にはポインタ変数のバイト長が4byteでない環境も存在します。上記値は参考程度としてください。

ブレイクポイント数の上限を増やす方法

メモリ(RAM)に余裕のある環境であれば、ブレイクポイント数の上限を増加しても問題ありません。増加させるためには、ソースを一部編集します。

mrdbconf.h

/* 省略 */

/* maximum number of setable breakpoint */
#define MAX_BREAKPOINT 5 <---ここを編集

/* 省略 */

MAX_BREAKPOINTがデフォルト5となっています。この値を変更するとブレイクポイント数の上限に反映されます。変更した後、make clean→makeすることを忘れないようにしましょう。

ブレイクポイント数の上限を10にして確認した結果、このようになります。10個のブレイクポイントを設定することができました。

yuhei@yuhei-VirtualBox:~/Documents/sample_mrdb$ mrdb countdown.rb 
(countdown.rb:1) b 1
Breakpoint 1: file countdown.rb, line 1.
(countdown.rb:1) b 2
Breakpoint 2: file countdown.rb, line 2.
(countdown.rb:1) b 3
Breakpoint 3: file countdown.rb, line 3.
(countdown.rb:1) b 4
Breakpoint 4: file countdown.rb, line 4.
(countdown.rb:1) b 5
Breakpoint 5: file countdown.rb, line 5.
(countdown.rb:1) b 6
Breakpoint 6: file countdown.rb, line 6.
(countdown.rb:1) b 7
Breakpoint 7: file countdown.rb, line 7.
(countdown.rb:1) b 8
Breakpoint 8: file countdown.rb, line 8.
(countdown.rb:1) b 9
Breakpoint 9: file countdown.rb, line 9.
(countdown.rb:1) b 10
Breakpoint 10: file countdown.rb, line 10.
(countdown.rb:1) i b
Num     Type           Enb What
1       breakpoint     y   at countdown.rb:1
2       breakpoint     y   at countdown.rb:2
3       breakpoint     y   at countdown.rb:3
4       breakpoint     y   at countdown.rb:4
5       breakpoint     y   at countdown.rb:5
6       breakpoint     y   at countdown.rb:6
7       breakpoint     y   at countdown.rb:7
8       breakpoint     y   at countdown.rb:8
9       breakpoint     y   at countdown.rb:9
10      breakpoint     y   at countdown.rb:10
(countdown.rb:1) 

ブレイクポイントNoの上限を増やす方法

ブレイクポイント数の上限だけでなく、ブレイクポイントNoの上限値も存在します。ブレイクポイントNoとはブレイクポイントを登録する毎に付与される「通し番号」です。

(countdown.rb:1) b 3
Breakpoint 13: file countdown.rb, line 3. <--- ブレイクポイントNoは13

ブレイクポイントNoはブレイクポイントを全削除してもリセットされず、ブレイクポイントを登録する毎に増加し続けます。 この上限値は(ブレイクポイントの上限×1024)となっています。この上限値も変更することが可能です。変更する値は「10000」のような直値でも問題ありません。変更するためには下記ソースを修正します。

apibreak.c

/* 省略 */

#define MAX_BREAKPOINTNO (MAX_BREAKPOINT * 1024) <---ここを編集

/* 省略 */

ただし値は「1以上、4294967295以下」とする必要があります。この値はデフォルトのままでも十分かもしれませんね。