While reading Understanding the JVM – Advanced Features and Best Practices, Second Edition (in Chinese) recently, there is a guide in chapter one to build JVM from source. It is based on OpenJDK7, which only works when using a Java6/Java7 VM as build bootstrap. Java8 bootstrap has more strict code checks and will finally fail the build. So, I just switched to a more recent OpenJDK8 code. The file name is openjdk-8u40-src-b25-10_feb_2015.zip.

The code provides a better build experience, and compiles on my Linux box almost out of box. But remember, do not use a gcc compiler >= gcc-6. It defaults to C++14 and breaks the build. On macOS, the build scripts seem only support gcc. Actually, a clang compiler is required to build the objc code.

1. So the first step after downloading and unzipping the code, modify the configure script:

Comment out the lines(2 appearances):

2. Now install freetype and run configure:

A slowdebug build disables optimization and helps a lot when debugging. The summary output looks like:

3. Apply the following patch to fix build errors. Partially picked from an official OpenJDK10 changeset:

4. Start the build:

Lots of warnings, but the build should finish successfully:

5. Debugging with lldb:

The output binary lie in openjdk/build/macosx-x86_64-normal-server-slowdebug/jdk. The output of java -version:

Never used lldb before, seems to be compatible with gdb:

There’s an official page on gcc website: https://sourceware.org/gdb/wiki/STLSupport. And here is how to set up it under Ubuntu.

Under Ubuntu 12.04(Precise), simply install the libstdc++6 debug package. It includes the python script for pretty printers:

Create a .gdbinit file in your home directory, with the content:

My test program looks like:

Build it with debugging enabled(-g):

Debug it with GDB:

Without pretty printers, the output is tedious and hard to understand:

Under Ubuntu 14.04(Trusty), the 4.8 version of debug package should be installed:

There’s an additional step. Since GDB in Trusty is built with python3, not python2, and the python scripts for pretty printers are in python2 syntax. A simple conversion is required:

Backup it before conversion if neccessary.

I’m running Ubuntu 12.04 as host, with VirtualBox 4.2.22. This tutorial should cover guests including Windows XP, CentOS and Ubuntu.

1. Settings in VirtualBox

In the settings page, Check “Enable Serial Port”, set “Port Number” to “COM1”. This is the port number in the guest. If the guest is a Linux, COM1 is shown as /dev/ttyS0, and COM2 is shown as /dev/ttyS1.

Set “Port Mode” to “Host Pipe”, check “Create Pipe” and set “Port/File Path” to “/tmp/vbox”. Seems it utilizes a named pipe. These settings work even if the host does not have a physical serial device.

serial_console_1

2. Install minicom

The second command setups minicom with an interactive menu. Select “Serial port setup”, and set “Serial Device” as “unix#/tmp/vbox”(without quotes). “Save setup as dfl” and “Exit from Minicom”.

3. Verity the serial device in guest

Now boot your Linux guest. Run the following command, and it should output something like:

The guest here is CentOS5, and the serial device is /dev/ttyS0.

4. Communication via serial device

Start minicom on your host:

Echo something from your guest and redirect to /dev/ttyS0. You host should get the message in minicom.

To read from the host, cat the device in guest so that you can do the input in minicom:

serial_console_2

5. Kernel configuration

CentOS5 comes with grub1, /etc/grub.conf is modified directly to allow the boot information to also be sent to our serial device. The original boot entry looks like:

Change to add console= parameter:

That’s all for CentOS 5/6. There’s no need to modify /etc/inittab or /etc/securetty file as required in ArchLinux. These OS will do it for you.

Now, reboot your guest CentOS. The boot information should now displayed in your minicom. Finally, it will provide you with a login shell.

serial_console_3
You can verify that there’s a new line added into /etc/inittab to enable getty(8) and execute a login shell:

And ttyS0 is also added into /etc/securetty.

6. Ubuntu guest settings

Ubuntu 12.04 come with grub2. We do not modify /boot/grub/grub.cfg, we modify /etc/default/grub instead, so that the serial console parameters will remain even after you update your kernel. Open it, modify the following line to:

And update grub:

One additional step for Ubuntu, is to enable getty(8) for serial console by your own. Ubuntu uses upstart init system, we need to create a file called /etc/init/ttyS0.conf containing the following:

Reboot you Ubuntu guest, and the serial device should work as it is with CentOS. More info, please refer to the official wiki.

7. Windows guest settings

The serial device shows as COM1 in Windows XP as previously set. With a simple echo and redirect, our host can receive the message.

serial_console_4

8. Windows as host

Settings of VirtualBox under Windows is almost the same as that under Linux. But we set “Port/File Path” to “\\.\pipe\vbox”, instead of “/tmp/vbox”. After the configuration of kernel and getty(8), we can use PuTTY to connect. Simply set “Connection type” to “Serial”, and “Serial line” to “\\.\pipe\vbox”.
serial_console_5

In previous articles, I was not able to use Qt’s debug package provided by Ubuntu. Now, I will explain how to use them.

Our simple application:

Our *.pro file, you should enable the debug build:

1. Build your debug version of application:

2. Install Qt’s debug package:

3. Install the Qt source:

Now you can start debugging your application. Since Qt’s debug symbols are installed in /usr/lib, It does not follow the GDB’s global debug directory described here. We should tell GDB to load these symbols manually:

We set a breakpoint at the beginning of main function to load all shared libraries. Next, we will load symbols for libQtCore.so.4. The symbol will be loaded in the start address of it (0xb7652510):

Now, you are able to step into the Qt library, but no source is attached:

Source files are attached by:

See the source and backtrace? 🙂

From last blog, I’ve demostrated the usage of Ubuntu *-dbg packages. However, not all *-dbg packages seem to work as libssl0.9.8-dbg. For instance, libcurl3-dbg and libqt4-dbg packages do not work. I’m afraid some debug info are missing in these two packages. I’m not sure.

I googled a lot, but was not able to find a solution. So I decided to build the debug version of the two library myself. Here are steps for libcurl:

After all, the compiled binary is located in /home/gonwan/testgdb/curl-7.19.7/lib/.libs/. Note, this is a hidden folder.

Here comes our test code:

Build commands:

I use /usr/lib/libcurl.so.4 instead of lcurl, since lcurl will link the binary to /usr/lib/libcurl-gnutls.so.4. But I currently cannot afford it :(. Last, start our GDB:

It prints the backtrace now, though I’m not so accustomed to console debugging. I add the LD_LIBRARY_PATH environment to let our test program find our homemade version of libcurl.so.4. In fact, we can run ldd like following lines. You see the re-direction?

Later, I successfully made it possible to debug Qt source code in IDE. I chose QtCreator, since it has both windows and linux version, and it’s easy to install and configure. I also built my homemade version of Qt:

I only built the most common modules, excluding webkit, script, xmlpatterns, phonon, multimedia and declarative modules. It took only 25 minutes to finish (An entire build under windows may take 3 – 4 hours.). After all, start your QtCreator, create a Qt console project with the source below:

Build the project in debug mode. And now, here’s the magic: Go to Project tab –> Run Settings –> Run Environment, append our homemade Qt library path to LD_LIBRARY_PATH. In my example, it’s /home/gonwan/testgdb/qt4-x11-4.6.2/lib. Ok, you’re almost done! Go back to the Edit tab, set a breakpoint at line 4 (or line 3 as you like), press F5 to start debugging the project. Then continue pressing F11, you will find GDB has stepped into Qt source code! Let me take a screenshot:

qtcreator_qt4debug

In order to load our homemade *.so, we can also run “make install”.