注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

熊猫正正的博客

熊猫正正的天空

 
 
 

日志

 
 

安卓Hacking:Part 5:使用JDB调试Java应用  

2015-07-26 14:42:36|  分类: Android开发与逆 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

本期将为大家演示如何使用JDB命令行工具调试Java应用,尽管本文并不会涉及Android的相关内容,但却是理解本系列下一期“寻找可调试的安卓应用”前提。

什么是JDB

JDB是一个简单的Java命令行调试器,包含在JDK中。

我们在本文中将会使用一台Ubuntu主机,我们可以在/usr/bin中找到JDB:

         #cd /usr/bin

         #ls | grep jdb

提示:如果你使用的是Windows,可以在Java目录下的bin目录中找到JDB,本文的示例主要在Ubuntu下完成,但即使在windows中相关的技术也基本是相同的。

简介

本文将会接合一个实例来理解如何用JDB命令调试Java程序,而不是直接去看JDB的用法。

以下是本文用作示例的代码:

文件名:Debug.java

编译生成的Class文件:Debug.class

t016b0b4f66c5dc9c04.png

这段代码片段中,Debug类的main方法调用了该类中的其他两个方法,编译后执行,会产生以下输出,如图:

t012e6c2f8c696a4609.png

我们使用了-g选项来编译程序,编译器会在类文件中生成一些调试信息。

运行JDB

要调试Java程序,我们需要一条JDB到JVM的通信信道,因为我们的Java程序实际上是运行在JVM(java虚拟机)中的

如下所示,有多种连接JDB和JVM的方法。

方法1

使用这个方法,我们直接使用JDB来加载类文件,JDB会自动创建一个JAVA虚拟机,并建立连接。

t01256b238d3aa59b16.png

图中的Debug代表编译后生成的类文件

方法2

使用这种方法,我们先使用以下命令启动一个Java虚拟机,Java虚拟机会监听54321端口。

java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=54321 Debug

t01c053b31783c3864d.png

然后使用如下命令启动JDB连接到JVM。

jdb -attach 54321

t01017d1c36d67a9867.png

这种方法也可以用于远程调试,在下一期中,我们会使用这种方法来远程调试Android应用。本文中会使用第一种方法。

开始调试

我们现在开始用第一种方法来调试示例程序,但我们需要执行一条run命令来让JDB启动Java虚拟机,如下图:

t01ca4c427ef5533f32.png

图中显示,启动了Java虚拟机后,程序立刻执行完成并退出了。

为了中断程序执行以便手工单步调试,我们需要在程序运行之前设置断点。

我们可以用”stop in”命令在方法开始的地方设置断点,如下图:

http://p0.qhimg.com/t01332b8f0fd6840fcb.png

值得注意的是,设置断点的时候,除了指定类和方法名之外,还要指定参数类型。

我们已经在Debug类中的main方法上设置了断点。

现在我们就能运行程序来触发断点,这里一样使用之前提到的run命令。

t0160495479188aa708.png

触发断点后,JDB会自动显示将要执行的下一行代码:

System.out.println(“We are in main method”);

可以使用“list“命令来查看当前的上下文代码

t01170b6586f79afcc1.png

使用“clear“命令查看设置的所有断点:

t01a6150709707963c9.png

如图,clear命令显示出来我们设置断点及位置

使用”threadgroups”命令查看所有的线程组。

t01bf0422a433120ac7.png

如图,当前有两个线程组:“system“和”main“

使用”threads”查看所有线程:

t01d38ff070595fa5e9.png

如上图,我们当前的system线程组中有三个线程,而main线程组中有一个线程,这就是我们要调试的。

使用”classes”命令查看当前Java虚拟机所加载的类的信息:

t016fad9c07f962414c.png

上图中显示了当前Java虚拟机所加载的类(为节省空间,截短了输出)

要查看特定类的更加详细的信息,可以使用以下命令:

 >class <classname>

下图显示了Debug类的详细信息:

t013842c84bb15053e3.png

同样,我们也能查看其它类的详细信息,例如下图就显示了 java.io.DatqaInputStream类的详细信息:

t01e9e311a67830f214.png

使用”methods <classname>”命令查看所加载的方法:

t0171b63349333d9ac3.png

以上介绍了以下常用的重要命令,现在我们将深入程序的执行流程,看怎样用JDB来帮助我们调试程序。

我们可以使用”next”命令执行下一行代码:

t01f3587a4100316fa8.png

执行完当前代码后,JDB会自动显示下一行代码:调用test方法。

这里,我们再执行”next”命令后,会执行完test方法并中断到下一行代码:passCheck:

t01a3472b41c083e3b3.png

现在,如果我们想进入passCheck方法进行调试,就应该使用”step”命令,而不再是”next”。

我重启了程序,在test方法处输入了step命令:

t01a7193c568bedaad9.png

现在,输入”next”命令继续运行下一条代码:

t01bda35450cce8c0ca.png

现在,如果我们因为某些原因希望直接离开该方法,而不是运行余下的代码,我们可以使用”step up”命令。

http://p1.qhimg.com/t01595e01a53696b280.png

当前代码已经离开test方法,回到main方法,等待执行下一条。

下面几行会毕竟有趣,我们将会学到如何查看变量中储存的数据,在此之前,我们先介绍一天更有趣的命令:“where”。

“where”命令会打印显示当前的调用栈。我们先在main方法中运行该命令,然后在另一个方法中运行同样的命令:

t015c89e3a013121b59.png

如图,当前程序正在main方法中,

现在使用”step”命令进入方法,并检查调用栈:

t01c62695cce7eec5f5.png

t0134e8c41e450c4891.png

如上图,程序当前正在”Debug.passCheck”中运行,而”Debug.passCheck”又是被“Debug.main”调用的

假如我现在对passCheck这个方法比较干兴趣,想看看该方法的局部变量中有不有一些敏感信息,我们可以使用”locals”命令查看所有的局部变量。(如果程序没有使用-g选项编译,该命令无效).

t01b891d8438e1b9fcf.png

如图显示,该方法接收了一个main方法传入的密码变量,因为参数还没有被赋值给局部变量,所有上图只显示了参数而没有局部变量,我们先执行下一行代码再查看局部变量”password”。

可以使用”print”命令打印出指定变量的内容:

t01bebd40af32aabe20.png

总结

本文简介介绍了JDB,以及几个常用的JDB命令的用法。

相关链接

http://docs.oracle.com/javase/7/docs/technotes/tools/windows/jdb.html

  评论这张
 
阅读(67)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017