This post is about using GDB to debug a DLL built with debug symbols which was called from a Java application being debugged by JetBrains IntelliJ IDEA.
First things first: I am working on a Java application which has calls to C++ methods. The C++ classes and namespaces are compiled into a DLL using Cygwin.
I am not going into the build process of this project, at this time, but check back later. The development process currently looks like:
- shell: bash
- source: Java and C++
- make: GNU make
- environment: Window 10 64-bit with Cygwin64
- IDE: JetBrains IntelliJ IDEA
- environment: Linux (Fedora 21 64-bit)
- IDE: Linux
- On Windows I had to call JetBrains IntelliJ IDEA from the Cygwin64 shell
- I added my own JAR Application in the Run/Debug Configurations dialog within IDEA:
- Your DLL needs to be built with debug symbols. With a Cygwin shell this means adding -g to the g++ command line.
- You can always use GDB to call Java and set breakpoints in C++ code; However, if there is a crash, then you will get much more useful information if GDB is attached to the process
JetBrains IntelliJ IDEA debugging Java
Using IDEA, put a break-point right before the native call that you want to debug into.
Now select the Java application you want to run (or setup the JAR Application, as I did above in the Notes section) and click on run Debug mode (start Debug is Shift+F9). Your application should run to the break-point that is just before the DLL call.
If you don’t know the Process ID of the Java application that is being debugged, then you can go to the IDEA session where you are still at a break-point just before the DLL call.
In the IDEA Console session under debug click on the “Evaluate Expression” icon:
Enter Code Fragment Mode by clicking the button on the bottom of the “Evaluate Expression” dialog (i.e. if you see a button called Expression Mode, then you are already in Code Fragment Mode). Enter this code (copy and paste), IDEA was not letting me paste, but CTRL+Shift+v worked:
String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); long pid = Long.parseLong(processName.split("@"));
The results (pid variable) is the PID of the Java application that is running.
GDB debugging C++
In the Cygwin64 shell call gdb, then attach GDB to the Java process:
Then set the break-point where you want to start debugging, e.g.:
break Java_keypress_KeyPress_registerHotKey continue
Back in IDEA now click on ‘Step Into (F7)’ and now we should hit our C++ break point. Continue debugging with GDB as normal.
Hopefully you see something like the following:
Program received signal SIGSEGV, Segmentation fault. 0x00000003dc8c1f3d in cygstdc++-6!_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ () from /usr/bin/cygstdc++-6.dll
To get more information you can use the following:
$ echo _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ | c++filt.exe std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
If you have a DLL/SO with debug symbols, then you can also try:
addr2line.exe -p -C -e /usr/bin/cygstdc++-6.dll 0x00000003dc8c1f3d
I like apples.