Showing posts with label debugging. Show all posts
Showing posts with label debugging. Show all posts

Thursday, February 14, 2013

Hotspot JIT output disassembly on Fedora 18

Well, I was very thrilled when I saw that it is possible to output assembly code produced by Hotspot. But, the problem is that this isn't enabled by default, at least not on Fedora 18. It is necessary to compile decompiler plugin before you can try this. To make things worse, this compilation process assumes that you don't have binutils already installed so it tries to compile that too. In the end, I managed to get that working and here is how.

First, you need to download OpenJDK's source. Note that there is source in Fedora's binary repository but this is only the source of Jaba API packages. So, you have to download the real source, either from java.net or approriate SRPM. In both cases be careful to download source that matches OpenJDK you have installed on your machine.

Next, unpack the source and go to the directory openjdk/hotspot/src/share/tools/hsdis. Now, open hsdis.c file and replace the following line:
#include <sysdep.h>
with the following lines:
#include <string.h>
#include <errno.h>
Now, compile the source using the following command:
gcc -o hsdis-amd64.so -DLIBARCH_amd64 -DLIBARCH="amd64" \
       -DLIB_EXT=".so" -m64 -fPIC -O hsdis.c -shared \
       -ldl -lopcodes
The compilation will fail unless you have binutils-devel package installed. So, take care about that. In case the compilation was successful you'll have hsdis-amd64.so file. It's a dynamic library. Note that I'm using 64 bit AMD/Intel architecture. If you are using 32 bit version replace amd64 with i386 and -m64 with -m32. In case of some other architecture you'll have to find out yourself what's the name.

Now, you'll need some Java class that you'll run and that will produce assembly output. The main point you should have in mind is that the code has to be such to provoke JIT to be started. Otherwise, you'll don't get any assembly output.  I used the following simple class file:
import java.math.BigInteger;

class Multiply
{
    public static void main(String[] args)
    {
        BigInteger a = BigInteger.ONE;

        for (int i = 0; i < 10000; i++)
            a = a.multiply(BigInteger.valueOf(2));
        System.out.println(a);
    }
}
After compiling it, run it using the following command:
LD_LIBRARY_PATH=. java -XX:+UnlockDiagnosticVMOptions \
    -XX:+PrintAssembly -XX:PrintAssemblyOptions=intel \
    Multiply
Note that I'm using LD_LIBRARY_PATH to tell JIT where disassembler (hsdis) is. In my case everything is in the current directory. Note that in the previous command I specified that I want Intel assembly syntax. The default one is AT&T.

Wednesday, September 26, 2012

Segmentation fault in the header of a main function...

Well, I just compiled one program I got from the Internet and to my surprise it segfaulted immediately after the start. To protect innocent, I'll call the binary of this program gensigseg. This is what happened:
$ ./gensigseg
Segmentation fault (core dumped)
First, I thought that it accesses command line arguments without checking they are present. This application proved already to be very lousy written, and it wouldn't surprise me that this is the problem. So, I tried with a dummy parameters, all in hope that I'll get some kind of a help message. But, the same thing happened again and there was no help message. It was time to see where it exactly segfaulted:
$ ulimit -c unlimited
$ ./gensigseg
Segmentation fault (core dumped)

$ gdb ./gensigseg core
...
Core was generated by `./gensigseg'.
Program terminated with signal 11, Segmentation fault.
#0  0x0000000000407100 in main (argc=Cannot access memory at address 0x7fff40d80f8c
) at gensigsegmain.c:137
137    int main (int argc, const char *argv []) {
You can imagine my surprise when I saw that! Segmentation fault in the header of the function main itself! Well, that was weird. Googling for this didn't revealed anything useful. After all, how many times did you see that?!

So, after poking with assembly, different optimization options, etc. I finally realized that the problem was in stack. Namely,  when disassembling main function in gdb, it pointed exact assembly instruction that caused the segmentation fault, and it turned out to be the instruction that accessed stack after the stack's value was subtracted with some large value (this was allocation of space for local variables). Anyway, after increasing stack size from default 8M to 32M (using ulimit command) the command finally worked.

Instead of conclusion, let me say that this application is unbelievably lousy written. So much about those who wrote it. More interesting is that this application was written for ITU, and if ITU accepts such shit (I have to use that word!) that what it says about ITU itslef? I'll leave this question unansvered...

Thursday, January 19, 2012

Problem with avformat_open_input()

I lost too much time because of a misleading error message reported by avformat_open_input function! I used the following code that exhibit the error:
AVFormatContext *pFormatCtx = NULL;
...
ret = avformat_open_input(&pFormatCtx, argv[1], NULL, NULL);
if (ret < 0)
   print_error_and_exit(ret, "avformat_open_input()");
print_error_and_exit() is a helper function that uses av_strerror() to give textual representation of the error code stored in ret. Running this code produced the following output:
$ ./a.out infile.wav outfile.wav
avformat_open_input(): No such file or directory
But the infile.wav was there! Using strace I found that open system call wasn't called and so it was certainly an internal error. This was frustrating! The reason I started to write this code was to find out why I'm getting another error in VoIP tool simulator, but I was stuck on something even more basic: Not being able to open a wav file. Googling around I finally found the following link which explained me a real cause of the error, i.e. I forgot to call av_register_all() initialization function.

This again shows how important good error reporting is, in both libraries and application programs!

I had also another problem with the previous code. It was segfaulting within avformat_open_input(). At first, I thought that I found a bug within a library but then I realized I forgot to initialize pFormatCtx to NULL. Namely, allocating a dynamic variable on stack didn't zero it so it was non-NULL and avformat_open_input() misbehaved. Mea culpa! :)

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive