该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-08-18
最后修改:2010-08-19
我想更深入的了解Ruby内部的实现,出发点或许过于天真,
我想了解下这门语言的实现,从中或许可以学习到某些思路,
得到源码之后,首先要对其进行编译,不能采用默认的编译方式, 要在执行./configure的时候加上如下参数
或者在Makefile中添加如下标志参数:
这样编译的Ruby包含了充足的调试信息,同时还保留了Ruby源码中大量使用的宏信息, 比如我们在gdb中显示如下的宏: (gdb) info macro RTEST Defined at ./include/ruby/ruby.h:349 included at /home/zheng.cuizh/ruby-1.9.2-rc2/ruby.c:18 #define RTEST(v) (((VALUE)(v) & ~Qnil) != 0) 如果编译参数没有添加,那么编译出来的代码是没办法看到macro信息的。
在编译好Ruby后,需要使用make install安装,安装好后就可以登上调试Ruby之旅了。
调试Ruby有几种方法,只要能在你知道的地方下个断点,并且Ruby解析器能够执行到该断点即可, 我想到以下两种方式:
对于第一种方式,我们直接使用gdb ruby启动即可,然后在gdb的console中设置属性及断点:
对于第二种方式,我们先执行irb,然后再开启一个终端,通过ps ax|grep irb|grep -v grep|awk '{print $1}' 找到irb的进程id,然后用gdb attach到该进程即可:
这样的话就会在初始化Hash对象的时候被断到,然后就可以继续调试了。
个人推荐采用第二种方式来调试Ruby解析器。
这里我要多说一下,第一种方式的最后一步b main的意思是对main()这个位于main.c中的入口函数。
(gdb) list main
Ruby是一种解释型语言,它的代码都是没编译过的字符串,
vm_exec(th);
PREPARE_PARSE_MAIN({ 从而完成边解析边执行的过程。第一种方法的main.c函数就是ruby解析器的入口,当我们在那里下断点后,必定能将Ruby断下来。 在main.c35行这句话:return ruby_run_node(ruby_options(argc, argv)); 我们需要在gdb里面通过键入s跟进两次,ruby_run_node和ruby_options这两个函数都需要步入,他们都很重要。其中ruby_run_node会调用vm_exec来执行语法树。
至此,我们的准备工作就完成了。很简单的步骤,却很重要。
之后的工作就是不断的跟踪Ruby各种类型的实现机制,简单的描述就是在irb里面不停尝试各种类型的new操作,同时在gdb里面不断的对不同类型rb_object_initialize下断点,然后步入每一个想知道的方法中,对某些变量设置观察点,打印出结构体,再步进。
真感谢Ruby有个irb这么好用的工具,也是由于动态语言的缘故,代码可以通过eval来执行。 有了irb,我们就可以交互式调试没段代码了。
这是走进Ruby的开始,我也刚刚做好准备工作,很多Ruby内部的实现我还没有读懂,我边读边写,不过我要在我读懂了之后再写出来,由于悟性的问题,我可能写的很慢或者有错误的地方,而且思路可能还会很跳跃^-^,希望高手能指点一下。
rb_argv0 = rb_str_new4(rb_progname);
#define rb_progname (GET_VM()->progname) #define GET_VM() ruby_current_vm
typedef struct rb_vm_struct { VALUE self; rb_thread_lock_t global_vm_lock; struct rb_thread_struct *main_thread; struct rb_thread_struct *running_thread; st_table *living_threads; VALUE thgroup_default; int running; int thread_abort_on_exception; unsigned long trace_flag; volatile int sleeper; /* object management */ VALUE mark_object_ary; VALUE special_exceptions[ruby_special_error_count]; /* load */ VALUE top_self; VALUE load_path; VALUE loaded_features; struct st_table *loading_table; /* signal */ struct { VALUE cmd; int safe; } trap_list[RUBY_NSIG]; /* hook */ rb_event_hook_t *event_hooks; int src_encoding_index; VALUE verbose, debug, progname; VALUE coverages; struct unlinked_method_entry_list_entry *unlinked_method_entry_list; #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE struct rb_objspace *objspace; #endif } rb_vm_t;
rb_thread_lock_t global_vm_lock;
在调试过程中要善用bt这个命令,通过bt我们可以看到某个函数的调用栈,配合eclipse等IDE(没有IDE的话就用layout查看代码),可以很好的分析出代码的走向,一个实例创建的过程。
比如在以irb方式调试的时候,刚刚断入irb的进程,执行bt后看如下输出:
(gdb) bt
第一行read函数就是irb和使用者交互的方法, 最后一行的main就是Ruby解析器的入口函数, 从下到上就是Ruby解析器整个执行过程。 不过我还没弄明白loop_i这个函数的作用。
先写到这里,下一章我也不知道会写什么,因为前提是我看懂了什么^-^ 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-08-18
赞,最好能写成一个系列吧。读ruby hacking guide半途而废,1.9的代码比1.8应该有比较大的变动吧。
|
|
返回顶楼 | |
发表时间:2010-08-18
強烈建議來個系列...
|
|
返回顶楼 | |
发表时间:2010-08-18
dennis_zane 写道 赞,最好能写成一个系列吧。读ruby hacking guide半途而废,1.9的代码比1.8应该有比较大的变动吧。
fireflyman 写道 強烈建議來個系列...
我也很希望能持续的写下去,但途中肯定会遇到一些问题的,到时候我会把问题抛出来,还请大家不要吝啬各自的才华帮我看看问题,借助大家的帮忙估计还是能写几篇的,希望大家不吝赐教啊! |
|
返回顶楼 | |
发表时间:2010-08-18
拜 gdb 熟练工 ……
|
|
返回顶楼 | |
发表时间:2010-08-18
嗯我只是想说解释器和解析器是不一样的……
加油,这系列有潜力~ 光一个new能看到的东西就已经相当多了,包括GC检查剩余可用空间/触发收集等也在流程中: static void * vm_xmalloc(rb_objspace_t *objspace, size_t size) { void *mem; if ((ssize_t)size < 0) { negative_size_allocation_error("negative allocation size (or too big)"); } if (size == 0) size = 1; #if CALC_EXACT_MALLOC_SIZE size += sizeof(size_t); #endif if ((ruby_gc_stress && !ruby_disable_gc_stress) || (malloc_increase+size) > malloc_limit) { garbage_collect_with_gvl(objspace); } mem = malloc(size); // 尝试分配空间 if (!mem) { // 如果没分配到空间的话, if (garbage_collect_with_gvl(objspace)) { // 就触发一次收集 mem = malloc(size); // 收集过后再试一次分配空间 } if (!mem) { ruby_memerror(); } } malloc_increase += size; #if CALC_EXACT_MALLOC_SIZE objspace->malloc_params.allocated_size += size; objspace->malloc_params.allocations++; ((size_t *)mem)[0] = size; mem = (size_t *)mem + 1; #endif return mem; } |
|
返回顶楼 | |
发表时间:2010-08-18
用windbg配合pdb文件可能更妙一些
|
|
返回顶楼 | |
发表时间:2010-08-19
想法和做法都很好,学习
|
|
返回顶楼 | |
发表时间:2010-08-19
通过调试学习真是个不错的方法。同时也能想到困难重重
|
|
返回顶楼 | |
发表时间:2010-08-19
在windbg里最妙的是可以查看源代码:
|
|
返回顶楼 | |