📜 ⬆️ ⬇️

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 had a vague idea of ​​how to do this. Unfortunately, there was very little sensible information on debugging native code. Having spent several evenings on this matter, I nevertheless figured out and adjusted debugging. Now I will talk about how this can be done and tell you what rakes can expect you if you plan to repeat my way.


For convenience, I created a project for debugging application - 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 is, respectively, the Activity code, the code for the JNI shell, and the native code.
')
Activity code is quite 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 end up with a rake, see below).

Here is the code:

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;
}

}


Jni shell is also pretty simple:

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);
}


Well, actually native code. Here, another function is called from the Jni-function, which kills the application:

#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, whenever you press a finger, the application drops. Our task is to find the place of the fall and see the backtrace. So let's get started.

Instruments


We should have at our disposal:


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) Add the following line to Application.mk:
APP_OPTIM: = debug
This parameter, if I’m not mistaken, removes stripping (deletion of unused characters) when copying libraries, and does some other useful things for debugging.
In Android.mk, add the -g -ggdb -O0 parameters to LOCAL_CFLAGS, and remove -s and -S from the LOCAL_LDLIBS parameters (if any).

3) After that, run Cygwin, go to the directory with the project and run the build with the key NDK_DEBUG = 1:
ndk-build NDK_DEBUG = 1

If everything is done correctly, the gdb.setup and gdbserver files will appear in the project directory in the libs / <platform> subdirectory.

4) In gdb.setup, the basic debugger settings are specified - in which directories to search for headers and libraries. It is necessary to check whether all the paths to the headings are indicated and, if necessary, add their own paths.
Here are the rakes. For some reason, at each reassembly in this file, the characters of line breaks are lost, which is why settings are not read. You should make sure that the file is applied UNIX-linefeed. I had to re-save gdb.setup with another line break after each call to ndk-build!

When you start the debugger, this file (gdb.setup) is automatically supplemented with other parameters and copied into obj / local / <platform> /. All native libraries necessary for the application to work are also stored in obj / local / <platform> /. If the build is correct, then the libraries contain debase symbols. If you are in doubt, it is possible to check the presence or absence of debazh characters directly from the Cygwin console using the nm utility, specifying the required 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 file build / core / build-binary.mk, namely: change the line:

$ (hide) $ (call cmd-strip, $ (PRIVATE_DST))

On the lines:

ifneq ($ (APP_OPTIM), debug)
$ (hide) $ (call cmd-strip, $ (PRIVATE_DST))
endif

Debugging


Everything is ready for debugging. We start debugging through eclipse, we wait until the debugger is picked up. Then in cygwin go to the directory with the project and run the native ndk-gdb debugger. The --adb parameter specifies the path to adb, which is included with android-sdk:


Here are another rake. Make sure that all the native libraries (in our case, NdkDebugTestLib) are loaded before launch! You can check this by putting a breakpoint on the library loading.

If everything is done correctly, you will see a long list of libraries for which characters 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 an invitation to enter:


Continue with the continue command. Then press a finger on the screen of the device, and the application falls, indicating the drop point:


The crash occurred when calling * x = 1; in line 6 in the jni / android_api.cpp file, as expected.

We enter backtrace - and we see a stack of calls of functions which led to falling:


Conclusion


Well, the goal is achieved - we found the place of the application crash, and saw the call stack. Using the debugger, you can set breakpoint, evaluate expressions and do much more, but it’s not a problem to find information about 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/

Source: https://habr.com/ru/post/144672/


All Articles