HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

Ruby 调试器一览

  • 2008-05-04
  • 本文字数:4114 字

    阅读完需:约 13 分钟

有一个关于 Ruby 的误解在 Ruby 社区内外广泛流传,即:Ruby 没有调试器。有些人说这是 Ruby 的一个问题。其他人则试图将所谓的缺少调试工具解释为智慧之举和良好风格。这些观点都是误解。Ruby 明明是有调试工具的——实际上有很多。让我们来看一看这些现有的工具,包括调试GUI、调试器实现和各种Ruby 实现中的调试支持。

什么是调试器?

首先,让我们搞清楚“调试器”实际上涉及了哪些东西?

调试的GUI 和接口

当然了,交互式调试器最重要的部分——至少对于用户来说——是用户接口。用户可以使用Ruby 调试器的命令行接口,例如和Ruby 标准库一起提供的Rubinius 调试器。它显然可以用来调试代码,只不过设置断点或查看运行状态会比较麻烦。

IDE 虽然有时在 Ruby 世界中不太受推崇,但它无疑令调试变得更简单了——毕竟,IDE 就是集成开发环境。集成对于调试来说很重要,而 IDE 正是把代码编辑和调试工具整合在一起了。你可以在源代码编辑器中直接管理断点——而不用记下代码的行号,进入命令行调试器中,然后手工设置断点。在 IDE 中,诸如基于行的单步调试之类的功能也更加实用,可以正确的找到所打开的文件的栈结构和所在行。

带有嵌入式脚本支持的 IDE 还允许对脚本进行调试。例如 ,Eclipse 的 EclipseMonkey 扩展支持用 JRuby 写成的脚本。由于这些脚本和 Eclipse IDE 都运行在同一个 JVM 上,由此调试器实例便可以被访问和控制了。

调试器协议还是连接到后端

把像 IDE 这样的调试器用户接口和调试器后端连接起来的一个简单方法是:使用命令行接口,并通过标准的 stdin/stdout/stderr 流来进行控制。这样,编辑器或者 IDE 的调试器支持就可以控制调试器,同时也让用户管理断点变得更加方便了。

另外一个方法是采用线路(wire)协议,它允许通过某种模式的进程通讯(IPC),现在一般是通过 TCP/IP 来连接到调试器。基于网络的协议还允许 GUI 和调试器分布在不同的机器上,也就是说可以使用本地的用户接口来对远程机器进行调试。

基于文本的或者至少基于文档的简单调试协议也允许使用任何语言来编写调试进程脚本。实际上,连接到 Ruby 调试器和打开 telnet 一样简单。 debug-commons DBGp 命令的协议就是由单行字符串和 XML 应答构成的。

VM 支持还是调试后端

为了支持断点等功能,语言运行时至少得提供监视和控制执行的支持。可以简单地像 Ruby 的跟踪(tracing)功能一样:在一行 Ruby 代码执行之前,Ruby 会调用一个叫做 set_trace_func 的回调函数。传过去的参数包括即将执行的那行代码的环境信息,比如行号,所属文件的名字和所属的类等等。这些信息就足以实现断点功能了:在一个断点注册表里面检查文件名和行号,看看是否被注册了。

当遇到一个断点时,执行就被挂起,只要不从回调中返回即可——Ruby 运行时只能在回调返回后才能继续运行。基于这些,就可以实现单步调试等功能了。

虽然使用跟踪功能可以实现一个调试器,但是在执行每一行之前都要先执行跟踪回调,显然太慢了。理想地解决方案是仅在执行有断点的行时才引发断点处理。运行时可以通过修改已加载的代码来实现此功能——不论是 AST 还是操作码(opcodes)——在有断点的行上。有些语言的运行时提供了内建的调试支持,与执行机制整合在一起。Java 和.NET 的二进制代码都提供调试信息(即从文件和行到字节代码位置一个映射),让内建的调试支持能使用这些信息来进行调试。在 Java 世界中,例如,JVM 配合 JVM 工具接口(JVM TI)一起实现了这个功能以及用来连接到 JVM 的 Java 调试线路协议(JDWP)。

还有一个方法是 Rubinius 调试器所使用的,它使用可访问和可修改的 Ruby 代码中的操作码(Rubinius 把 Ruby 源代码先编译成操作码然后再执行)。

通过把一个一般操作码替换成一个特殊操作码来设置一个断点,而这个特殊操作码则用来挂起当前进程并通知调试堆栈中的高层。 通过设置大量的基础体系和管理数据结构以供语言来访问,语言本身就可以用来建立调试机制。

各种 Ruby 实现的调试器和 IDE 支持

有了以上基础,再让我们来看一看现有的调试器。从用得最广、支持得也最多的 Matz 的 Ruby 实现(MRI)开始。之后让我们再看一看 JRuby、Rubinius 以及 IronRuby 的现状——看看这些 Ruby 实现的工具支持,还有它们与 MRI 以及其工具支持和性能的区别。

Ruby/MRI

调试后端

Ruby 1.8.x,也就是 MRI,是官方的 Ruby 解释器,是用 C 语言实现的。我们最常见的调试器就是针对它的。这个跟踪调试器是配合它的 Ruby 版本以及标准库一起使用的。另外还有更快的实现。比如 ruby-debug ,它是使用本地扩展来实现的。

