`
liugang594
  • 浏览: 977076 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Eclipse调试框架的学习与理解一

阅读更多

提供一个可视化的调试器对于调试程序是很有益处的。Eclipse里的java调试器做的已经非常完美了。

只要努力,我们也能得到一个那么完美(理论上)的UI调试器。在Eclipse里,定义了很多针对调试器的扩展点供我们扩展,让我们可以轻松的利用Eclipse已有的机制来实现自己的UI调试器,例如:运行堆栈的显示、变量值的显示、追加和删除断点,以及单步跟踪等等。

但是首先我们需要清楚两件事:

1、Eclipse并没有提供任何针对调试器的默认实现。

2、Eclipse本身并不支持调试,这需要语言工具或引擎的支持。

Eclipse只是提供了一个共通的UI界面来操作和显示结果。这点我们是需要首先清楚。

 

一、运行堆栈的结构

所谓的运行堆栈,可以看下图:

图一

图一

调试Java的时候,我们总是可以看到一个类似于这样的图,其中左边是一个树状结构,选择其中的任一stackFrame(稍后讲)在右边的Variables视图就会看到当前这个stachFrame中所有变量的值。

 

Eclipse里,这个堆栈结构如下:

图二

图二

堆本的最顶层的是Launch对象,最低层的是IValue对象(实际上也不能这么讲,IValue对象与IVariable对象是循环套用的,所以会形成类似于JavaValue的一种树结构)。其中在左边结构里只会显示到IStackFrame这一级,剩下两级在右边的Variables视图里显示。

 

堆栈中的每个对象都应该定义成一个DebugElement对象,也就是实现的时候需要直接或间接的继承这个对象,它定义了一些通用的方法,例如发出事件,取得launch或都是取得模型标识。在后面我们会讲到这些都很有用。

 

怎么得到这个栈

在继续之前,我们先介绍一下这个堆栈是怎么来的。

 

在介绍Launch框架的那篇文章里,我提到过:launch对象可以加两种类型的对象,一个是IDebugTarget对象;另一个是IProcess对象。我也提到了:如果是在“run”模式下,我们选择追加IProcess对象;如果是在“debug”模式下,我们应该追加IDebugTarget对象。

 

一旦我们追加了一个IDebugTarget对象(需要自己继承实现),里面就会有一个getThreads()方法用来返回所有的当前这个target的所有IThread对象;在IThread对象里有一个返回所有这个Thread对象下的StackFrame对象的方法getStackFrames()。以此类推,我们就可以得到一个完整的堆栈。

 

 

怎么显示这个栈 

事实上,我们不用管怎么显示这个栈,只要你在实现类里定义好了那些get**s()方法,那么Eclipse框架会自动调用这些方法,然后得到一棵堆栈树。

我觉得这里的关键是:怎么决定这个树的具体显示内容。我说的这个内容,不是指对于某个结果——结点上的label显示成什么,这个也是很简单的,每个类中都需要实现的一个方法就是:getName()。结点的label值就是显示这个方法的返回值。

 

除此之外,还有一个扩展点可以用来提供树上各类型结点的显示方式,例如图标、文本等等。这个扩展点是:

org.eclipse.debug.ui.debugModelPresentations

 

我想说的是:怎么决定树上有多少个什么样的结点。也就是我们怎么给出每个对象里的get**s()方法,例如上面的getThreads()方法和getStackFrames()方法。我们需要知道的是,这个不是Eclipse能决定的,而是要由你当前的应用和你的后台的解释结果来决定。

二、单步跟踪的支持

我们回到图一,我们看一下我们熟悉(如果你在Eclipse调试过Java)的那些跟踪按钮:

 

图三图三

看红色圈住的部分,有运行、暂停、停止和用来单步调试的单步进入、跳过和跳出。

 

这些扭键缺省已经和键盘绑定了,例如扭F5就是单独进入、F8就是运行到下个断点等等。我们需要给出的就是当前哪些键可用、和可用的时候如何执行。

 

实现上我们的每层的实现类里都会有针对上面每个按钮的方法需要实现,我们以StackFrame层的单步进入为例,需要实现以下两个方法:

public boolean canStepInto() 返回false表示单步不可用;返回true表示单步可用 public void stepInto() throws DebugException 在单步可用的情况下,执行单步命令时调用此方法。通常是发送出一个单步进入命令(后台支持),得到一个返回值。然后根据此返回值来决定余下事项。

 

其实各事件同此类似。实际这里还是一样,需要自己去实现各步的逻辑。

事实上,我们不用管怎么显示这个栈,只要你在实现类里定义好了那些get**s()方法,那么Eclipse框架会自动调用这些方法,然后得到一棵堆栈树。

我觉得这里的关键是:怎么决定这个树的具体显示内容。我说的这个内容,不是指对于某个结果——结点上的label显示成什么,这个也是很简单的,每个类中都需要实现的一个方法就是:getName()。结点的label值就是显示这个方法的返回值。

 

除此之外,还有一个扩展点可以用来提供树上各类型结点的显示方式,例如图标、文本等等。这个扩展点是:

org.eclipse.debug.ui.debugModelPresentations

 

我想说的是:怎么决定树上有多少个什么样的结点。也就是我们怎么给出每个对象里的get**s()方法,例如上面的getThreads()方法和getStackFrames()方法。我们需要知道的是,这个不是Eclipse能决定的,而是要由你当前的应用和你的后台的解释结果来决定。

  • 描述: 图一
  • 大小: 8.9 KB
  • 描述: 图二
  • 大小: 7.8 KB
  • 描述: 图三
  • 大小: 9.6 KB
分享到:
评论
3 楼 zxjlwt 2015-08-10  
学习了。

http://surenpi.com
2 楼 imu2008 2014-05-08  
好文,谢谢分享~楼主好样的
1 楼 luoww1 2013-12-30  
能给个具体的工程嘛?这样看,自己还是不会实现,有点晕乎乎的。。。谢谢。。。

相关推荐

Global site tag (gtag.js) - Google Analytics