Debugging in Visual Studio 2017 with a Command Line Compiled (cl.exe) and Linked (link.exe) Debug Executable Example

Compile (cl.exe) with /Zi /Od /Fd

Link (link.exe) with /DEBUG /DEBUGTYPE:PDATA

The produced executables will contain the full path in the Dynamically Linked Libraries (DLLs) and Executables.

To debug in Visual Studio 2017 go to File > Open Project/Solution… and select your executable.

Advertisements

Catching a double free or corruption error with memcheck (a Valgrind tool)

I was randomly getting errors (1 run in 50 would reproduce) like:

$ ./myprogram
*** glibc detected *** double free or corruption (out): 0x093014a4 ***

Linux has a randomization of virtual address space which is supposed to help thwart buffer overflow attacks etc.

This can cause errors to randomly not show, so in the spirit of trying to consistently reproduce the problem I disabled this using:

$ setarch x86_64 -R ./myprogram

This didn’t seem to help.

$ valgrind --tool=memcheck ./myprogram

The output of this produced a:

Invalid free which showed where the error was.

Debugging C++ with GDB

An example…

If you want to know how to launch GDB, then an example program with GDB commands are provided at the bottom of this page, click here to go to them.

How do I tell where I am at while debugging?

GDB let’s you move up and down the stack, so you must first understand the difference between:

  1. Where has the program stopped for debugging?
  2. Where in the stack am I currently at?

Where has the program stopped for debugging?

To see where you are in the program (print a stack back-trace):

where
info stack
bt

To see the file and location of at the top of the stack (where the program stopped):

frame 0

To see the code at this location run:

list

Just remember, that if you run list again, it will continue down the file – run ‘frame’ again to reset it.

Where in the stack am I currently at?

To see the file and location of where GDB is in the stack:

frame

If you want to see registers and frame arguments run:

info frame

You can move up and down the stack with:

up
down

To see the code around where you are:

list

What source file is this symbol defined in?

If you are in GDB and need to see what file a symbol is defined in, then run:

info types <type>

You can also just print them all with:

info types

How do I invoke code?

Just print it:

p myShapePtr.getSize()

Catch any Throw

If your program is crashing and you just want to see why, then you can tell GDB to catch a throw using a catchpoint. To create such a catchpoint use:

catch throw

This will catch every throw your program does.  What you may be surprised to find is that some libraries throw and catch and you may find yourself in unexpected locations hitting catchpoints that threw.

You can do much more with the catch command, you can tell it to set a catchpoint at any of these:

throw - The throwing of a C++ exception.
catch - The catching of a C++ exception.
exec - A call to exec. This is currently only available for HP-UX.
fork - A call to fork. This is currently only available for HP-UX.
vfork - A call to vfork. This is currently only available for HP-UX.
load || load libname - The dynamic loading of any shared library, or the loading of the library libname. This is currently only available for HP-UX.
unload || unload libname - The unloading of any dynamically loaded shared library, or the unloading of the library libname. This is currently only available for HP-UX.

 

How do I Enable Minidumps on Windows?

If you see something like this:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000000000000, pid=10700, tid=6032
#
# JRE version: Java(TM) SE Runtime Environment (8.0_71-b15) (build 1.8.0_71-b15)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.71-b15 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  0x0000000000000000
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:UsersNikIdeaProjectshydrogenhs_err_pid10700.log
Compiled method (c2)     383  418       4       java.lang.StringBuilder::append (8 bytes)
 total in heap  [0x0000000002c37b50,0x0000000002c38428] = 2264
 relocation     [0x0000000002c37c70,0x0000000002c37c98] = 40
 main code      [0x0000000002c37ca0,0x0000000002c38060] = 960
 stub code      [0x0000000002c38060,0x0000000002c38078] = 24
 metadata       [0x0000000002c38078,0x0000000002c380c0] = 72
 scopes data    [0x0000000002c380c0,0x0000000002c382e8] = 552
 scopes pcs     [0x0000000002c382e8,0x0000000002c383a8] = 192
 dependencies   [0x0000000002c383a8,0x0000000002c383b0] = 8
 handler table  [0x0000000002c383b0,0x0000000002c383f8] = 72
 nul chk table  [0x0000000002c383f8,0x0000000002c38428] = 48
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#

To get more information about this error message, then enable minidumps.

Enable minidumps through Advanced System Settings -> System Properties -> Startup and Recovery -> Settings -> Write debugging information: ‘Small memory dump (…)’.

You will have to reboot the machine, and then you will see fuller logs.

After rebooting, rerun the program to see the crash again and now it will have much more useful details.

Notice: You may also want to build debug so that the dump has more useful information

Debugging DLL using GDB called via JNI (Java Native Interface) being debugged by JetBrains IntelliJ IDEA

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

Notes:

  • 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

addHotKey

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:EvaluateExpression

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("@")[0]);

EvaluateCodeFragment

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:

attach 7964

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