æè¡é¨ã®å½å (@k0kubun) ã§ãã
å æ¥byebugã®é«éåãè¡ã£ã¦ããæä¸ãå¤æ´ãå ããbyebugã使ã£ã¦ããã¨ä¸å®ã®ç¢ºçã§rubyãSEGVãããã°ãçºè¦ãã¾ããã ç§ã¯Cè¨èªã®ã³ã¼ãã®ãããã°ã®çµé¨ã¯ãªãã£ãã®ã§ããããããã¬ã®ä½¿ãæ¹ã調ã¹ãªããSEGVã®åå 調æ»ãè¡ãããããéã£ãã¨ããç¡äºåãè¾¼ã¾ããææ°ã®é«éãªbyebugãå®å ¨ã«ä½¿ããããã«ãªãã¾ããã
ãã®éãrubyèªä½ããããã°ããããã«å¿ è¦ãªæ å ±ãåæ£ãã¦ãã¦å¤§å¤ã ã£ãã®ã§ãã¾ã rubyã®ãããã°ããããã¨ããªãããã©ãã£ã¦ã¿ããã¨ãã人ã対象ã«ãgdbã¨ãããããã¬ã使ã£ãrubyã®ãããã°ã®æ¹æ³ãç´¹ä»ãã¾ãã
ãããã°ç¨ã«rubyããã«ããã
ãããã°æã«å¤æ°åãã½ã¼ã¹ã³ã¼ããªã©ã®æ å ±ãè¦ãããã«ã¯ãæé©åãªãã·ã§ã³ããªãã«ãã¦ãããã°ç¨ã«rubyããã«ããã¦ããå¿ è¦ãããã¾ãã
rubyã®ãããã°ç¨ãã«ãæé
GitHubã«ããrubyã®ãªãã¸ããªãcloneãã¦ãããã°ç¨ã«ãã«ãããæé ãç´¹ä»ãã¾ãã ãããã°ã«å¿ è¦ãªgccã®ã³ã³ãã¤ã«ãªãã·ã§ã³ã«é¢ãã¦ã®è©³ç´°ã¯ãã¡ãã®ããã¥ã¡ã³ããã覧ãã ããã
$ git clone https://github.com/ruby/ruby $ cd ruby # ./configureã(å)çæ $ autoreconf # -O0ã§æé©åãç¡å¹ã«ãããdebugflagsã¯ããã©ã«ã㧠"-ggdb3" ã«ãªã£ã¦ãã¾ãã $ ./configure optflags="-O0" $ make $ make install
ããã«ããçæããã./ruby
ã使ã£ã¦ãããã°ãã¦ããã¾ãã*1
ãã«ãããrubyãrbenvãã使ãã«ã¯
ãããã«ãããrubyãrbenvã§ç®¡çãããå ´åã¯~/.rbenv/versions/
以ä¸ã«ã¤ã³ã¹ãã¼ã«ããå¿
è¦ãããã¾ãã以ä¸ã®ãããªæé ã§trunkã¨ãã¦rbenvãã使ããããã«ã§ãã¾ãã
# ~/.rbenv/versions/trunk ã«ã¤ã³ã¹ãã¼ã«ãããããã«ãã $ ./configure optflags="-O0" --prefix="${HOME}/.rbenv/versions/trunk" $ make $ make install
ãããã°ã«ä½¿ãæã¯ã./ruby
ã®ä»£ããã«$(RBENV_VERSION=trunk rbenv which ruby)
ãæå®ãã¦ãã ããã
gdbã§rubyã®åä½ã追ã£ã¦ã¿ã
ã§ã¯ã以ä¸ã®ã³ã¼ããrubyã«ã©ã®ããã«å¦çãããã®ãgdbã使ã£ã¦å®éã«è¿½ã£ã¦ã¿ã¾ãããã
str = 'world' str.prepend('hello ') puts str
rubyã®ã¡ã½ãããå®è£ ããã¦ããé¢æ°åã調ã¹ã
str.prepend('hello ')
ã®åå¾ã§å¤æ°str
ãã©ãå¤ããããè¦ã¦ã¿ã¾ãã
String#prepend
ãå®è¡ãããç´åã§ãã¬ã¼ã¯ããããã«ã¯ãã¾ããããCã®ã½ã¼ã¹ã®ã©ãã§å®è£
ããã¦ãããç¥ãå¿
è¦ãããã¾ãã
ruby-docã®String#prependã®ãã¼ã¸ã§ãclick to toggle sourceãã¨ãããªã³ã¯ãã¯ãªãã¯ããã¨ã以ä¸ã®ããã«String#prepend
ã¯rb_str_prepend
ã§å®è£
ããã¦ãããã¨ãããã¾ãã
調ã¹ãé¢æ°ã§ãã¬ã¼ã¯ãã
ã©ã®é¢æ°ã§ãã¬ã¼ã¯ããããããã£ããã以ä¸ã®ããã«ç®çã®é¢æ°ã«break
ããrun
ã§ã¹ã¯ãªãããèµ°ããã¾ãã
$ echo "str = 'hello'\nstr << ' world'.freeze\nputs str" > ./hello.rb $ gdb --args ./ruby ./hello.rb (gdb) break rb_str_prepend Breakpoint 1 at 0xdc16b: file string.c, line 2689. (gdb) run Starting program: /home/vagrant/ruby/ruby ./hello.rb [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1". [New Thread 0xb7ae5b40 (LWP 2272)] Breakpoint 1, rb_str_prepend (str=2151591520, str2=2151591700) at string.c:2689 2689 StringValue(str2);
rb_str_prepend
ã§å®è¡ãæ¢ãããã¾ããã
ç¶æ³ã確èªãã
ä¸è¨ã®åºåã ãã ã¨ä»ã©ãã«ããã®ããããã«ããã§ããããããã°ç¨ã«rubyããã«ããã¦ãããããã§ãlist
ãå©ãã¨ä»¥ä¸ã®ããã«å¨è¾ºã®ã½ã¼ã¹ã³ã¼ãã表示ãããã¨ãã§ãã¾ãã
(gdb) list 2684 */ 2685 2686 static VALUE 2687 rb_str_prepend(VALUE str, VALUE str2) 2688 { 2689 StringValue(str2); 2690 StringValue(str); 2691 rb_str_update(str, 0L, 0L, str2); 2692 return str; 2693 }
str
ã¨str2
ã¯ä½ã確èªãã¦ã¿ã¾ããããVALUEã¯ãã¤ã³ã¿ãªã®ã§ãp
ã§å¤ããã®ã¾ã¾è¡¨ç¤ºããã¨ãªãã¸ã§ã¯ãã®ã¢ãã¬ã¹ã表示ããã¾ãã
(gdb) p str $1 = 2151591520 (gdb) p str2 $2 = 2151591700
ãã®ãªãã¸ã§ã¯ãã®å¤ã確èªããã«ã¯ã©ãããã°ããã§ãããããrubyå
ã«ã¯ãããã°ç¨ã«rb_p
ã¨ããé¢æ°ãå®ç¾©ããã¦ããããããcall
ã§å¼ã³åºãã¨å¤ã確èªã§ãã¾ãã
(gdb) call rb_p(str)
" world"
ããgdbãrubyã®ãªãã¸ããªå
ã§å®è¡ãã¦ããã°ãrubyã®ãªãã¸ããªã«ãã.gdbinitã§rb_p
ãcall rb_p
ã«ããã³ãã³ããå®ç¾©ããã¦ãããããrb_p
ã ãã§ç¢ºèªã§ãã¾ãã
(gdb) rb_p(str2)
"hello"
ä»ã«ããrb_backtrace
ã使ãã¨rubyã¬ãã«ã§ã®ããã¯ãã¬ã¼ã¹ãè¦ãã¾ãã
(gdb) rb_backtrace from ./hello.rb:2:in `<main>' from ./hello.rb:2:in `prepend'
ããã¯gdbã®ã³ãã³ãã§ãããbacktrace
ãå©ãã¨Cã¬ãã«ã§ã®ããã¯ãã¬ã¼ã¹ãè¦ãã¾ãã
(gdb) backtrace #0 rb_str_prepend (str=2151591520, str2=2151591700) at string.c:2691 #1 0x801381b1 in call_cfunc_1 (func=0x800dc165 <rb_str_prepend>, recv=2151591520, argc=1, argv=0xb7ae6020) at vm_insnhelper.c:1542 #2 0x80138b52 in vm_call_cfunc_with_frame (th=0x802a3c18, reg_cfp=0xb7b65fc8, calling=0xbfffede8, ci=0x80380ab8, cc=0x803d8058) at vm_insnhelper.c:1709 #3 0x80138c57 in vm_call_cfunc (th=0x802a3c18, reg_cfp=0xb7b65fc8, calling=0xbfffede8, ci=0x80380ab8, cc=0x803d8058) at vm_insnhelper.c:1804 #4 0x80139816 in vm_call_method_each_type (th=0x802a3c18, cfp=0xb7b65fc8, calling=0xbfffede8, ci=0x80380ab8, cc=0x803d8058) at vm_insnhelper.c:2091 #5 0x80139e81 in vm_call_method (th=0x802a3c18, cfp=0xb7b65fc8, calling=0xbfffede8, ci=0x80380ab8, cc=0x803d8058) at vm_insnhelper.c:2215 #6 0x8013a06c in vm_call_general (th=0x802a3c18, reg_cfp=0xb7b65fc8, calling=0xbfffede8, ci=0x80380ab8, cc=0x803d8058) at vm_insnhelper.c:2258 #7 0x8013cccd in vm_exec_core (th=0x802a3c18, initial=0) at insns.def:995 #8 0x8014c33c in vm_exec (th=0x802a3c18) at vm.c:1636 #9 0x8014cbc6 in rb_iseq_eval_main (iseq=0x803eafa0) at vm.c:1879 #10 0x80018fd5 in ruby_exec_internal (n=0x803eafa0) at eval.c:244 #11 0x800190dd in ruby_exec_node (n=0x803eafa0) at eval.c:309 #12 0x800190ab in ruby_run_node (n=0x803eafa0) at eval.c:301 #13 0x80017224 in main (argc=2, argv=0xbffff764) at main.c:36
ã¹ãããå®è¡ãã
å¤æ°ã®æ¨ç§»ã確èªããªããã¹ãããå®è¡ããã¦ã¿ã¾ããããnext
ãå©ãã¨1è¡ãã¤å
ã«é²ããã¨ãã§ãã¾ãã
2689 StringValue(str2); (gdb) next 2690 StringValue(str); (gdb) next 2691 rb_str_update(str, 0L, 0L, str2);
rb_str_update
ã¨ããä½ãæ´æ°ãèµ°ããããªé¢æ°ã®æåã«æ¢ã¾ãã¾ããããã®è¡ã§ã¯str
ã¨str2
ã®å¤ã¯ã©ãå¤ããã§ããããã
(gdb) next 2692 return str; (gdb) rb_p(str) "hello world" (gdb) rb_p(str2) "hello"
#prepend
ã®ã¬ã·ã¼ãã«ãªã£ã¦ãã" world"
ã®ã¿å¤ãå¤ãã£ã¦ãããã¨ã確èªã§ãã¾ããã
ãããã°ä¸ã«ä»»æã®å¼ãå®è¡ãã
rb_eval_string_protect
é¢æ°ã使ãã¨ããããã°ã®éä¸ã§ä»»æã®å¼ãå®è¡ãããã¨ãã§ãã¾ãã
(gdb) call rb_eval_string_protect("str << '!'", 0) $3 = 2151591520 (gdb) rb_p str "hello world!"
strã®æ«å°¾ã«"!"
ã追å ã§ãã¾ãããcontinue
ã§æå¾ã¾ã§èµ°ãããã¨ã©ããªãã§ããããã
(gdb) continue
Continuing.
hello world!
ãã®ããã«ãputs
ã«æ¸¡ãå¼æ°ããããã°ä¸ã«å¤æ´ã§ãã¦ãããã¨ã確èªã§ãã¾ããã
ãã¥ã¼ããªã¢ã«ã¯ä»¥ä¸ã§ããæå¾ã«ä»å使ç¨ããã³ãã³ããã¾ã¨ãã¦ããã¾ãã
ã³ãã³ã | æä½å 容 |
---|---|
break f | é¢æ°fã«ãã¬ã¼ã¯ãã¤ã³ããè²¼ã |
run | ããã°ã©ã ãå®è¡ãã |
list | ç¾å¨ããä½ç½®ã®ã½ã¼ã¹ã確èªãã |
p | Cã¬ãã«ã§ã®å¤ã確èªãã |
backtrace | Cã¬ãã«ã§ã®ããã¯ãã¬ã¼ã¹ã表示ãã |
rb_p | rubyã¬ãã«ã§ã®å¤ã確èªãã |
rb_backtrace | rubyã¬ãã«ã§ã®ããã¯ãã¬ã¼ã¹ã表示ãã |
next | 次ã®è¡ã«ç§»åãã |
continue | æå¾ã¾ã§å®è¡ãã |
call rb_eval_string_protect("...", 0) | ä»»æã®å¼ãå®è¡ãã |
rubyãSEGVããæã®ãããã°æ¹æ³
UNIXããã»ã¹ãç°å¸¸çµäºããã¨ãããã»ã¹ã®ã¡ã¢ãªã®ç¶æ ããã®ã¾ã¾ä¿åããã³ã¢ãã¡ã¤ã«ã¨ãããã®ãçæããã¾ãã rubyãSEGVããã¨ãããã®ã³ã¢ãã¡ã¤ã«ãgdbããèªã¿è¾¼ããã¨ã§ãå¾ããSEGVããç¬éã®ç¶æ³ã調æ»ãããã¨ãã§ãã¾ãã
ãã ãç°å¢ã«ãã£ã¦ã¯ããã©ã«ãã§ã³ã¢ãã³ããç¡å¹ã«ãªã£ã¦ãããã¨ãããã®ã§ã以ä¸ã®ããã«ã³ã¢ãã³ããæå¹ã«ãã¦ããrubyãSEGVããã¾ãã
$ ulimit -c # core file sizeã確èªã0ãªãã³ã¢ãã³ããããªã $ ulimit -c unlimited # ã³ã¢ãã¡ã¤ã«ã®ãµã¤ãºãæ大ã«ãã
ãã®å¾ä»¥ä¸ã®ããã«ããã¨SEGVæã®ç¶æ³ã調æ»ãããã¨ãã§ãã¾ãã
# ä¾ãã°OSXã§ã¯ /cores/core.XXXXX ã«ä½ããã $ gdb -c /path/to/core ./ruby
ãã以å¤ã®ãããã°æä½ã¯rubyã®åä½ã追ããããæã¨åãã§ãã
ã¾ã¨ã
rubyã®ãããã°ãå§ããã®ã«å¿ è¦ãªç¥èãä¸éãç´¹ä»ãã¾ããããããã ã£ãã§ããããã æ®æ®µrubyã使ãå´ã®ç«å ´ã ã¨Cè¨èªã®ãããã°ã«å¿ è¦ãªç¥èã¯ãªããªã身ã«ã¤ããªãã§ããããã£ã¦ã¿ãã¨rubyã®å é¨ã®æåãããã£ã¦é¢ç½ãã®ã§æ¯éã試ããã ããã