还有一个选择是随 SapphireSteel 的 Ruby in Steel IDE 提供的: Cylon debugger 。它也是通过本地代码来实现功能,使用 Ruby 钩子来获得诸如方法调用等事件通知而完成的。 SapphireSteel 的标准测试表明,Cylon 调试器比用 Ruby 写的调试器快得多,也比 ruby-debug 要快。

GUI

许多 Ruby IDE 提供都调试功能。基于 Eclipse 的 RDT (现在是 Aptana 和 RadRails 的一部分)在很久以前就开始提供调试支持了,一开始是连接到基于 Ruby 的跟踪调试器上,后来转而支持 ruby-debug。RDT 的调试协议被分解到了debug-commons 项目中,该项目用于Netbeans Ruby,以提供调试功能。在Ruby IDE 世界中还有一个古老的 ActiveState’s Komodo ,它是基于 DBGp 协议的。另外一个能与 Eclipse 的调试器 GUI 抗衡的 IDE 是 Eclipse DLTK Ruby ,它也是 CodeGear 3dRail 的基础。DLTK 也使用 DBGp 来连接到后端。SapphireSteel 的 Ruby in Steel 包含了一个调试器 GUI,它允许使用 Cylon 调试器来进行快速调试。

这些 IDE 的功能虽不尽相同,但至少都提供了断点、单步调试和变量查看功能。 注意:尽管 IntelliJ 在它们的 IDE 中提供了编辑 Ruby 功能,但在 IntelliJ Ruby 的蓝图中调试支持是作为一个未来项目的

JRuby

调试后端

基于跟踪的常规 Ruby 调试器也能用于 JRuby。除此之外,更快的版本是 jruby-debug (也属于 debug-commons 项目),它是用 Java 而不是 Ruby 语言来实现的,从而减少了每行的执行开销。

还有一个新的来自SapphireSteel 的JRuby 调试后端。刚才提到了这个公司,他们还做了MRI 的快速Cylon 调试器。和jruby-debug 不同,SapphireSteel 的解决方案同时使用Java 和本地代码(通过JNI)实现了调试器后端。

GUI

支持 set_trace_func 调试的 Ruby IDE 也能用于 JRuby。另外 Netbeans 和 Apatana 也提供了 jruby-debug 支持。对于那些不止把 JRuby 当作普通 Ruby 运行时、还要用 Ruby 调用的 Java 类的人来说,显然很需要支持跨语言的调试。当 Ruby 核调用 Java 核时,最好同时显示 Ruby 和 Java 的堆栈和变量。

SapphireSteel IDE 使用他们自己实现的后端和通讯协议,而不是基于 ruby-debug 或者 jruby-debug,这意味着它是被绑定在 Ruby in Steel IDE 中的。

Rubinius

调试后端

毫无疑问, Rubinius 取得了长足的进步——特别是在过去的几个月中,它的调试支持从没有一跃成为 Ruby 界中的佼佼者(根据调试性能表现)。全速Ruby 调试器允许伴随调试运行一个Ruby 程序,而没有其他方案中的那种性能消耗,正如前面解释的或者链接新闻中所述的一般。

Rubinius 的设计决定了其调试功能的强大,使得在运行时常规的 Ruby 核可以使用大量的 VM 基础结构和原数据。操作码和已加载 Ruby 核的解析树(ParseTree),以及堆栈踪迹(stacktrace)都是可访问的。内部追查的能力更强了,例如使用SendSites。 SendSites 指出了消息传递到哪(“方法调用”),它还能链接到方法上。这样就可以获得在运行时中已加载代码的配置,但也起到了代码分析和覆盖工具的作用。每发一条信息,Sendsite 的计数器就会增加;由于这个信息也能用于 Ruby 代码,所以写一个简单的代码分析工具或者至少是代码覆盖工具就只是几行代码的事。

GUI

现在 Rubinius 调试器的用户接口还是命令行界面,它可以管理断点、单步调试,也能查看正在运行的 Ruby 核的操作码或者它们的源文件。 sexp [method]是一个实用的命令,它返回[method]的 AST 的 ParseTree 符号表达式(s-expr,忽略参数的情况下把当前方法的 AST 表示为 ParseTree 符号表达式)。这是十分有用的信息,特别是对于那些使用元编程(metaprogramming)的代码——运行时所生成的代码显然不含源代码。能够看到那些生成的被加载的代码显然对于调试那些元编程的代码有帮助。另外,能够看到符号表达式也比试图去猜测生成的代码是干什么的更进了一步,也更加方便了——通过采用基于 ParseTree 的工具,比如 Ruby2Ruby ,它是一个接收符号表达式并格式化后返回给 Ruby 源代码的工具。

直到本文发布之日为止,Rubinius 和调试器 GUI 的连接还不没有出现。不过,由于现在调试协议实现已经可以工作了,这个状况即将发生改变。从实现调试支持的速度来判断,对调试器 GUI 的支持也不远了(调试协议的实现是调试器实现中的一个简单部分)。一旦它支持了 debug-commons 或者 DBGp 协议,采用这些协议的 IDE 就能够用于 Rubinius 了。

