【问题标题】:How to Debug Java -JNI using GDB on linux ?如何在 Linux 上使用 GDB 调试 Java -JNI?
【发布时间】:2026-02-01 18:35:02
【问题描述】:
任何人都可以指导如何使用 GDB 调试器在 Linux 上调试 JNI 代码(如果可能,请建议其他选项)。
-My JNI project when running on Linux is leading to a JVM crash.
-The CPP code has been compiled into .so files.
-I run the project like this : *java xyz.jar -commandline_args_to_project*.
我安装了 Gdb,但不知道如何使用它调试项目。
我还必须使用 -g 选项 t 调试 .so 文件来编译 .cpp 文件吗?
【问题讨论】:
标签:
java
linux
gdb
java-native-interface
shared-libraries
【解决方案1】:
- 启动您的 java 应用程序
- 使用 top、ps、... 查找 pid
- 用这个 pid 启动 gdb
- 附上您的程序代码
- 像往常一样使用 gdb 进行调试
这个博客post 解释了整个事情。
【讨论】:
-
:我在link 找到了另一种方法。通过这种方式,我能够从 GDB 内部调试启动我的项目,因此不需要切换不同的 shell。
【解决方案2】:
我发现以下方式非常有趣。通过将下面的文件链接到您要调试的 jni 库,当动态链接器加载该库时,由于 gcc 构造函数属性,它会自动为当前 jvm 启动一个 gdbserver。
只需从命令行或 Eclipse 中使用远程 gdb,即可轻松调试。我只设置如果我在调试模式下构建,我暂时还没有实现检测 jvm 是否在调试中启动,目前只允许这样做,但可能很容易。
我只是从这里的文章中改编了这个概念:http://www.codeproject.com/Articles/33249/Debugging-C-Code-from-Java-Application
#ifndef NDEBUG // If we are debugging
#include <stdlib.h>
#include <iostream>
#include <sstream>
namespace debugger {
static int gdb_process_pid = 0;
/**
* \brief We create a gdb server on library load by dynamic linker, to be able to debug the library when java begins accessing it.
* Breakpoint have naturally to be set.
*/
__attribute__((constructor))
static void exec_gdb() {
// Create child process for running GDB debugger
int pid = fork();
if (pid < 0) {
abort();
} else if (pid) {
// Application process
gdb_process_pid = pid; // save debugger pid
sleep(10); /* Give GDB time to attach */
// Continue the application execution controlled by GDB
} else /* child */ {
// GDBServer Process
// Pass parent process id to the debugger
std::stringstream pidStr;
pidStr << getppid();
// Invoke GDB debugger
execl("/usr/bin/gdbserver", "gdbserver", "127.0.0.1:11337", "--attach", pidStr.str().c_str(), (char *) 0);
// Get here only in case of GDB invocation failure
std::cerr << "\nFailed to exec GDB\n" << std::endl;
}
}
}
#endif
此外,它还允许在安装了 gdbserver 并在您的开发电脑上安装 gdb-multiarch 的嵌入式设备上进行调试。
在 Eclipse 中进行调试时,它会在 C/C++ 调试器和 Java 调试器之间自动跳转。您只需启动两个调试会话:java 一个和远程 C/C++ 一个,在 127.0.0.1:11337 上运行。
【解决方案3】:
Link by tm.sauron 是对的但是当我们有很多参数要传递给 java 命令时会不太方便,比如我的项目有大约几行参数要传递。因此,在这种情况下,我们可以使用 IDE 启动应用程序,并在我们想要在本机库中进行调试时将其中断。当然原生库需要在调试模式下创建。