Prolog
Before I get into the rest of the post, here is a link to a .zip of the Eclipse project files if you just want to skip ahead.
The Rest Of The Post
Native software development on Android using its JNI capabilities is incredibly frustrating without proper visibility into the causes of native code errors.
Here is an example project and some background info that shows how to get gdb and gdbserver working to catch those nasty bugs. Just extract the project files into the NDK’s sample directory and import the project into Eclipse.
Here were some of the search terms I tried unsuccessfully while trying find something like this:
using gdb on android
using ndk-gdb
debug jni android
hello world android native code
hello world android emulator
debugging using gdbserver android
Requirements
- A phone running Android 2.2 (Froyo) (might work on the emulator, but I didn’t focus on that)
- The latest Android NDK (at least r4b)
- Lots of Patience
The NDK-GDB.TXT readme file in the NDK has a good overview of the process of getting a debuggable Android application + JNI build set up, but I would have much preferred it if Google had simply included something like a hello-gdbserver test app in the provided samples. One simple app where you could induce a crash to see what would happen, like a tutorial for smarter bug-hunting. So, I made this one.
Getting Started
Here’s an example of some (exaggeratedly) buggy code in the JNI shared object in jni/hello-gdbserver.c:
1234567891011 /** Class: com_example_hellogdbserver_HelloGdbServer* Method: invokeCrash* Signature: ()V*/JNIEXPORT void JNICALL Java_com_example_hellogdbserver_HelloGdbServer_invokeCrash(JNIEnv *env, jclass clazz){int *crasher = 0x0;*crasher = 0xdeaddead;}
Fugly. This will kill your app dead without so much as a thank you or goodbye. And you’ll never know what hit you, because all you see is a stack trace in DDMS that says “I blew up, and here is a long list of hexadecimal numbers you’ll never decode.” In any non-trivial app (which is basically any app), you could spend days trying to hunt this down, which is certainly not the best use of engineer time.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 I/DEBUG ( 27): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***I/DEBUG ( 27): Build fingerprint: 'generic/sdk/generic/:1.6/Donut/20842:eng/test-keys'I/DEBUG ( 27): pid: 260, tid: 260 >>> com.example.hellogdbserver <<<I/DEBUG ( 27): signal 11 (SIGSEGV), fault addr 00000000I/DEBUG ( 27): r0 0000a9d0 r1 4376e278 r2 deaddead r3 00000000I/DEBUG ( 27): r4 bef506b0 r5 00000000 r6 80600ba1 r7 4104baecI/DEBUG ( 27): r8 bef50690 r9 4104bae4 10 4104bad4 fp 00000000I/DEBUG ( 27): ip 80600ba1 sp bef50680 lr ad00e438 pc 80600bae cpsr 60000030I/DEBUG ( 27): #00 pc 00000bae /data/data/com.example.hellogdbserver/lib/libhello-gdbserver.soI/DEBUG ( 27): #01 pc 0000e434 /system/lib/libdvm.soI/DEBUG ( 27): #02 pc 00040b0e /system/lib/libdvm.soI/DEBUG ( 27): #03 pc 000432b6 /system/lib/libdvm.soI/DEBUG ( 27): #04 pc 00013198 /system/lib/libdvm.soI/DEBUG ( 27): #05 pc 00017be4 /system/lib/libdvm.soI/DEBUG ( 27): #06 pc 0001762c /system/lib/libdvm.soI/DEBUG ( 27): #07 pc 000529a8 /system/lib/libdvm.soI/DEBUG ( 27): #08 pc 00059eda /system/lib/libdvm.soI/DEBUG ( 27): #09 pc 00013198 /system/lib/libdvm.soI/DEBUG ( 27): #10 pc 00017be4 /system/lib/libdvm.soI/DEBUG ( 27): #11 pc 0001762c /system/lib/libdvm.soI/DEBUG ( 27): #12 pc 0005282c /system/lib/libdvm.soI/DEBUG ( 27): #13 pc 0003f790 /system/lib/libdvm.soI/DEBUG ( 27): #14 pc 00031caa /system/lib/libdvm.soI/DEBUG ( 27): #15 pc 0002a804 /system/lib/libandroid_runtime.soI/DEBUG ( 27): #16 pc 0002b306 /system/lib/libandroid_runtime.soI/DEBUG ( 27): #17 pc 00008bf2 /system/bin/app_processI/DEBUG ( 27): #18 pc 0000bd60 /system/lib/libc.soI/DEBUG ( 27): #19 pc b000163c /system/bin/linkerI/DEBUG ( 27): stack:I/DEBUG ( 27): bef50640 00000071I/DEBUG ( 27): bef50644 afe0b03f /system/lib/libc.soI/DEBUG ( 27): bef50648 80600ba1 /data/data/com.example.hellogdbserver/lib/libhello-gdbserver.soI/DEBUG ( 27): bef5064c 00000007I/DEBUG ( 27): bef50650 afe3c9a0I/DEBUG ( 27): bef50654 afe39dd4 /system/lib/libc.soI/DEBUG ( 27): bef50658 0000a000 [heap]I/DEBUG ( 27): bef5065c 00000028I/DEBUG ( 27): bef50660 4104896a /data/dalvik-cache/data@app@com.example.hellogdbserver.apk@classes.dexI/DEBUG ( 27): bef50664 00000000I/DEBUG ( 27): bef50668 001c5788 [heap]I/DEBUG ( 27): bef5066c 001a7710 [heap]I/DEBUG ( 27): bef50670 001c56f0 [heap]I/DEBUG ( 27): bef50674 ad043199 /system/lib/libdvm.soI/DEBUG ( 27): bef50678 df002777I/DEBUG ( 27): bef5067c e3a070adI/DEBUG ( 27): #00 bef50680 4376e278 /dev/ashmem/mspace/dalvik-heap/2 (deleted)I/DEBUG ( 27): bef50684 0000a9d0 [heap]I/DEBUG ( 27): bef50688 00000000I/DEBUG ( 27): bef5068c 00000000I/DEBUG ( 27): #01 bef50690 41295860 /dev/ashmem/dalvik-LinearAlloc (deleted)I/DEBUG ( 27): bef50694 0000bc60 [heap]I/DEBUG ( 27): bef50698 80600ba1 /data/data/com.example.hellogdbserver/lib/libhello-gdbserver.soI/DEBUG ( 27): bef5069c 4376e278 /dev/ashmem/mspace/dalvik-heap/2 (deleted)I/DEBUG ( 27): bef506a0 00000071I/DEBUG ( 27): bef506a4 0000bc60 [heap]I/DEBUG ( 27): bef506a8 bef506b0 [stack]I/DEBUG ( 27): bef506ac ad040b11 /system/lib/libdvm.soD/Zygote ( 29): Process 260 terminated by signal (11)I/WindowManager( 67): WIN DEATH: Window{437ee360 com.example.hellogdbserver/com.example.hellogdbserver.HelloGdbServer paused=false}I/ActivityManager( 67): Process com.example.hellogdbserver (pid 260) has died.
The Google guys have a page describing how to transcribe that stuff back into meaningful information, but it’s long-winded, manual, and from a practical standpoint a waste of time.
The Fix
Step 1. Tell the gcc C compiler to add debug symbols to your code
In Android.mk add the following line:
1 LOCAL_CFLAGS := -g
Problem 1. Android Ignores You
Oddly enough, even with the debug flag set, you’ll notice that the final step of ndk-build, the Install step, copies and then strips your binaries of debug information. Not very helpful, that. Just run the ndk-build script with verbose mode active, V=1, and you’ll see something like this:
1234 Install : libhello-gdbserver.so => /libs/armeabimkdir -p /libs/armeabiinstall -p /libhello-gdbserver.so /libs/armeabi/libhello-gdbserver.so/arm-eabi-4.4.0/bin/arm-eabi-strip --strip-debug /libs/armeabi/libhello-gdbserver.so
which is due to a line in the setup.mk Makefile fragment:
12 build/toolchains/arm-eabi-4.4.0/setup.mk:188:cmd-strip = $(TOOLCHAIN_PREFIX)strip --strip-debug $1
That last line kills your debugging symbols.
Step 2. Ignore Android
So you have to edit it out, as a quick hack, in the install-binary.mk Makefile fragment:
12 build/core/install-binary.mk:29:# $(hide) $(call cmd-strip, $(PRIVATE_DST))
A better fix would be to add a real variable check in the Makefile for debug vs. non debug builds and to act accordingly. In any case, your next builds will have full debug symbols in them. So just do a quick
1 $ ndk-build -B V=1
[update: 2010/09/24]
A better fix:
1234 build/core/install-binary.mk:29:ifneq ($(APP_OPTIM),debug)$(hide) $(call cmd-strip, $(PRIVATE_DST))endif
Now when you’re building, you can just specify the APP_OPTIM level as a parameter to ndk-build:
12 ~/android-ndk-r4b/ndk-build -B V=1 APP_OPTIM=debug~/android-ndk-r4b/ndk-build -B V=1 APP_OPTIM=release
This is also useful because APP_OPTIM can be specified in the Application.mk file.
Step 3. Rebuild Your APK
Ok, so once you have the shared object built, it’s time to package it into an APK using Eclipse. This is pretty standard. Since the ndk-build has “installed” the libhello-gdbserver.so shared object to the right directory, just do a Build -> Clean, Build -> Rebuild All in Eclipse and wait the half a second it takes to regenerate the APK.
Try running the application, you should see this:
Then, still in the project’s directory, call ndk-gdb.
123 $ pwd/home/vilimpoc/android-ndk-r4b/samples/hello-gdbserver$ ~/android-ndk-r4b/ndk-gdb --verbose
Fun Error Message 1
1234567891011121314 Android NDK installation path: /home/vilimpoc/android-ndk-r4bUsing default adb command: /cygdrive/c/androidDev/android-sdk-windows/tools/adbADB version found: Android Debug Bridge version 1.0.26Using final ADB command: '/cygdrive/c/androidDev/android-sdk-windows/tools/adb -e'Using auto-detected project path: .Found package name: com.example.hellogdbserverFound debuggable flag: trueABIs targetted by application: armeabiDevice API Level: 8Device CPU ABI: armeabiCompatible device ABI: armeabi<span style="color: #ff0000;">Found device gdbserver: /data/data/com.example.hellogdbserver/lib/gdbserver: No such file or directoryERROR: Non-debuggable application installed on the target device.Please re-install the debuggable version !</span>
Make sure in AndroidManifest.xml, you’ve got Debuggable set to true. Rebuild and reinstall.
Fun Error Message 2
1 $ run-as: Package 'com.example.hellogdbserver' has corrupt installation
Rebuild and reinstall.
12 adb uninstall com.example.hellogdbserveradb install HelloGdbServer.apk
Fun Error Message 3
Sometimes the above message looks like the following, where the information gets mashed up wrongly into the verbose output from ndk-gdb. e.g. the string “run-as: Package ‘com.example.hellogdbserver’ has corrupt installation” was variable-substituted into the command to forward debug information over tcp/5039.
123456 ##### NEW COMMAND/cygdrive/c/androidDev/android-sdk-windows/tools/adb -e forward tcp:5039 localfilesystem:run-as: Package 'com.example.hellogdbserver' has corrupt installation/debug-socket##### NEW COMMAND/cygdrive/c/androidDev/android-sdk-windows/tools/adb -e shell run-as com.example.hellogdbserver lib/gdbserver +debug-socket--attach 7492Android Debug Bridge version 1.0.26
1234 -d - directs command to the only connected USB devicereturns an error if more than one USB device is present.-e - directs command to the only running emulator.returns an error if more than one emulator is running.
1 [... snip ...]
1234 - If it is "system" or "data", only the corresponding partitionis updated.ERROR: Could not setup network redirection to gdbserver?Maybe using --port=<port> to use a different TCP port might help?
The solution remains the same: Rebuild APK and reinstall.
Fun Error Message 4
1 <span style="color: #000000;">run-as: Package 'com.example.hellogdbserver' is unknown</span>
Sometimes you must Clean and Rebuild your entire project in Eclipse, especially if you make a dumb mistake, like change your Java Package from “com.examples.hellogdbserver” to “com.example.hellogdbserver”. Sometimes that slight change doesn’t quite make it into the package, or the aapt package manager doesn’t see it, and you end up with an application running under a package name that isn’t what you expect, and isn’t one that run-as can find. Try adb install / uninstalling a couple of times, or uninstalling via the phone’s Settings -> Applications menu to get the app into a state where the phone recognizes the package.
The rule of thumb is: If adb install/uninstall can see your program by its package name, then so can gdb.
When It Works, It Looks Like This
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 vilimpoc@funky ~$ lsandroid-ndk-r4b cygdrivevilimpoc@funky ~$ cd android-ndk-r4b/vilimpoc@funky ~/android-ndk-r4b$ lsGNUmakefile README.TXT apps build docs ndk-build ndk-gdb out samples sourcesvilimpoc@funky ~/android-ndk-r4b$ cd samplesvilimpoc@funky ~/android-ndk-r4b/samples$ lsbitmap-plasma hello-exe hello-gdbserver hello-gl2 hello-jni hello-neon san-angeles two-libsvilimpoc@funky ~/android-ndk-r4b/samples$ cd hello-gdbservervilimpoc@funky ~/android-ndk-r4b/samples/hello-gdbserver$ ls -ltotal 5-rwx------+ 1 vilimpoc Domain Users 721 2010-09-23 16:15 AndroidManifest.xmldrwx------+ 1 vilimpoc Domain Users 0 2010-09-23 15:12 assetsdrwx------+ 1 vilimpoc Domain Users 0 2010-09-23 17:24 bin-rwx------+ 1 vilimpoc Domain Users 364 2010-09-23 15:12 default.propertiesdrwx------+ 1 vilimpoc Domain Users 0 2010-09-23 15:12 gendrwx------+ 1 vilimpoc Domain Users 0 2010-09-23 16:20 jnidrwxr-xr-x+ 1 vilimpoc Domain Users 0 2010-09-23 15:23 libsdrwxr-xr-x+ 1 vilimpoc Domain Users 0 2010-09-23 15:23 objdrwx------+ 1 vilimpoc Domain Users 0 2010-09-23 15:13 resdrwx------+ 1 vilimpoc Domain Users 0 2010-09-23 14:49 srcvilimpoc@funky ~/android-ndk-r4b/samples/hello-gdbserver$ ~/android-ndk-r4b/ndk-gdb --verboseAndroid NDK installation path: /home/vilimpoc/android-ndk-r4bUsing default adb command: /cygdrive/c/androidDev/android-sdk-windows/tools/adbADB version found: Android Debug Bridge version 1.0.26Using final ADB command: '/cygdrive/c/androidDev/android-sdk-windows/tools/adb'Using auto-detected project path: .Found package name: com.example.hellogdbserverFound debuggable flag: trueABIs targetted by application: armeabiDevice API Level: 8Device CPU ABIs: armeabi-v7a armeabiCompatible device ABI: armeabiFound device gdbserver: /data/data/com.example.hellogdbserver/lib/gdbserverUsing gdb setup init: /home/vilimpoc/android-ndk-r4b/samples/hello-gdbserver/libs/armeabi/gdb.setupUsing toolchain prefix: /home/vilimpoc/android-ndk-r4b/build/prebuilt/windows/arm-eabi-4.4.0/bin/arm-eabi-Using app out directory: /home/vilimpoc/android-ndk-r4b/samples/hello-gdbserver/obj/local/armeabiFound data directory: '/data/data/com.example.hellogdbserver'Found first launchable activity: .HelloGdbServerLaunching activity: com.example.hellogdbserver/.HelloGdbServer##### NEW COMMAND/cygdrive/c/androidDev/android-sdk-windows/tools/adb shell am start -n com.example.hellogdbserver/.HelloGdbServerStarting: Intent { cmp=com.example.hellogdbserver/.HelloGdbServer }##### NEW COMMAND/cygdrive/c/androidDev/android-sdk-windows/tools/adb shell sleep 1Found running PID: 1948Launching gdbserver.Launched gdbserver successfully.Setup network redirection##### NEW COMMAND##### NEW COMMAND/cygdrive/c/androidDev/android-sdk-windows/tools/adb shell run-as com.example.hellogdbserver lib/gdbserver +debug-socket --a/cygdrive/c/androidDev/android-sdk-windows/tools/adb forward tcp:5039 localfilesystem:/data/data/com.example.hellogdbserver/debug-socketAttached; pid = 1948Listening on sockaddr socket debug-socket##### NEW COMMAND/cygdrive/c/androidDev/android-sdk-windows/tools/adb pull /system/bin/app_process C:/cygwin/home/vilimpoc/android-ndk-r4b/samples/hello-gdbserver/obj/local/armeabi/app_process5 KB/s (0 bytes in 5680.001s)Pulled from device/emulator.GNU gdb 6.6Copyright (C) 2006 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "--host=i686-pc-cygwin --target=arm-elf-linux".Error while mapping shared library sections:/system/bin/linker: No such file or directory.Error while mapping shared library sections:libc.so: No such file or directory.Error while mapping shared library sections:libstdc++.so: No such file or directory.Error while mapping shared library sections:libm.so: No such file or directory.Error while mapping shared library sections:liblog.so: No such file or directory.Error while mapping shared library sections:libcutils.so: No such file or directory.Error while mapping shared library sections:libz.so: No such file or directory.Error while mapping shared library sections:libutils.so: No such file or directory.Error while mapping shared library sections:libbinder.so: No such file or directory.Error while mapping shared library sections:libexpat.so: No such file or directory.Error while mapping shared library sections:libcrypto.so: No such file or directory.Error while mapping shared library sections:libssl.so: No such file or directory.Error while mapping shared library sections:libicudata.so: No such file or directory.Error while mapping shared library sections:libicuuc.so: No such file or directory.Error while mapping shared library sections:libicui18n.so: No such file or directory.Error while mapping shared library sections:libsqlite.so: No such file or directory.Error while mapping shared library sections:libnativehelper.so: No such file or directory.Error while mapping shared library sections:libnetutils.so: No such file or directory.Error while mapping shared library sections:libEGL.so: No such file or directory.Error while mapping shared library sections:libwpa_client.so: No such file or directory.Error while mapping shared library sections:librpc.so: No such file or directory.Error while mapping shared library sections:libgps.so: No such file or directory.Error while mapping shared library sections:libhardware_legacy.so: No such file or directory.Error while mapping shared library sections:libpixelflinger.so: No such file or directory.Error while mapping shared library sections:libhardware.so: No such file or directory.Error while mapping shared library sections:libui.so: No such file or directory.Error while mapping shared library sections:libsurfaceflinger_client.so: No such file or directory.Error while mapping shared library sections:libcamera_client.so: No such file or directory.Error while mapping shared library sections:libemoji.so: No such file or directory.Error while mapping shared library sections:libjpeg.so: No such file or directory.Error while mapping shared library sections:libskia.so: No such file or directory.Error while mapping shared library sections:libGLESv1_CM.so: No such file or directory.Error while mapping shared library sections:libskiagl.so: No such file or directory.Error while mapping shared library sections:libdvm.so: No such file or directory.Error while mapping shared library sections:libGLESv2.so: No such file or directory.Error while mapping shared library sections:libETC1.so: No such file or directory.Error while mapping shared library sections:libsonivox.so: No such file or directory.Error while mapping shared library sections:libmedia.so: No such file or directory.Error while mapping shared library sections:libbluedroid.so: No such file or directory.Error while mapping shared library sections:libdbus.so: No such file or directory.Error while mapping shared library sections:libandroid_runtime.so: No such file or directory.Error while mapping shared library sections:libexif.so: No such file or directory.Error while mapping shared library sections:libdrm1.so: No such file or directory.Error while mapping shared library sections:libvorbisidec.so: No such file or directory.Error while mapping shared library sections:libopencore_common.so: No such file or directory.Error while mapping shared library sections:libopencore_net_support.so: No such file or directory.Error while mapping shared library sections:libopencore_player.so: No such file or directory.Error while mapping shared library sections:libomx_sharedlibrary.so: No such file or directory.Error while mapping shared library sections:libomx_amrenc_sharedlibrary.so: No such file or directory.Error while mapping shared library sections:libstagefright_amrnb_common.so: No such file or directory.Error while mapping shared library sections:libstagefright_avc_common.so: No such file or directory.Error while mapping shared library sections:libstagefright_color_conversion.so: No such file or directory.Error while mapping shared library sections:libstagefright.so: No such file or directory.Error while mapping shared library sections:libmedia_jni.so: No such file or directory.Error while mapping shared library sections:libstlport.so: No such file or directory.Error while mapping shared library sections:libwebcore.so: No such file or directory.Error while mapping shared library sections:gralloc.qsd8k.so: No such file or directory.warning: Unable to find dynamic linker breakpoint function.GDB will be unable to debug shared library initializersand track explicitly loaded dynamic code.warning: shared library handler failed to enable breakpoint0xafd0ebd8 in ?? ()(gdb) continueContinuing.
1 <span style="color: #ff0000;"> </span>
Tap the “Induce Crash” button. gdb should immediately produce the following:
123456789 <span style="color: #ff0000;">Program received signal SIGSEGV, Segmentation fault.0x80300bae in Java_com_example_hellogdbserver_HelloGdbServer_invokeCrash (env=0xaa50, clazz=0x4625f0b8)at /home/vilimpoc/android-ndk-r4b/samples/hello-gdbserver/jni/hello-gdbserver.c:2929 *crasher = 0xdeaddead;<span style="color: #000000;">(gdb)</span></span>
Rejoice In No Longer Needing __android_log_print()
Hallelujah! Usable segmentation fault information. Finally, one can get rid of all those debug print statements!
Questions / Feedback / Code Fail?
File them in the comments and I’ll update the above. Thanks!
really thx for this! you forgot that user need type “continue” after
“warning: shared library handler failed to enable breakpoint
0xafd0ebd8 in ?? ()
(gdb)”
to continue with debug
Why does this require Android 2.2 (Froyo)? What prevents this from working on earlier versions?
There’s probably some additional stuff they had to add to the base system images to enable this. There’s some discussion of the ndk-gdb requirements in NDK-GDB.html.
Thanks for the example, it was very useful.
I have a strange problem though, I was always getting Fun Error Message 4 for my application, even after lots of reinstalling and messing about. Then I renamed my package to com.example.hellogdbserver (the same as your example) and then it works. Conversely, renaming your example package to anything other than com.example.hellogdbserver stops it from working.
I’ve been scouring through the projects for hours and can’t see any settings which would account for this behaviour.
I then tried it on another phone, going through the steps carefully and can’t get anything to run at all, not even your sample.
On an emulator however it works straight away.
Anyone else seen a similar problem?
You might have to grep through the project directory to see where the various package names and class names are being used. I know I made a similar change (e.g. renamed a class or the project) at some point and had to do this to get it to work.
I got it working on my phone in the end by renaming the project package to be an extra level deep (i.e. com.first.second.third rather than com.first.second). I tried calling run-as on various applications on my phone through adb and I still can’t find a definite pattern as to which ones work and which don’t.
If the value int *crasher = 0x0; was changed to 0x1 would this
signal 11 (SIGSEGV), fault addr 00000000
change to
signal 11 (SIGSEGV), fault addr 00000001
meaning that a fault addr of 0000000 would mean someone was assigning something to NULL?
Yes.
Hi,
Thanks a lot for the article ! It worked fine with your example, and I could play for a while with it.
But during my tests, I tried using a bit of C++ (to see how class / method debugging was working with gdb)
Hi again … seems my comment got html filtered :s
I was saying that I could use gdb with your example without any problem, but as soon as I add a .cpp / .h files, gdb doesn’t work anymore.
I don’t understand why … I copied the CFLAGS into the CPPFLAGS to make sure .cpp files were compiled with the same debug informations, but it still didn’t work …
Any idea what I might be doing wrong ? If you need details, please drop me a mail, I’ll send your the modified example I’m using and the errors I get 🙂
Thanks in advance !
Hi ! In case someone has the same difficulty as I had, to correct the problem, I had to add
extern “C”
before my c function in the .cpp file to make it “visible” by gdb. Then I could debug everything, and even add other cpp files with classes, etc.
In the r5b release of the NDK, the file that you do the APP_OPTIM hack on has been renamed to build/core/build-binary.mk.
In my opinion, Google should make your APP_OPTIM hack a standard feature of the next release of the NDK!
A couple things to note. ndk-gdb REALLY doesn’t like having any spaces in the adb path. Since my sdk is installed in Program Files, I had to create a symbolic link to make sure the path had no spaces in it.
If your native library is part of an Android library that links with your application, you need to change PACKAGE_NAME in ndk-gdb (line 332 for me) to be the package name of the application (it tries to use the package of the Android library that owns the native code). Otherwise it won’t be able to find and attach to your application.
Great tutorial! Just a note to add. If you are using Android Libraries that link to your main application and your JNI code is in the library, you will run into naming problem where when you execute ndk-gdb you will get the error that the application has not been started even when it is running. You will need to edit ndk-gdb. Find the line:
PACKAGE_NAME=
run_awk_manifest_script extract-package-name.awk
and change it to:
PACKAGE_NAME=”complete namespace of your application”
Then it will see that your app is running!
In Android 2.2 it’s possible to debug only main thread. Multithreading gdb support is avaiable from 2.3(see ndk docs)
Also for debugging it’s better to use Sequoyah plugin for eclipse – it allows you to convinient interact with gdbserver, debugging native code similar to java code.