Debugging native Android NDK code on Windows
Introduction
Good day!
Once I faced the task of catching an incomprehensible fall in my application. As far as I knew then, the Android NDK provided the ability to debug C ++ code, but I vaguely imagined how to do it. Unfortunately, there was very little sensible information on debugging native code. Having spent several evenings on this matter, I still figured out and set up debugging. Now I will talk about how this can be done and I’ll talk about what kind of rake can expect you if you decide to repeat my path.
For convenience, I created a debugging application project - NdkDebugTest. The application shows a black screen, and when you click on the screen, the native code is called, which kills the application. The project consists of two java files and one jni file. This, respectively, is the Activity code, the code for the JNI shell, and the native code.
The Activity code is pretty simple - with any touch, the native OnInput function is called. Also, when creating an Activity, an empty DoInit () method is called, whose task is to start the static loading of native libraries from JniWrapper.java (if this is not done, we will get to the rake, see below).
Here is the code: The Jni shell is also quite simple: Well, actually the native code. Here, another function is called from the Jni function, which kills the application:
package fishrungames.ndkdebugtest;
//...
public class MainActivity extends Activity
{
protected void onCreate(Bundle icicle)
{
super.onCreate(icicle);
JniWrapper.DoInit();
}
public boolean onTouchEvent(MotionEvent event)
{
float x = event.getX();
float y = event.getY();
JniWrapper.OnInput(x, y);
return true;
}
}
package fishrungames.ndkdebugtest;
public class JniWrapper
{
static {
System.loadLibrary("gnustl_shared");
System.loadLibrary("NdkDebugTestLib");
}
public static void DoInit()
{
//To force libraries to load
}
public static native void OnInput(float x, float y);
}
#include "android_api.h"
void crusher()
{
int *x = 0;
*x = 1;
}
JNIEXPORT void JNICALL Java_fishrungames_ndkdebugtest_JniWrapper_OnInput(JNIEnv * env, jobject obj, float x, float y)
{
crusher();
}
As I wrote above, after launching the application, with any click of the finger, the application crashes. Our task is to find a place to fall and see the backtrace. So let's get started.
Instruments
We must have at our disposal:
- Eclipse with the open NdkBuildTest project
- Cygwin
- Installed android-sdk
- Installed android-ndk, the path to which must be specified in the PATH environment variable. The older the ndk version, the better (I used android-ndk-r8)
Training
1) Make sure the debuggable = "true" parameter is set in the manifest:
<application android: icon = "@ drawable / ic_menu_template" android: label = "NdkDebugTest" android: debuggable = "true">
2) In Application.mk, add the following line:
APP_OPTIM: = debug
This parameter, if I’m not mistaken, will cancel stripping (deleting unused characters) when copying libraries, and do some other things useful for debugging.
In Android.mk, the -g -ggdb -O0 parameters should be added to LOCAL_CFLAGS, and -s and -S (if any) should be removed from the LOCAL_LDLIBS parameters.
3) After that, run Cygwin, go to the directory with the project and start the assembly with the key NDK_DEBUG = 1:
ndk-build NDK_DEBUG = 1
If everything is done correctly, then the gdb.setup and gdbserver files will appear in the project directory in the subdirectory libs / <platform> /.
4) In gdb.setup, the basic debugger settings are indicated - in which directories to look for headers and libraries. It is necessary to check whether all the paths to the headers are indicated and, if necessary, add their own paths.
There is a rake. For some reason, with each rebuild in this file line break characters get lost, because of which the settings are not read. Make sure that the file uses UNIX line breaks. After each call to ndk-build, I had to re-save gdb.setup with a different line break!
When the debugger starts, this file (gdb.setup) is automatically supplemented with other parameters and is copied to obj / local / <platform> /. All native libraries necessary for the application to work are also stored in obj / local / <platform> /. If the assembly went right, then the libraries contain debazhnye characters. If you doubt it, then the presence or absence of debazhnyh characters can be checked directly from the Cygwin console using the nm utility, specifying the desired so-file as a parameter:
nm /obj/local/armeabi/libNdkDebugLib.so
In some older versions of android-ndk It was also recommended to edit the build / core / build-binary.mk file, namely: change the line:
$ (hide) $ (call cmd-strip, $ (PRIVATE_DST))
To the lines:
ifneq ($ (APP_OPTIM), debug)
$ (hide) $ (call cmd-strip, $ (PRIVATE_DST))
endif
Debugging
Everything is ready for debugging. We start debugging through eclipse, wait until the debugger picks up. Then in cygwin we go to the directory with the project and run the ndk-gdb native debugger. The --adb parameter specifies the path to adb, which is part of android-sdk:

Here is another rake. Make sure that all native libraries (in our case, NdkDebugTestLib) are loaded before launch! You can verify this by setting a breakpoint on loading the library.
If everything is done correctly, you will see a long list of libraries for which symbols have not been loaded. Make sure that your library is not among them (in our case, libNdkDebugTestLib.so).
If everything goes well, we will see a prompt to enter:

We continue with the continue command. Then we press a finger on the device screen, and the application crashes, indicating the point of fall:

The crash occurred when calling * x = 1; on line 6 in jni / android_api.cpp, as expected.
We introduce backtrace - and we see a stack of function calls that led to the crash:

Conclusion
Well, the goal is achieved - we found the application crash site, and saw the call stack. Using the debugger, you can set breakpoints, evaluate expressions and do much more, but there is no problem finding information on how to use the command line debugger.
Here is a link to the project, which is described in the article: http://fishrungames.ru/4habr/NdkDebugTest.rar .
Sources
http://vilimpoc.org/blog/2010/09/23/hello-gdbserver-a-debuggable-jni-example-for-android/
http://blog.sephiroth.it/2010/12/14/how- to-debug-native-code-with-android /
http://mhandroid.wordpress.com/2011/01/23/using-eclipse-for-android-cc-debugging/