Tuesday, January 11, 2011

Android Debugging, Visual Studio style!

UPDATE: More recent beta versions of wingdb make these instructions obsolete. Try it here.

The high point of my week, courtesy of the good people at www.wingdb.com... (click to enlarge)


Full Android NDK debugging in Visual Studio. This is using version 1.8, which is kind of tricky to set up--mad props to the WinGDB support folks who walked me through it. Version 2.0 is coming soon, though, and according to WinGDB, they will have full support for Android NDK.

For the curious, here's how I got this working.  If you want to try this, do so at your own risk and please don't go bugging the WinGDB folks about it; they're busy enough working on version 2.0 and they don't need anything slowing them down! For this example, I'm using the project I described in an earlier post.
  1. First, install all of the normal prerequisites--Cygwin, Android SDK, and Android NDK. I'm using the latest Android stuff, which as of now is SDK tools r8 and NDK r5. Install Visual Studio and WinGDB as well. Run "android.bat" and make sure everything is up to date. You might also want to set the environment variables ANDROID_SDK and ANDROID_NDK to point to the root of the SDK and NDK, respectively.
  2. Since the current WinGDB build was based on the previous SDK, you'll need to copy adb.exe back to where it used to be in the old SDK: copy %ANDROID_SDK%\platform-tools\adb.exe %ANDROID_SDK%\tools
  3. Create an NDK project (or use one of the samples). Build the project using ndk-build. Then, run ndk-gdb --start. This will set up the files that gdb needs to see in order for WinGDB to attach. As soon as the gdb prompt appears, type quit to dismiss it. Elsewhere in these instructions I'll assume that the environment variable PROJECT_ROOT points to the root directory of your project (where AndroidManifest.xml lives).
  4. Regedit time! You need to add an entry for "AndroidSDKPath" to WinGDB/Preferences/General. The exact location of this key will vary depending on your OS. I have 64-bit Windows7 so mine shows up under HKLM/SOFTWARE/Wow6432Node. YMMV. In any case, the value for AndroidSDKPath should be the full path to wherever you installed the Android SDK, like so:
  5. In Visual Studio, open the WinGDB preferences dialog (choose WinGDB|Preferences... from the main menu). Set the following options:
    • Default debugger path: %ANDROID_NDK%\toolchains\arm-eabi-4.4.0\prebuilt\windows\bin\arm-eabi-gdb.exe
    • Use Cygwin mode for local sessions: yes
    • Cygwin installation (root) path: wherever you installed this (default is c:\cygwin)
  6. Dismiss the preferences dialog. 
  7. From the Visual Studio main menu, select WinGDB|Attach to process...
  8. Set the following options (you should only need to do this once):
    • Target type: Embedded Linux System (gdbserver)
    • Executable path: <path to your project>\obj\local\armeabi\app_process
    • Target login: <your device id>:adb (or emulator:adb if you're using the emulator)
  9. Press the "Advanced Settings..." button. In the Advanced Settings dialog, set the following options:
    1. Environment tab
      • Debugger path: %ANDROID_NDK%\toolchains\arm-eabi-4.4.0\prebuilt\windows\bin\arm-eabi-gdb.exe
    2. Directories tab
      • Additional source directories: %ANDROID_NDK%\platforms\android-9\arch-arm
      • Shared library directories: %ANDROID_NDK%\platforms\android-9\arch-arm\usr\lib;%PROJECT_ROOT%\obj\local\armeabi
    3. Target tab
      • Sysroot on host: /cygdrive/c/sdk/android-ndk-r5/platforms/android-9/arch-arm (notice that this has to be in Cygwin path format, so I can't use %ANDROID_NDK%. In this case my ndk is installed under c:\sdk\android-ndk-r5, which in Cygwin turns into /cygdrive/c/sdk/android-ndk-r5. You'll need to change that to whatever your local NDK path is in Cygwinese.)
    4. Server tab
      • Launch server from sysroot: no
      • Path to gdbserver: /system/bin/gdbserver
      • Server port: an unused IP port (I used 1100)
      • Server port is forwarded: yes
      • Forwarded server port: another unused port (in my case, 11000).
  10. Check "Save these settings as project defaults" unless you enjoy typing them in over and over again. (Yeah, I learned that the hard way.)
  11. Dismiss the Advanced Settings dialog.
  12. Back in the Attach to remote process dialog, check "Show processes from all users."
  13. If you don't see any processes, click Refresh. You should see a long list of processes that are running on your device or emulator. User processes are listed by package name, so search for your package name and select it.

  14. Click the Attach button and wait a bit
  15. You'll see a message box warning you that there are no debug symbols in the executable. Dismiss it. It's true that the executable on the device doesn't have symbols that WinGDb can use; that's why you set up the shared libraries directory back in step 9.2.
  16. Set a breakpoint and enjoy!
To debug again, just repeat from step 12. You'll only need to fiddle with the settings again if you switch to a new project, in which case you'll probably need to adjust the paths that are relative to your project root.

As far as I can tell, WinGDB works pretty well. I was able to set breakpoints, step through code, and use the watch window. There are limitations, of course; I was only able to attach to processes, not launch them, and the "autos" window didn't work, for instance. But just having the ability to debug in my favorite environment... that made my week.

Just a reminder, what I've described in this post is not a supported use of WinGDB 1.8! Don't go emailing WinGDB asking them to fix things they don't officially support; that's just not cool. (If you do have problems, though, leave a comment here--I can't promise to solve it, but I or some other reader may be able to.)

Good luck and let me know if you find this useful.

13 comments:

  1. Thanks a lot for this, it's great. I'd tried recently to use the unixey 'DDD' debugger with GDB, but that pretty much crashed every time before I could do anything useful with it.

    You mentioned in one of your other posts about using MSBuild to compile NDK code. I've put something together to do this, hopefully you'll find it handy too:
    http://code.google.com/p/vs-android/

    Cheers.

    ReplyDelete
  2. @Gavin: This is sweet! A lot simpler than I thought it would be, too. The Microsoft instructions, which we followed for our Native Client VS integration (nativeclient-vsx.googlecode.com) are a lot more involved, and I was kind of dreading the task of porting our stuff over for Android.

    Might still do it, though--the NaCl stuff has a full gdb-compatible debugger built in, which removes the need to use a gdb.exe at all. It speaks gdb-rsp, so it should work with the android gdbserver.

    ReplyDelete
  3. Great job, Ian!

    I tried to follow the way you wrote here with WinGDB version 1.91.588, 30 day trial version, VS 2008. But at the very end, when all seems to be working just fine, I encounter a weird issue. Just as I attach to my process running in Emulator, an error falls:

    "warning: shared library handler failed to enable breakpoint
    Breakpoint 1 at 0xa8c"

    This is the first thing I see upon attach - so surely no breakpoints set from my side. It seems trying to push some unknown breakpoint on its own, heh. But at the same time it opens a correct source file from my app, but instruction pointer gets stuck on some function. Every time I try to Continue or Step over the same error falls back, just on every tick.

    If you get any ideas of what is going on I will really appreciate it. Or even some thoughts or hints might be usefull too.

    And one more thing I spotted - you wrote in point 3: "As soon as the gdb prompt appears". I get no gdb prompts appeared - the application just starts in emulator and I get back to bash shell after "ndk-gdb --start" completes, without any errors or messages. Something wrong with GDB environment setup maybe? But all the rest works just as you say in you article.

    I got the "debuggable" flag set to true in manifest file, and compile my C code with "LOCAL_CFLAGS := -g" options, so all seems good to debug. Any ideas?

    Thanks in advance! Oleg.

    ReplyDelete
  4. @Oleg: I don't know for sure. My setup was different from yours in several ways:
    1. WinGDB 1.8
    2. VS 2010
    3. Nexus S hardware, not emulator

    GDB tries to set breakpoints in things like the .so loader and thread startup routines so that it can monitor when threads and libs get added--that might be where your mystery breakpoint is coming from.

    Your comment on step 3 sounds like something is definitely wrong with your ndk-gdb setup. If you don't get a gdb prompt in step 3 nothing else is going to work. Try running ndk-gdb --verbose. The verbose spew is really helpful.

    Good luck!
    Ian

    ReplyDelete
  5. @Oleg: Step 3 is something you only need to do once. It sets up the environment and copies some files into the places where WinGDB expects to find them. That's why you quit out of the debugger immediately in step 3--the point wasn't to launch the debugger and do actual work, the point was to launch (and verify) the ndk-gdb setup process.

    ReplyDelete
  6. @Ian: Did you end out trying Gavins vs-android environment?
    The reason I ask, is it seems to be incompatible with this guide...
    I follow all the steps and it all seems to go well, except when I try to attach, it says:
    Could not start gdbserver
    /system/bin/gdbserver: not found

    This is obviously because step 3 fails when using vs-android, since 'ndk-gdb --start' doesn't work in the context of a vs-android project.
    It errors with:
    /home/manue/android-ndk-r5c/build/core/add-application.mk:116: *** Android NDK:
    Aborting... . Stop.
    ERROR: The device does not support the application's targetted CPU ABIs!
    Device supports: armeabi-v7a armeabi
    Package supports: Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: /cygdrive/w/dr/android/[ProjectName]/Trunk/jni/Android.mk

    The missing makefile seems to be the problem.
    Can you suggest what I need to do to fix this problem in the context of vs-android?

    @Gavin: Perhaps it'd be good to put a modified version of this guide on the vs-android wiki detailing any different steps required to get it working in the visual studio context?

    Cheers guys!!

    ReplyDelete
  7. @Manu: right, these instructions are definitely not compatible with vs-android. However, I did send the WinGDB guys a link to vs-android and their most recent beta release says it has added some support for vs-android.

    ReplyDelete
  8. Actually, it seems they don't support vs-android... instead they rolled their own set of build scripts (which the debugger is tuned to work with), which don't seem to be as complete as vs-android, and it also doesn't help me too much, since I've spent the past 2 weeks setting our (quite large) project up to compile and run under vs-android >_<
    So I guess I'll keep hacking away at your guide here and see if I can make the debugger work in the context of vs-android... it's close, just a few things missing :/

    @Gavin (If you're reading): Did you ever have a go at this tutorial with your stuff? How did you fare?

    ReplyDelete
  9. I guess that's not too shocking. VS debugger integration is annoying--it almost almost works, but not quite. For instance, as far as I can tell, there is literally no way to get F5 to work without completely replacing the project/build system.

    ReplyDelete
  10. This is one of the best blogs I have ever come across.!!!!
    Cheers dude !
    Web Shopping Cart | Free Ecommerce Software

    ReplyDelete
  11. Some how wingdb installer with fail and rollback with my Win7 Ultra system (VS2010).
    BTW, Is there any way to import current eclipse android project to VS sln?

    ReplyDelete
  12. Did any of you got to make it work with vs-android?
    Thanks!

    ReplyDelete

Submit comments here. Be nice.