バイナリーパッチを試してみた
前回の話(http://d.hatena.ne.jp/miura1729/20080806/1218026143)を試してみました。こんな感じの手抜きプログラムを使って試しました。本当はこの後write barrierのチェックコードの挿入が必要ですが、今回は手抜きでどこがストア命令か教えてくれるだけです。
#!/bin/env ruby # ニモニックパターンの定義 NIMONIC_FILE_NAME = /^\s*\.file\s+\"(.*?)\"/ NIMONIC_LINE_NUMNER = /^\s*\.stabn\s+.*?,.*?,(.*?),/ NIMONIC_STORE = /^\s*movl\s+(.*?)\s*,\s*(-?[0-9]+)?\((.*?)\)/ REGISTOR_STACK = ["%esp"] REGISTOR_BESE_POINTER = ["%ebp"] REGISTOR_SPBP = REGISTOR_BESE_POINTER + REGISTOR_STACK @curfile = nil @file_content = nil @curline = nil ARGF.each_line do |lin| case lin when NIMONIC_FILE_NAME @curfile = $1 @file_content = File.readlines(@curfile) when NIMONIC_LINE_NUMNER @curline = $1 when NIMONIC_STORE src = $1 offset = $2 ? $2 : "" basereg = $3 if !REGISTOR_SPBP.include?(basereg) then print "#{@curfile}:#{@curline}" print @file_content[@curline.to_i - 1] end end end
いろいろ調べたところ、.file命令でCのファイル名が.stabnの第3引数でCレベルの行番号が得られるようです。
これを、使ってruby 1.9.0のgc.cで-S -gオプションをつけて試してみました。
一見、代入じゃないところも検出しているように見えますが、多分代入になっていると思います。
結果です。
gc.c:387 rb_thread_raised_clear(th); gc.c:388 GET_THREAD()->errinfo = nomem_error; gc.c:391 rb_thread_raised_set(th, RAISED_NOMEMORY); gc.c:426 ruby_gc_stress = RTEST(bool); gc.c:462 ruby_gc_profile = RTEST(bool); gc.c:465 objspace->profile.count = 0; gc.c:497 malloc_increase += size; gc.c:536 malloc_increase += size; gc.c:629 dont_gc = Qfalse; gc.c:651 dont_gc = Qtrue; gc.c:671 tmp->next = global_List; gc.c:672 tmp->varptr = addr; gc.c:673 global_List = tmp; gc.c:683 global_List = tmp->next; gc.c:691 tmp->next = tmp->next->next; gc.c:707 RUBY_CRITICAL( gc.c:707 RUBY_CRITICAL( gc.c:717 heaps_length = next_heaps_length; gc.c:760 heaps[hi].membase = membase; gc.c:761 heaps[hi].slot = p; gc.c:762 heaps[hi].limit = objs; gc.c:764 if (lomem == 0 || lomem > p) lomem = p; gc.c:765 if (himem < pend) himem = pend; gc.c:769 p->as.free.flags = 0; gc.c:770 p->as.free.next = freelist; gc.c:771 freelist = p; gc.c:790 heaps_inc = 0; gc.c:798 heaps_inc = next_heaps_length - heaps_used; gc.c:830 freelist = freelist->as.free.next; gc.c:886 dont_gc = 1; gc.c:887 during_gc = 0; gc.c:915 n->flags |= T_NODE; gc.c:916 nd_set_type(n, type); gc.c:918 n->u1.value = a0; gc.c:919 n->u2.value = a1; gc.c:920 n->u3.value = a2; gc.c:930 OBJSETUP(data, klass, T_DATA); gc.c:930 OBJSETUP(data, klass, T_DATA); gc.c:930 OBJSETUP(data, klass, T_DATA); gc.c:931 data->data = datap; gc.c:932 data->dfree = dfree; gc.c:933 data->dmark = dmark; gc.c:975 SET_STACK_END; gc.c:976 if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END); gc.c:985 SET_STACK_END; gc.c:999 mark_stack_overflow = 0; gc.c:1000 mark_stack_ptr = mark_stack; gc.c:1221 *mark_stack_ptr = ptr; gc.c:1225 mark_stack_overflow = 1; gc.c:1510 p->as.free.flags = 0; gc.c:1511 p->as.free.next = freelist; gc.c:1512 freelist = p; gc.c:1536 heaps[j] = heaps[i]; gc.c:1536 heaps[j] = heaps[i]; gc.c:1536 heaps[j] = heaps[i]; gc.c:1544 heaps_freed = last; gc.c:1567 freelist = 0; gc.c:1569 deferred_final_list = 0; gc.c:1582 p->as.free.flags = FL_MARK; /* remain marked */ gc.c:1583 p->as.free.next = final_list; gc.c:1588 p->as.free.flags = 0; gc.c:1589 p->as.free.next = freelist; gc.c:1590 freelist = p; gc.c:1599 RBASIC(p)->flags &= ~FL_MARK; gc.c:1607 heaps[i].limit = 0; gc.c:1609 p->as.free.flags |= FL_SINGLETON; /* freeing page mark */ gc.c:1611 freelist = free; /* cancel this page from freelist */ gc.c:1617 GC_PROF_SET_MALLOC_INFO; gc.c:1617 GC_PROF_SET_MALLOC_INFO; gc.c:1619 malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); gc.c:1620 if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; gc.c:1622 malloc_increase = 0; gc.c:1627 during_gc = 0; gc.c:1636 deferred_final_list = final_list; gc.c:1644 GC_PROF_SET_HEAP_INFO; gc.c:1644 GC_PROF_SET_HEAP_INFO; gc.c:1644 GC_PROF_SET_HEAP_INFO; gc.c:1644 GC_PROF_SET_HEAP_INFO; gc.c:1644 GC_PROF_SET_HEAP_INFO; gc.c:1645 deferred_final_list = final_list; gc.c:1649 GC_PROF_SET_HEAP_INFO; gc.c:1649 GC_PROF_SET_HEAP_INFO; gc.c:1649 GC_PROF_SET_HEAP_INFO; gc.c:1649 GC_PROF_SET_HEAP_INFO; gc.c:1649 GC_PROF_SET_HEAP_INFO; gc.c:1657 RANY(p)->as.free.flags = 0; gc.c:1658 RANY(p)->as.free.next = freelist; gc.c:1659 freelist = RANY(p); gc.c:1823 SET_STACK_END; gc.c:1886 GC_PROF_TIMER_START; gc.c:1886 GC_PROF_TIMER_START; gc.c:1886 GC_PROF_TIMER_START; gc.c:1886 GC_PROF_TIMER_START; gc.c:1888 SET_STACK_END; gc.c:2163 FL_SET(obj, FL_FINALIZE); gc.c:2168 finalizer_table = st_init_numtable(); gc.c:2190 FL_SET(dest, FL_FINALIZE); gc.c:2231 deferred_final_list = 0; gc.c:2249 p->as.free.flags = FL_MARK; /* remain marked */ gc.c:2250 p->as.free.next = *final_list; gc.c:2251 *final_list = p; gc.c:2267 deferred_final_list = 0; gc.c:2282 p->as.free.flags = 0; gc.c:2293 p->as.free.flags = 0; gc.c:2300 during_gc = 0; gc.c:2475 counts[i] = 0; gc.c:2667 rb_obj_freeze(rb_str_new2("failed to allocate memory"))); gc.c:2668 OBJ_TAINT(nomem_error); gc.c:2669 OBJ_FREEZE(nomem_error);