正确的使用Ruby调试器,可以帮助我们调试代码。我们可以简单的像打开telnet一样的连接到Ruby调试器。它会调用一个叫做set_trace_func的回调函数。

许多开发人员都认为Ruby调试器是不存在的。这实际上是一个错误的观念。那么Ruby调试器到底起到一个什么样的作用,下面我们将会为大家做一个详细的解读。有些人说这是Ruby的一个问题。其他人则试图将所谓的缺少调试工具解释为智慧之举和良好风格。#t#

Ruby调试器可以用来调试代码(ruby 调试)  Ruby调试器 第1张

这些观点都是误解。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调试器可以用来调试代码(ruby 调试)

发表评论

您需要后才能发表评论