使用jdb和gdb同时调试java native code

来源:互联网 发布:ubuntu无法联网 编辑:程序博客网 时间:2024/05/22 02:33

主要流程:

1.使用jdb启动生成的java字节码或jar包;

2.java源码中适当的位置设置断点,如main方法;

3.使用run指令,使代码跑起来。(jdb命令只是进入调试环境,jvm还没有运行起来,当然我们的代码也没有运行起来,run指令之后,才有创建一个jvm,在进程列表中会发现多出一个java进程。)

4.另起一个终端,使用查询新生成的java进程的进程id

5.使用gdb命令附着到上述java进程。

6.C源码中适当的位置设置断点。

至此,两个调试都挂在了同一个jvm上。需要注意,只有两个调试器同时允许程序执行是,程序才会继续运行。


HelloWorld为例说明:

第一至第三步如下:

$jdb HelloWorld <= 第一步正在初始化jdb...>stop in HelloWorld.main<= 第二步,设置适当的断点正在延迟断点HelloWorld.main。将在加载类后设置。>run <= 第三步, run起来运行HelloWorld设置未捕获的java.lang.Throwable设置延迟的未捕获的java.lang.Throwable>VM已启动:设置延迟的断点HelloWorld.main断点命中:"线程=main",HelloWorld.main(), 行=4bci=04 HelloWorld hw = new HelloWorld();main[1]
然后另起一个终端,继续第四步至第六步

$ps -e | grep java32160pts/24 00:00:00 java$sudo gdb -p 32160GNUgdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1Copyright(C) 2014 Free Software Foundation, Inc.//××××此处有打断输出,省略Loadedsymbols for /usr/lib/jvm/jdk1.7.0_07/jre/lib/i386/libdt_socket.soReadingsymbols from/home/luyao/java/jni/HelloWorld/libHelloWorld.so...done.Loadedsymbols for /home/luyao/java/jni/HelloWorld/libHelloWorld.so <= 可以看到已经加载我们的库了0xb775f428in __kernel_vsyscall ()(gdb)break HelloWorld.c:Java_HelloWorld_print <=设置一个断点,在native的print函数前Breakpoint1 at 0xb682d58d: file HelloWorld.c, line 8.(gdb)c<= gdb释放阻塞。还需jdb调用cont命令,程序才会继续执行。Continuing.

回到第一个终端,执行cont命令

第一个终端里:

main[1]contInJava, before> native
第二个终端里:

(gdb)cContinuing.[Switchingto Thread 0xb68edb40 (LWP 32164)]Breakpoint1, Java_HelloWorld_print (jenv=0xb6707d28, jobj=0xb68ed010)atHelloWorld.c:88 inti = 0; <= Nice! 程序已经断在gdb里了。(gdb)//然后就可以任意发挥了。

几个问题:

1)在上述C代码中,有一句注释掉的代码fflush(stdout);如果没有该行代码,在jdb调试器中,输出会发生乱序(native函数中的输出被延迟甚至漏掉)。单独挂gdb调试器时,没有这种问题。估计跟JVM中实现native层标准输出设备缓存的方法有关。等进一步研究JVM的实习后再来关注这个问题。

2)由于java对线程id描述的方式不同,目前无法确定从java代码调用native代码时是否发生线程切换,很大程度上感觉不会发生线程切换。在《Insidethe Java VirtualMachine》一书中只讲到从java调用native时只发生了线程栈的切换,即native代码有独立的栈,(这类似与用户态栈和内核态栈的区别)。没有线程的切换。但是这本书的编写时间较早,2000年,当时java应该还是1.3或者1.4,不知道在1.7,或者说在安卓的Dalvik虚拟机中的实现是否有不同,需进一步研究。

3)一个很困惑的问题。在启动gdb时,使用的时root权限,如果不用root权限,会报错,如下:

Attachingto process 7093Couldnot attach to process. If your uid matches the uid of the targetprocess,check the setting of /proc/sys/kernel/yama/ptrace_scope, or tryagainas the root user. For more details, see/etc/sysctl.d/10-ptrace.confptrace:不允许的操作.

不明白的是,非root下,我的uid肯定是一致的,即目标进程javauid也是当前用户。而使用root权限启动gdb时,gdbuid显然与目标进程javauid不一致了

$ps -aux | grep javaluyao 7093 0.0 0.6 688660 13812 pts/24 tl+ 00:14 0:00/usr/lib/jvm/jdk1.7.0_07/jre/bin/java -Xdebug-Xrunjdwp:transport=dt_socket,address=luyao-K40IN:55455,suspend=yHelloWorldluyao 8765 0.0 0.0 6116 824 pts/7 S+ 00:20 0:00 grep--color=auto javaluyao@luyao-K40IN:~/java/jni/HelloWorld$ps -aux | grep gdbroot 8611 0.0 0.0 8312 2036 pts/12 S+ 00:19 0:00 sudo gdb-p 7093root 8612 0.8 1.4 40216 30012 pts/12 S+ 00:19 0:00 gdb -p7093luyao 8857 0.0 0.0 6116 824 pts/7 S+ 00:20 0:00 grep--color=auto gdb
查看上述错误提示中提到的文档如下:

$cat /etc/sysctl.d/10-ptrace.conf#The PTRACE system is used for debugging. With it, a single userprocess#can attach to any other dumpable process owned by the same user. Inthe#case of malicious software, it is possible to use PTRACE to access#credentials that exist in memory (re-using existing SSH connections,#extracting GPG agent information, etc).##A PTRACE scope of "0" is the more permissive mode. A scopeof "1" limits#PTRACE only to direct child processes (e.g. "gdbname-of-program" and#"strace -f name-of-program" work, but gdb's "attach"and "strace -fp $PID"#do not). The PTRACE scope is ignored when a user has CAP_SYS_PTRACE,so#"sudo strace -fp $PID" will work as before. For moredetails see:#https://wiki.ubuntu.com/SecurityTeam/Roadmap/KernelHardening#ptrace##For applications launching crash handlers that need PTRACE,exceptions can#be registered by the debugee by declaring in the segfault handler#specifically which process will be using PTRACE on the debugee:# prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0);##In general, PTRACE is not needed for the average running Ubuntusystem.#To that end, the default is to set the PTRACE scope to "1". This value#may not be appropriate for developers or servers with only adminaccounts.kernel.yama.ptrace_scope= 1$cat /proc/sys/kernel//yama/ptrace_scope1

好吧,应该是ubuntu自身的安全机制导致,/proc/sys/kernel//yama/ptrace_scope中的值改为0就可以了。





0 0