前回はWinDbgを使ったけど、今回はうまく見れなかったのでgdbを使ってみる。 (gdbなので、Windows以外でも似たような感じでデバッグできるはず)
gdbをインストール
Rtools Bash(これを書いている段階ではRtools40の方)を立ち上げて、以下でgdbをインストール
pacman -S ucrt64/mingw-w64-ucrt-x86_64-gdb
Rをデバッグビルド
このやり方でビルドする。quick-build.sh
のmake
の行にdebug=T
を付け加えるといいらしい(どう違うのかあまり把握してない)。
Rを実行
まずはビルドしたRを実行する。
Sys.getpid()
でPIDが得られるので、別のRtools Bashを立ち上げて、そのPIDをアタッチする。 が、デバッグしたいライブラリを読み込んでからでないとシンボルが見えないので読み込む。 今回はgridの中の関数にブレークポイントを仕掛けたいので、
library(grid)
しておく。準備が終われば、以下のコマンドでアタッチする。
/ucrt64/bin/gdb -p <PID>
b
でブレークポイントを仕掛ける。今回は、doSetViewport()
という関数で問題が起こっているようなのでそこに仕掛ける。
(gdb) b doSetViewport Breakpoint 1 at 0x7ffacc6b55e0: file grid.c, line 150.
仕掛けられたら、 c
で R のセッション側にコントロールを戻す。
(gdb) c Continuing.
Rのコードを実行して指定したブレークポイントを通過すると、Rの実行が止まってgdbで操作できるようになる。
Thread 1 hit Breakpoint 1, doSetViewport (vp=vp@entry=0x1654e77d080, topLevelVP=topLevelVP@entry=TRUE, pushing=pushing@entry=TRUE, dd=dd@entry=0x1654cfb3c80) at grid.c:150 150 {
bt
でバックトレースを見たり、
(gdb) bt #0 doSetViewport (vp=vp@entry=0x1654e77d080, topLevelVP=topLevelVP@entry=TRUE, pushing=pushing@entry=TRUE, dd=dd@entry=0x1654cfb3c80) at grid.c:150 #1 0x00007ffacc6cb176 in initVP (dd=dd@entry=0x1654cfb3c80) at viewport.c:406 #2 0x00007ffacc6b53c7 in dirtyGridDevice (dd=dd@entry=0x1654cfb3c80) at grid.c:112 #3 0x00007ffacc6b55a8 in dirtyGridDevice (dd=0x1654cfb3c80) at grid.c:124 #4 L_gridDirty () at grid.c:122 ...略...
n
(先に進む)とかs
(先に進む&次の関数に入る)でステップ実行していく
(gdb) n 157 getDeviceSize((dd), &devWidthCM, &devHeightCM); (gdb) n 158 if (!topLevelVP && pushing) { (gdb) n 192 if (LOGICAL(gridStateElement(dd, GSS_RESOLVINGPATH))[0]) { (gdb) n 201 } else if (isClipPath(viewportClipSXP(vp))) { (gdb) n 219 if (viewportClip(vp) == NA_LOGICAL) { (gdb) n 232 } else if (viewportClip(vp)) { (gdb) n 236 double rotationAngle = REAL(viewportRotation(vp))[0]; ...略... (gdb) n 353 UNPROTECT(1); (gdb) n 358 if (LOGICAL(gridStateElement(dd, GSS_RESOLVINGPATH))[0]) { (gdb) s gridStateElement (dd=dd@entry=0x1654cfb3c80, elementIndex=elementIndex@entry=16) at state.c:154 154 return VECTOR_ELT((SEXP) dd->gesd[gridRegisterIndex]->systemSpecific,
で、今回はどうやらここがダメそう、ということが分かった。
(gdb) s [New Thread 9448.0x54fc] ../../gdb-10.1/gdb/infrun.c:2614: internal-error: void resume_1(gdb_signal): Assertion `pc_in_thread_step_range (pc, tp)' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) [answered Y; input not from terminal]
もうちょっと変数の中身とかを覗けば色々わかるのかもしれないけど今日はこのへんで終わり。バグの原因がぜんぜん特定できない...