Solution for SIGILL exception in Android Linker
If you are developing native Android apps or libraries and have recently (as of Q4'2014) updated your SDK or NDK, your debugging may fail with the following exception:
The exception message typically looks like that:
This happens due to a bug in Android GDB that prevents it from correctly handling a breakpoint that is set in linker to detect library load/unload events. This page describes a solution to that problem.
The cause
In order to load the symbols for your libraries when they are loaded, GDB needs to hook the library loading events. This is done by setting an implicit breakpoint in the rtld_db_dlactivity() function inside the linker binary. The problem happens when GDB tries to continue running after hitting that breakpoint. It tries to perform a single step by setting another breakpoint in the function that called it and the Android OS triggers an exception.
The manual solution
In order to avoid the SIGILL or SIGSEGV exception, you need to manually set a breakpoint at the same address and once it is hit, prevent GDB from doing the disruptive single-stepping by manually overriding the PC register value:
Then you need to force GDB to load the symbols to the newly loaded library:
However, you need to ensure that you set the breakpoint before GDB sets its internal breakpoint.
The automatic solution
If you are using VisualGDB 4.3 or later to debug your Android
code, open the VisualGDB Project Properties, go to the Debug
Settings page and enable the Library Load Workaround:
VisualGDB supports 2 different methods of setting the breakpoint:
- Method 1 sets the breakpoint at the same address as GDB normally does. This works if GDB has already set a breakpoint in the linker and it is causing SIGILLs.
- Method 2 sets the breakpoint at the normal address + 1, explicitly telling GDB to use the THUMB mode. This works if GDB has not set any breakpoints and library load events are simply ignored.
Different combinations of Android toolchains and Android OS versions produce different behavior, so don't hesitate to try both methods if one of them does not work.