用 VSCode gdb 去 debug JVM#

以下操作基于 JDK 构建、调试环境 一节的环境。

VSCode gdb attach JVM 进程#

.vscode/launch.json :

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "java-pid",
            "type": "cppdbg",
            "request": "attach",
            "program": "/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug-hsdis/jdk/bin/java",
            "processId": "${command:pickProcess}",
            "miDebuggerPath": "/usr/bin/gdb",
            "osx": {
                "MIMode": "lldb",
            },
            "linux": {
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "text": "handle SIGSEGV print nostop",
                        "description": "Disable stopping on signals handled by the JVM"
                    }
                ],
            },
        }
    ]
}        

更多说明见:GDB JVM FAQ - attach process

VSCode gdb 调试 jstack#

.vscode/launch.json

一开始,我是用这个方法:

        {
            "name": "jstack",
            "type": "cppdbg",
            "request": "launch",
            "program": "/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug/jdk/bin/jstack",
            "args": [
                "204131"
            ],
            "stopAtEntry": false,
            "cwd": "/home/labile/opensource/jdk",
            "environment": [],
            "externalConsole": false,
            "linux": {
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "text": "handle SIGSEGV noprint nostop",
                        "description": "Disable stopping on signals handled by the JVM"
                    },
                ]
            }
        }

native 与 Java 代码混合调试#

后来,我发觉除了 debug native code 外,我还需要 debug java code。于是,就不能用 jstack launcher 命令去使用 jstack 的功能了。就要想法子用 java 命令启动 jstack。于是:

        {
            "name": "java-jstack",
            "type": "cppdbg",
            "request": "launch",
            "program": "/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug/jdk/bin//java",
            "args": [
                "-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=y", "-Dapplication.home=/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug/jdk", "-Dsun.jvm.hotspot.debugger.useProcDebugger", "-Djdk.module.main=jdk.jcmd", "-Dsun.java.command=jdk.jcmd/sun.tools.jstack.JStack",
                "-XX:-BackgroundCompilation", "-Xint", "-XX:CompileCommand=break,jdk.internal.loader.NativeLibraries::newInstance",
                "sun.tools.jstack.JStack",  "24586"
            ],
            "stopAtEntry": false,
            "cwd": "/home/labile/opensource/jdk",
            "environment": [],
            "externalConsole": false,
            "linux": {
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "text": "handle SIGSEGV noprint nostop",
                        "description": "Disable stopping on signals handled by the JVM"
                    },
                ]
            }
        }

其中, 24586 是一个预先启动好的 java 进程的 pid,等待被 jstack dump threads。 对应的原始命令应为:

./build/linux-x86_64-server-slowdebug/jdk/bin/java -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=y -Dapplication.home=/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug/jdk -Dsun.jvm.hotspot.debugger.useProcDebugger -Djdk.module.main=jdk.jcmd -Dsun.java.command=jdk.jcmd/sun.tools.jstack.JStack sun.tools.jstack.JStack  24586

设置好 native 的 breakpoint,开始调试后,JVM 会挂起以等待 debugger 连接(因suspend=y)。

/home/labile/opensource/jdk/build/linux-x86_64-server-slowdebug/jdk/bin/jdb -attach 8000

jdb 连接上后,就可以 set java breakpoint 了。需要执行 contrun 命令, Java 层面才可以继续运行。

设置 breakpoint 的一些例子:

stop at sun.tools.attach.VirtualMachineImpl:60

stop at sun.tools.attach.VirtualMachineImpl:226

stop at sun.tools.attach.VirtualMachineImpl:314

stop at jdk.internal.loader.NativeLibraries:120