IronRuby

IronRuby 生成的是 MS IL 代码,它目标是.NET 平台。它使用 DLR,这个系统收集各种语言的公共功能,比如表达式树等产生的 MS IL。

调试后端

DLR 生成 .NET MS IL,也生成 MS IL 调试信息。这意味着 IronRuby 既可以使用.NET 调试工具,也可以使用 Visual Studio 调试器的 GUI。

GUI

你可以使用 Visual Studio,而 Ruby 的 SapphireSteel Ruby in Steel IDE——也是基于 Visual Studio 的 IDE——也支持 IronRuby 开发。在以后的版本中肯定会增加调试功能。

其他问题

这篇文章介绍了一部分现有的 Ruby 调试工具,而不是全部。还有别的 IDE 的 GUI 和后端,比如 ActiveState 的 Komodo,还有一些不同程度地支持 Ruby 实现或调试功能的后端。这里没有提到 XRuby 这个 Ruby 实现,它也支持调试。同样也没有提到Ruby 1.9,尽管已经官方发行了,但它还在紧锣密鼓的开发中。由于Ruby 1.9 的VM 也使用字节码解释器,那么很可能会采用类似Rubinius 的方案。

最后是免责声明:现在,其他Ruby 实现和调试支持正在飞快地开发着。所以,请把此文看作是对Ruby 调试支持的概述——实际上,在你阅读时,各种Ruby 实现的调试支持和工具很可能已经有了变化和改进。

查看原文: A Look at Ruby Debuggers

2008-05-04 07:556543
用户头像

发布了 33 篇内容, 共 50737 次阅读, 收获喜欢 0 次。

关注

评论

发布
暂无评论
发现更多内容

如何通过机器学习赋能智能研发协作?

LigaAI

人工智能 智能化 LigaAI 研发协作平台 亚马逊云科技

软件测试 | 测试开发 | 工作多年,技术认知不足,个人成长慢,职业发展迷茫,该怎么办?

测吧(北京)科技有限公司

测试

干啥啥都行,这次又拿了第一名!

青藤云安全

网络安全 主机安全 青藤云安全

固定QPS异步任务功能再探

FunTester

Vue.nextTick核心原理

yyds2026

Vue

对比四大智能合约语言:Solidity 、Rust 、 Vyper 和 Move

One Block Community

区块链 程序员 编程语言 Solidity Move

Spark+ignite实现海量数据低成本高性能OLAP

张磊

大数据 spark 分布式数据库 Ignite 内存计算

文盘Rust -- 起手式,CLI程序

TiDB 社区干货传送门

开发语言

记一次TiDB数据库报错的处理过程

TiDB 社区干货传送门

管理与运维

CSS写一个圣诞树Chrome浏览器小插件

肥晨

11月月更 css写圣诞树 Chrome插件

用低代码平台搭建低代码平台

iofod jude

佛萨奇1.0 2.0矩阵公排项目系统开发详情

开发微hkkf5566

武汉web前端培训学习前景如何

小谷哥

我偷偷学了这5个命令,打印Linux环境变量那叫一个“丝滑”!

wljslmz

Linux 运维 环境变量 11月月更

使用Online unsafe recovery恢复v6.2同城应急集群

TiDB 社区干货传送门

实践案例 集群管理 管理与运维 数据库架构设计 6.x 实践

自学前端达到什么水平才能找到工作,来看这套前端学习路线图

千锋IT教育

大专学历通过大数据培训好找工作吗?

小谷哥

破局 NFT 困境:实用型 NFT 是什么?

TinTinLand

区块链 NFT 元宇宙 web3

学历通过大数据培训学习合适吗?

小谷哥

4步消除漏洞积压

SEAL安全

漏洞修复 软件供应链安全 漏洞管理 11月月更

在web前端学习中如何学习知识点

小谷哥

GPU服务器到底有什么作用?

Finovy Cloud

云渲染 GPU渲染 云渲染平台

新能源锂电池极片制造设备如何实现故障智能诊断?

PreMaint

智能诊断 故障诊断 新能源 设备健康管理

COSCon'22 第七届中国开源年会圆满落幕

腾源会

开源

java培训学习后怎么样

小谷哥

Etcd API 未授权访问漏洞修复

TiDB 社区干货传送门

监控 实践案例 故障排查/诊断

TiDB上云之TiDB Operator

TiDB 社区干货传送门

集群管理 TiDB 底层架构 管理与运维 数据库架构设计

文盘Rust -- 把程序作为守护进程启动

TiDB 社区干货传送门

开发语言

看直播,领报告 |《勒索软件的认识与防御指南》最新发布!

青藤云安全

网络安全 勒索病毒 主机安全 勒索 青藤云安全

解读Vue3模板编译优化

yyds2026

Vue

基于OpenHarmony L2设备,如何用IoTDeviceSDKTiny对接华为云

华为云开发者联盟

云计算 华为云 企业号十月 PK 榜

Ruby调试器一览_Ruby_Werner Schuster_InfoQ精选文章