Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Debug Java -JNI using GDB on linux ?

Tags:

Can anyone guide on how to debug a JNI code on Linux using GDB debugger(if possible please suggest other options).

    -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*.

I have the Gdb installed but am not getting how we can debug the project using it. Also do I necessarily need to compile the .cpp files with -g option t debug .so files?

like image 927
Twaha Mehmood Avatar asked Feb 13 '12 05:02

Twaha Mehmood


People also ask

Can I debug Java with gdb?

The gdb allows you to examine and control the execution of code and is useful for evaluating the causes of crashes or general incorrect behavior. gdb does not handle Java™ processes, so it is of limited use on a pure Java program. It is useful for debugging native libraries and the JVM itself.


2 Answers

  1. Start your java application
  2. Look up the pid using top, ps, ...
  3. Start gdb with this pid
  4. Attach your program code
  5. Debug as usual using gdb

This blog post explains the whole thing.

like image 63
jackrabbit Avatar answered Sep 25 '22 16:09

jackrabbit


I found the following way really interesting. By linking the file below to the jni library you want to debug, when the library get loaded by the dynamic linker it automatically starts a gdbserver for the current jvm, thanks to the gcc constructor attribute.

Simply using remote gdb from command line or from eclipse make it easy to debug then. I only setup that if I build in debug mode, I haven't implemented for the moment to detect if jvm was started in debug, to only allow this at this moment, but could be easy.

I simply adapted the concept from the article here : 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

Additionally it also allows debugging on embedded devices with gdbserver installed and gdb-multiarch on your development pc.

While debugging from within eclipse it jump automatically between the C/C++ debugger and the Java debugger. You just have to start both debugging session : the java one and the remote C/C++ one which runs on 127.0.0.1:11337.

like image 45
daminetreg Avatar answered Sep 23 '22 16:09

daminetreg