茱莉亚·伊万斯

Ruby的堆栈结构定义多久改变一次??

你好!我这周正在为我的Ruby分析器做一些研究,所以我想我会在博客上写下搜索。这些就是我今天早上要弄清楚的,所以都是年初的舞台。

基本上,我试图弄清楚我是否可以在编译时在myRuby profiler中定义一组有限的固定Ruby结构布局(RU._2_3_0,Ruyy22Y4Y0,等等)或者如果我需要在运行时使用DWARF获得结构布局。如果你对这个感兴趣,并且对这个帖子有想法,我很乐意在twitter/email上听到它们。

在我开始讨论粗俗的问题之前vm_core.h的频率改变我在乎的方式?“,让我们从小背景开始。

如何从Ruby程序中得到当前的Ruby堆栈??

采样分析器需要回答的主要问题是现在鞋钉是什么?“.

如果在安装了调试符号的Ruby 2.1进程上运行gdb,可以获得

(gdb)p((struct RString*)ruby_._..cfp.iseq.location.label)为$1={heap={len=7378148951706596193,PTR=0x0,aux={capa=0,共享=0 },“=”ASDFASDF,‘000’
          
           }
          

在这种情况下,您会看到“=”ASDFASDF“因为当前函数的名称是ASDFASDF整洁!这很简单。

我特别想说"在Ruby 2.1进程上不过。Ruby 2.2.3怎么样?2.3.0?1.9?2.4.0?2.5.0?这样做吗?ruby_._..cfp.iseq.location.label咒语改变?内部结构布局有变化吗?答案是“是的,我试图弄清楚经常它改变

2种对堆栈进行解码的方法:DWARF和包括头文件

假设我想跑”“ruby_._..cfp.iseq.location.label来自与我运行的Ruby程序分离的进程。为了能够做到这一点,我需要能够从Ruby程序中获得内存(我们将考虑在这里解决),然后将该内存解码成正确的Cstruct。如何确定Ruby程序中的内存如何映射到C结构?2种可能的方式!!

  1. 希望Ruby进程安装和使用DWARF调试符号(这是gdb的工作方式)
  2. 提前根据正确的Ruby头文件编译我的分析器

pyflam使用.#2(根据Python的头文件进行编译),gdb使用.#1(这是内置的DWARF解析器)。这个原因对于py.,方法#2工作得很好,因为它只需要知道头文件的三个不同可能的变体(python 2,Python 3.4,Python 3.6)。

处理DWARF是件痛苦的事情,并不是每个Ruby进程都有调试符号,所以我更喜欢能够使用第二种方法。这个帖子就是我试图弄清楚什么会妨碍我工作的方法!!

我想在本帖中回答的问题

我对两个问题感兴趣:

  • 我需要了解对核心Ruby结构的多少更改?它只是3左右(像Python)还是还有更多??
  • 有没有γ干扰素我需要担心扰乱我的结构布局吗??

ifdefs是怎么回事?好,Ruby解释器中有很多地方,根据一些编译时间值来改变内部结构的布局。

typedef struct rb_._struct{struct list_node vmlt_node;价值自我;RbV-VMyt*vm;rb_execution_context_t*ec;值last_status;/*$?*/*用于cfunc*/struct rb_call_info*call;/*用于加载(true)*/VALUE top_self;值top_wrapper;/*线程控制*/rb_native._id_t._id;#ifdef NON_SCALAR_THREAD_ID rb_._id_string_t._id_string;第二节

我关心的结构

我认为我关心的主要结构是rb_._struct,,RBY-ISEQS-结构,,rb_iseq_location_struct,和rb_iseq_._body.以下是5种不同Ruby版本中结构定义的链接。

红宝石2.1.0

红宝石2.2.0

红宝石2.3.0

红宝石2.4.0

红宝石2.5.0RC1

一些变化

  • 在Ruby 2.2.0中,有一个新的结构list_node vmlt_node开始时rb_._struct.这是介绍的。F11Db2A60.我认为2.2.0是第一个有这种承诺的发行版。需要一个新的头文件。
  • 在Ruby 2.2.0中,有一个新的斯塔克马克斯中的字段RBY-ISEQS-结构结构。需要一个新的头文件。
  • 在Ruby 2.3.0中,大部分内容RBY-ISEQS-结构结构被移入构造rb_iseq_._body*body;;字段。(所以你需要身体部位而不是ISEQ定位)需要更改代码。
  • 在Ruby 2.4.0中,布局rb_iseq_._body再次改变。需要一个新的头文件。
  • 在Ruby 2.5.0中,有一个主要的重构器,其中ruby_._.全局变量替换为ruby_._execution_context_ptr.这个rb_._struct结构也是完全不同的。这种变化发生在837 FD5E4703请求代码更改。

还有更多的变化我还没有找到/编目,我可能会稍后更新这篇文章,但现在我很无聊。

这些变化很大!!

看起来,Ruby结构定义Ruby堆栈的情况与Python中的描述大不相同——而不是只有三个版本需要考虑,我所关心的结构的结构布局会改变每个主要的Ruby版本。(可能也在次要版本中?)我还没查过.我现在看到的两个选项是

  • 使用DWARF(因为这样我就不用担心结构布局的改变,只有那些需要更改代码的人
  • 获取每个次要Ruby版本(2.3.1,2.3.2,2.3.3,2.3.4,等)。我做的这个快速列表看起来好像有……40个小红宝石版本?这个数目很多,但不是无穷大。在Rust中,我可以使用bindgen为所有那些ruby版本生成Rust绑定,就像……将所有版本提交到我的存储库中。这看起来有点像前面的更多工作,但是最好在编译时拥有所有可能的奇怪的结构定义。也许我可以用少于40个版本来逃避。

快说:有Stephen Kell的有趣研究项目叫做liballocs这使得使用DWARF更容易。这里是它生成的示例C文件(gzi.)(来自LIBC)。主要是链接到它,所以我记得以后再回到它。

现在就这些了!我以后会继续看这个。