Proper thread support for gdbserver.

WARNING: DEEP MAGIC AHEAD!

This patch allows the gdbserver binary that we build for the
NDK to properly support threads on Android 2.3 and higher.

For previous platforms, the binary will still be limited to
to only set breakpoints on the main thread (just like with
previous NDK releases).

The root cause of the problem is a platform bug that was only
fixed in Android 2.3, so there is little we can do in the NDK
to fix it (apart from hoping the fix is back-ported properly).

Now the hairy details:

- The patch provides sources for libthread_db.a which will
  get recompiled explicitely by build-gdbserver.sh.

  Note that libthread_db has no real stable ABI/API so we
  provide GDB version-specific implementations here
  (see sources/android/libthread_db/gdb-<version>)

- Both libthread_db.c versions have been modified to probe
  the system at runtime and detect if the platform bug is in
  effect.

  If it is, the library acts as if there are no threads in the
  process. The reason for this behaviour (i.e. instead of
  patching the gdbserver sources) is explained in comments
  inside libthread_db.c.

+ Local patches to make signal handling and libthread_db support work
  properly with gdbserver 6.6.

Change-Id: Idf3d71422d337f4384f51ca45cafe7f71fd8559d
diff --git a/build/tools/build-gdbserver.sh b/build/tools/build-gdbserver.sh
index 94f2094..2e43ff1 100755
--- a/build/tools/build-gdbserver.sh
+++ b/build/tools/build-gdbserver.sh
@@ -30,32 +30,36 @@
 <ndk-dir> is the top-level NDK installation path and <toolchain>
 is the name of the toolchain to use (e.g. arm-eabi-4.4.0).
 
+The final binary is placed under:
+
+    <ndk-dir>/toolchains <toolchain>/prebuilt/gdbserver
+
 NOTE: The --platform option is ignored if --sysroot is used."
 
-RELEASE=`date +%Y%m%d`
-BUILD_OUT=`random_temp_directory`
-PLATFORM=android-3
 VERBOSE=no
-JOBS=$HOST_NUM_CPUS
 
-OPTION_HELP=no
 OPTION_BUILD_OUT=
-OPTION_SYSROOT=
+BUILD_OUT=`random_temp_directory`
+register_option "--build-out=<path>" do_build_out "Set temporary build directory" "/tmp/<random>"
+do_build_out () { OPTION_BUILD_OUT="$1"; }
+
+PLATFORM=android-3
+register_var_option "--platform=<name>"  PLATFORM "Target specific platform"
 
 SYSROOT=
 if [ -d $TOOLCHAIN_PATH/sysroot ] ; then
   SYSROOT=$TOOLCHAIN_PATH/sysroot
 fi
+register_var_option "--sysroot=<path>" SYSROOT "Specify sysroot directory directly"
 
-register_option "--build-out=<path>" do_build_out "Set temporary build directory" "/tmp/random"
-register_option "--platform=<name>"  do_platform  "Target specific platform" "$PLATFORM"
-register_option "--sysroot=<path>"   do_sysroot   "Specify sysroot directory directly [$SYSROOT]."
-register_option "-j<number>"         do_jobs      "Use <number> build jobs in parallel" "$JOBS"
+NOTHREADS=no
+register_var_option "--disable-threads" NOTHREADS "Disable threads support"
 
-do_build_out () { OPTION_BUILD_OUT=$1; }
-do_platform () { OPTION_PLATFORM=$1; }
-do_sysroot () { OPTION_SYSROOT=$1; }
-do_jobs () { JOBS=$1; }
+JOBS=$HOST_NUM_CPUS
+register_var_option "-j<number>" JOBS "Use <number> build jobs in parallel"
+
+GDB_VERSION=6.6
+register_var_option "--gdb-version=<name>" GDB_VERSION "Use specific gdb version."
 
 extract_parameters $@
 
@@ -74,8 +78,14 @@
         exit 1
     fi
 
+    SRC_DIR2="$SRC_DIR/gdb/gdb-$GDB_VERSION/gdb/gdbserver"
+    if [ -d "$SRC_DIR2" ] ; then
+        SRC_DIR="$SRC_DIR2"
+        log "Found gdbserver source directory: $SRC_DIR"
+    fi
+
     if [ ! -f "$SRC_DIR/gdbreplay.c" ] ; then
-        echo "ERROR: Source directory does not contain gdb sources: $SRC_DIR"
+        echo "ERROR: Source directory does not contain gdbserver sources: $SRC_DIR"
         exit 1
     fi
 
@@ -112,37 +122,86 @@
 
 # Check build directory
 #
-fix_option BUILD_OUT "$OPTION_BUILD_OUT" "build out directory"
-fix_option PLATFORM "$OPTION_PLATFORM" "platform"
-fix_sysroot "$OPTION_SYSROOT"
+fix_sysroot "$SYSROOT"
+log "Using sysroot: $SYSROOT"
+
+if [ -n "$OPTION_BUILD_OUT" ] ; then
+    BUILD_OUT="$OPTION_BUILD_OUT"
+fi
+log "Using build directory: $BUILD_OUT"
+run mkdir -p "$BUILD_OUT"
+
+# Copy the sysroot to a temporary build directory
+BUILD_SYSROOT="$BUILD_OUT/sysroot"
+run mkdir -p "$BUILD_SYSROOT"
+run cp -rp "$SYSROOT/*" "$BUILD_SYSROOT"
+
+# Remove libthread_db to ensure we use exactly the one we want.
+rm -f $BUILD_SYSROOT/usr/lib/libthread_db*
+rm -f $BUILD_SYSROOT/usr/include/thread_db.h
+
+if [ "$NOTHREADS" != "yes" ] ; then
+    # We're going to rebuild libthread_db.o from its source
+    # that is under sources/android/libthread_db and place its header
+    # and object file into the build sysroot.
+    LIBTHREAD_DB_DIR=$ANDROID_NDK_ROOT/sources/android/libthread_db/gdb-$GDB_VERSION
+    if [ ! -d "$LIBTHREAD_DB_DIR" ] ; then
+        dump "ERROR: Missing directory: $LIBTHREAD_DB_DIR"
+        exit 1
+    fi
+    # Small trick, to avoid calling ar, we store the single object file
+    # with an .a suffix. The linker will handle that seamlessly.
+    run cp $LIBTHREAD_DB_DIR/thread_db.h $BUILD_SYSROOT/usr/include/
+    run $TOOLCHAIN_PREFIX-gcc --sysroot=$BUILD_SYSROOT -o $BUILD_SYSROOT/usr/lib/libthread_db.a -c $LIBTHREAD_DB_DIR/libthread_db.c
+    if [ $? != 0 ] ; then
+        dump "ERROR: Could not compile libthread_db.c!"
+        exit 1
+    fi
+fi
+
+log "Using build sysroot: $BUILD_SYSROOT"
 
 # configure the gdbserver build now
-dump "Configure: $TOOLCHAIN gdbserver build."
-run mkdir -p $BUILD_OUT
+dump "Configure: $TOOLCHAIN gdbserver-$GDB_VERSION build."
 OLD_CC="$CC"
 OLD_CFLAGS="$CFLAGS"
 OLD_LDFLAGS="$LDFLAGS"
 
 INCLUDE_DIRS=\
 "-I$TOOLCHAIN_PATH/lib/gcc/$ABI_CONFIGURE_TARGET/$GCC_VERSION/include \
--I$SYSROOT/usr/include"
-CRTBEGIN="$SYSROOT/usr/lib/crtbegin_static.o"
-CRTEND="$SYSROOT/usr/lib/crtend_android.o"
+-I$BUILD_SYSROOT/usr/include"
+CRTBEGIN="$BUILD_SYSROOT/usr/lib/crtbegin_static.o"
+CRTEND="$BUILD_SYSROOT/usr/lib/crtend_android.o"
 
 # Note: we must put a second -lc after -lgcc to resolve a cyclical
 #       dependency on arm-linux-androideabi, where libgcc.a contains
 #       a function (__div0) which depends on raise(), implemented
 #       in the C library.
 #
-LIBRARY_LDFLAGS="$CRTBEGIN -L$SYSROOT/usr/lib -lc -lm -lgcc -lc $CRTEND "
+LIBRARY_LDFLAGS="$CRTBEGIN -lc -lm -lgcc -lc $CRTEND "
+
+case "$GDB_VERSION" in
+    6.6)
+        CONFIGURE_FLAGS="--with-sysroot=$BUILD_SYSROOT"
+        ;;
+    7.1.x)
+        # This flag is required to link libthread_db statically to our
+        # gdbserver binary. Otherwise, the program will try to dlopen()
+        # the threads binary, which is not possible since we build a
+        # static executable.
+        CONFIGURE_FLAGS="--with-libthread-db=$BUILD_SYSROOT/usr/lib/libthread_db.a"
+        ;;
+    *)
+        CONFIGURE_FLAGS=""
+esac
 
 cd $BUILD_OUT &&
-export CC="$TOOLCHAIN_PREFIX-gcc" &&
+export CC="$TOOLCHAIN_PREFIX-gcc --sysroot=$BUILD_SYSROOT" &&
 export CFLAGS="-O2 -nostdinc -nostdlib -D__ANDROID__ -DANDROID -DSTDC_HEADERS $INCLUDE_DIRS $GDBSERVER_CFLAGS"  &&
 export LDFLAGS="-static -Wl,-z,nocopyreloc -Wl,--no-undefined $LIBRARY_LDFLAGS" &&
 run $SRC_DIR/configure \
 --host=$GDBSERVER_HOST \
---with-sysroot=$SYSROOT
+$CONFIGURE_FLAGS
 if [ $? != 0 ] ; then
     dump "Could not configure gdbserver build. See $TMPLOG"
     exit 1
@@ -165,16 +224,23 @@
 # note that we install it in the toolchain bin directory
 # not in $SYSROOT/usr/bin
 #
-dump "Install  : $TOOLCHAIN gdbserver."
+if [ "$NOTHREADS" = "yes" ] ; then
+    DSTFILE="gdbserver-nothreads"
+else
+    DSTFILE="gdbserver"
+fi
+dump "Install  : $TOOLCHAIN $DSTFILE."
 DEST=`dirname $TOOLCHAIN_PATH`
 mkdir -p $DEST &&
-run $TOOLCHAIN_PREFIX-objcopy --strip-unneeded $BUILD_OUT/gdbserver $DEST/gdbserver
+run $TOOLCHAIN_PREFIX-objcopy --strip-unneeded $BUILD_OUT/gdbserver $DEST/$DSTFILE
 if [ $? != 0 ] ; then
-    dump "Could not install gdbserver. See $TMPLOG"
+    dump "Could not install $DSTFILE. See $TMPLOG"
     exit 1
 fi
 
-dump "Done."
-if [ -n "$OPTION_BUILD_OUT" ] ; then
-    rm -rf $BUILD_OUT
+log "Cleaning up."
+if [ -z "$OPTION_BUILD_OUT" ] ; then
+    run rm -rf $BUILD_OUT
 fi
+
+dump "Done."
diff --git a/build/tools/prebuilt-common.sh b/build/tools/prebuilt-common.sh
index 02a3d6f..76fe9ab 100644
--- a/build/tools/prebuilt-common.sh
+++ b/build/tools/prebuilt-common.sh
@@ -532,8 +532,8 @@
         ABI_CFLAGS_FOR_TARGET="-fexceptions"
         ABI_CXXFLAGS_FOR_TARGET="-frtti"
         ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-libstdc__-v3"
-        # Stick to 6.6 for now.
-        # GDB_VERSION=7.1.x
+        # Stick to 6.6 for now. 7.1.x doesn't seem to work right now.
+        #GDB_VERSION=7.1.x
         ;;
     x86-*)
         ARCH="x86"
diff --git a/build/tools/rebuild-all-prebuilt.sh b/build/tools/rebuild-all-prebuilt.sh
index 8874cfc..31a5021 100755
--- a/build/tools/rebuild-all-prebuilt.sh
+++ b/build/tools/rebuild-all-prebuilt.sh
@@ -211,9 +211,9 @@
         return
     fi
     dump "Build $1 gdbserver..."
-    $PROGDIR/build-gdbserver.sh $FLAGS --build-out=$BUILD_DIR/gdbserver-$1 $SRC_DIR/gdb/gdb-$GDB_VERSION/gdb/gdbserver $NDK_DIR $1
+    $PROGDIR/build-gdbserver.sh $FLAGS --build-out=$BUILD_DIR/gdbserver-$1 --gdb-version=$GDB_VERSION $SRC_DIR $NDK_DIR $1
     if [ $? != 0 ] ; then
-        dump "ERROR: Could not build $1 toolchain!"
+        dump "ERROR: Could not build $1 gdbserver!"
         exit 1
     fi
     package_it "$1 gdbserver" "$1-gdbserver" "toolchains/$1/prebuilt/gdbserver"
diff --git a/build/tools/toolchain-patches/gdb/0001-Proper-libthread_db-support-in-gdbserver.patch b/build/tools/toolchain-patches/gdb/0001-Proper-libthread_db-support-in-gdbserver.patch
index 3f020f7..4d1cd92 100644
--- a/build/tools/toolchain-patches/gdb/0001-Proper-libthread_db-support-in-gdbserver.patch
+++ b/build/tools/toolchain-patches/gdb/0001-Proper-libthread_db-support-in-gdbserver.patch
@@ -1,13 +1,16 @@
-From 1f21dc117bb3c18773b85107550757b40ca91dc9 Mon Sep 17 00:00:00 2001
+From bc7aac86cdf8938f43bc5b9c6f1ac33c1882cf7b Mon Sep 17 00:00:00 2001
 From: David 'Digit' Turner <digit@android.com>
-Date: Tue, 5 Oct 2010 22:08:33 +0200
+Date: Thu, 25 Nov 2010 18:37:38 +0100
 Subject: [PATCH] Proper libthread_db support in gdbserver.
 
-Change-Id: I6dde4030f7471c578928b17bff19086de23ba483
+Change-Id: I5ebbb18efe663e7bf24d6147f33cc92f38dea148
 ---
- gdb-6.6/gdb/gdbserver/acinclude.m4 |    2 +-
- gdb-6.6/gdb/gdbserver/configure    |    2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
+ gdb-6.6/gdb/gdbserver/acinclude.m4   |    2 +-
+ gdb-6.6/gdb/gdbserver/configure      |    2 +-
+ gdb-7.1.x/gdb/gdbserver/Makefile.in  |    8 ++++----
+ gdb-7.1.x/gdb/gdbserver/configure    |    4 ++--
+ gdb-7.1.x/gdb/gdbserver/configure.ac |    4 ++--
+ 5 files changed, 10 insertions(+), 10 deletions(-)
 
 diff --git a/gdb-6.6/gdb/gdbserver/acinclude.m4 b/gdb-6.6/gdb/gdbserver/acinclude.m4
 index aaad2e2..04f023c 100644
@@ -35,6 +38,72 @@
    cat >conftest.$ac_ext <<_ACEOF
  /* confdefs.h.  */
  _ACEOF
+diff --git a/gdb-7.1.x/gdb/gdbserver/Makefile.in b/gdb-7.1.x/gdb/gdbserver/Makefile.in
+index 5bf82e2..bc2ed43 100644
+--- a/gdb-7.1.x/gdb/gdbserver/Makefile.in
++++ b/gdb-7.1.x/gdb/gdbserver/Makefile.in
+@@ -176,13 +176,13 @@ clean-info:
+ 
+ gdbserver$(EXEEXT): $(OBS) ${ADD_DEPS} ${CDEPS}
+ 	rm -f gdbserver$(EXEEXT)
+-	${CC-LD} $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) -o gdbserver$(EXEEXT) $(OBS) \
+-	  $(GDBSERVER_LIBS) $(XM_CLIBS)
++	${CC-LD} $(INTERNAL_CFLAGS) $(OBS) $(GDBSERVER_LIBS) $(XM_CLIBS) \
++          $(INTERNAL_LDFLAGS) -o gdbserver$(EXEEXT)
+ 
+ gdbreplay$(EXEEXT): $(GDBREPLAY_OBS)
+ 	rm -f gdbreplay$(EXEEXT)
+-	${CC-LD} $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) -o gdbreplay$(EXEEXT) $(GDBREPLAY_OBS) \
+-	  $(XM_CLIBS)
++	${CC-LD} $(INTERNAL_CFLAGS) -o gdbreplay$(EXEEXT) $(GDBREPLAY_OBS) \
++          $(XM_CLIBS) $(INTERNAL_LDFLAGS)
+ 
+ # Put the proper machine-specific files first, so M-. on a machine
+ # specific routine gets the one for the correct machine.
+diff --git a/gdb-7.1.x/gdb/gdbserver/configure b/gdb-7.1.x/gdb/gdbserver/configure
+index 47bd81a..399d08b 100755
+--- a/gdb-7.1.x/gdb/gdbserver/configure
++++ b/gdb-7.1.x/gdb/gdbserver/configure
+@@ -4291,7 +4291,7 @@ srv_libs=
+ USE_THREAD_DB=
+ 
+ if test "$srv_linux_thread_db" = "yes"; then
+-  srv_libs="-ldl"
++  srv_libs="-lthread_db -lc"
+   old_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -rdynamic"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+@@ -4356,7 +4356,7 @@ if test "${with_libthread_db+set}" = set; then :
+ 
+ $as_echo "#define USE_LIBTHREAD_DB_DIRECTLY 1" >>confdefs.h
+ 
+-  srv_libs="$srv_libthread_db_path"
++  srv_libs="$srv_libthread_db_path -lc"
+ 
+ fi
+ 
+diff --git a/gdb-7.1.x/gdb/gdbserver/configure.ac b/gdb-7.1.x/gdb/gdbserver/configure.ac
+index 638c228..a13117b 100644
+--- a/gdb-7.1.x/gdb/gdbserver/configure.ac
++++ b/gdb-7.1.x/gdb/gdbserver/configure.ac
+@@ -180,7 +180,7 @@ srv_libs=
+ USE_THREAD_DB=
+ 
+ if test "$srv_linux_thread_db" = "yes"; then
+-  srv_libs="-ldl"
++  srv_libs="-lthread_db -lc"
+   old_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -rdynamic"
+   AC_TRY_LINK([], [], [RDYNAMIC=-rdynamic], [RDYNAMIC=])
+@@ -202,7 +202,7 @@ AC_ARG_WITH(libthread-db,
+ AS_HELP_STRING([--with-libthread-db=PATH], [use given libthread_db directly]),
+ [srv_libthread_db_path="${withval}"
+   AC_DEFINE(USE_LIBTHREAD_DB_DIRECTLY, 1, [Define if we should use libthread_db directly.])
+-  srv_libs="$srv_libthread_db_path"
++  srv_libs="$srv_libthread_db_path -lc"
+ ])
+ 
+ if test "$srv_xmlfiles" != ""; then
 -- 
-1.7.1
+1.7.3.1
 
diff --git a/build/tools/toolchain-patches/gdb/0002-Fix-signal-handling-in-gdbserver-6.6.patch b/build/tools/toolchain-patches/gdb/0002-Fix-signal-handling-in-gdbserver-6.6.patch
new file mode 100644
index 0000000..c0616dc
--- /dev/null
+++ b/build/tools/toolchain-patches/gdb/0002-Fix-signal-handling-in-gdbserver-6.6.patch
@@ -0,0 +1,22 @@
+diff -burN gdb-org/gdb-6.6/gdb/gdbserver/linux-low.c gdb/gdb-6.6/gdb/gdbserver/linux-low.c
+--- gdb-org/gdb-6.6/gdb/gdbserver/linux-low.c	2010-11-26 09:33:53.446951831 +0100
++++ gdb/gdb-6.6/gdb/gdbserver/linux-low.c	2010-11-26 10:03:01.905288172 +0100
+@@ -778,6 +778,18 @@
+       errno = 0;
+       tkill_failed = 1;
+     }
++#elif defined(__ANDROID__)
++  extern int tkill(int, int);
++  if (!tkill_failed)
++    {
++      int ret = tkill(lwpid, signo);
++      if (errno != ENOSYS)
++        return ret;
++      errno = 0;
++      tkill_failed = 1;
++    }
++#else
++#  error SIGNAL HANDLING WILL NOT WORK!!
+ #endif
+ 
+   return kill (lwpid, signo);
diff --git a/docs/CHANGES.html b/docs/CHANGES.html
index 1f6d5e1..e1e8c27 100644
--- a/docs/CHANGES.html
+++ b/docs/CHANGES.html
@@ -22,8 +22,8 @@
 
 IMPORTANT CHANGES:
 
-- Support for API level 9, which adds the following native features to the
-  platform:
+- Support for API level 9, (a.k.a. Android 2.3) which adds the following
+  native features to the platform:
 
      - Native audio API through the OpenSL ES Standard.
        New headers &lt;SLES/OpenSLES.h&gt; and &lt;SLES/OpenSLES_Android.h&gt; are
@@ -52,6 +52,18 @@
 
        Note that most of these new features are targetted at game developers.
 
+- Improved gdbserver binary to allow debugging _threaded_ programs properly
+  with ndk-gdb (the previous binary could only set breakpoints on the main
+  thread).
+
+  IMPORTANT: THIS ONLY WORKS IF YOU RUN ON ANDROID 2.3 OR HIGHER.
+
+  The root cause of the problem is a platform bug that was only fixed in
+  2.3. If you try to debug on a previous platform, the gdbserver binary
+  will only be able to set breakpoints on the main thread.
+
+  For more information, see the specific section in docs/NDK-GDB.html.
+
 - Easier debuggable builds: just invoke ndk-build while defining the
   NDK_DEBUG variable to 1, as in:
 
diff --git a/docs/NDK-GDB.html b/docs/NDK-GDB.html
index 2b2bb75..1832a4f 100644
--- a/docs/NDK-GDB.html
+++ b/docs/NDK-GDB.html
@@ -1,5 +1,8 @@
 <html><body><pre>'ndk-gdb' Overview
 
+IMPORTANT: IF YOU ARE DEBUGGING THREADED PROGRAMS, PLEASE READ THE
+           SECTION BELOW TITLED 'Thread Support'.
+
 I. Usage:
 ---------
 
@@ -169,4 +172,39 @@
 limitation in a future NDK release.
 
 The other NDK requirements apply: e.g. GNU Make 3.81 or higher.
+
+
+IV. Thread Support:
+-------------------
+
+If your application runs on a platform older than Android 2.3, ndk-gdb will
+not be able to debug native threads properly. Instead, the debugger will only
+be able to put breakpoints on the main thread, completely ignoring the
+execution of other ones.
+
+The root of the problem is complex, but is essentially due to a very unfortunate
+bug in the platform, which was only discovered lately.
+
+The gdbserver binary that comes with this NDK has special code to detect this
+condition at runtime and adapt its behaviour automatically (in other words,
+you don't have anything special to do when building your code).
+
+What this means in practical terms are:
+
+- If you are on Android 2.3, or a prior platform release which has had the
+  platform bugfix back-ported to it, you will be able to debug native
+  threads automatically.
+
+- If you are not, you will only be able to debug the main thread
+  (as in previous NDK releases). You will also see the following message
+  when launching ndk-gdb (just before the gdb prompt):
+
+     Thread debugging is unsupported on this Android platform!
+
+  If you place a breakpoint on a function executed on a non-main thread, the
+  program will exit with the following message in GDB:
+
+        Program terminated with signal SIGTRAP, Trace/breakpoint trap.
+        The program no longer exists.
+
 </pre></body></html>
\ No newline at end of file
diff --git a/sources/android/libthread_db/README b/sources/android/libthread_db/README
new file mode 100644
index 0000000..f83f8f4
--- /dev/null
+++ b/sources/android/libthread_db/README
@@ -0,0 +1,13 @@
+Here are the sources of the special libthread_db that will be statically
+linked against our gdbserver binary. These are uses automatically by the
+build-gdbserver.sh script.
+
+THIS IS NOT AN IMPORT MODULE.
+
+Applications don't need to link to libthread_db anyway, this library is
+a small interface used by gdbserver to manage the list of threads on the
+target process. Its API and ABI are not stable and may change in the
+future.
+
+Each implementation is also highly specific to the version of gdbserver
+you are compiling, hence the subdirectories like "gdb-6.6"
\ No newline at end of file
diff --git a/sources/android/libthread_db/gdb-6.6/libthread_db.c b/sources/android/libthread_db/gdb-6.6/libthread_db.c
new file mode 100644
index 0000000..95381e2
--- /dev/null
+++ b/sources/android/libthread_db/gdb-6.6/libthread_db.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ */
+
+#include <dirent.h>
+#include <sys/ptrace.h>
+#include <stdint.h>
+#include <thread_db.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define DEBUG 0
+#if DEBUG
+#  include <string.h>  /* for strerror() */
+#  define D(...)  fprintf(stderr, "libthread_db:%s: ", __FUNCTION__), fprintf(stderr, __VA_ARGS__)
+#else
+#  define D(...)  do{}while(0)
+#endif
+
+extern int ps_pglobal_lookup (void *, const char *obj, const char *name, void **sym_addr);
+
+struct ps_prochandle
+{
+    pid_t pid;
+};
+
+
+/*
+ * This is the list of "special" symbols we care about whose addresses are
+ * cached by gdbserver from the host at init time.
+ */
+enum {
+    SYM_TD_CREATE,
+    SYM_THREAD_LIST,
+    NUM_SYMS
+};
+
+static char const * gSymbols[] = {
+    [SYM_TD_CREATE] = "_thread_created_hook",
+    NULL
+};
+
+
+char const **
+td_symbol_list(void)
+{
+    return gSymbols;
+}
+
+
+/* Extract the permitted capabilities of a given task */
+static int
+_get_task_permitted_caps(int pid, int tid, uint64_t *cap)
+{
+    char path[64];
+    char buff[1024];
+    int  len;
+    int  fd;
+    int  result = -1;
+    char*  perm;
+    char*  end;
+
+    /* Open task status file */
+    snprintf(path, sizeof path, "/proc/%d/task/%d/status", pid, tid);
+    fd = open(path, O_RDONLY);
+    if (fd < 0) {
+        D("Could not open %s: %s\n", path, strerror(errno));
+        return -1;
+    }
+
+    /* Read its content, up to sizeof buff-1, then zero-terminate */
+    do {
+        len = read(fd, buff, sizeof buff-1);
+    } while (len < 0 && errno == EINTR);
+
+    if (len < 0) {
+        D("Could not read %s: %s\n", path, strerror(errno));
+        goto EXIT;
+    }
+
+    buff[len] = 0;
+
+    /* Look for "CapPrm: " in it */
+    perm = strstr(buff, "CapPrm:");
+    if (perm == NULL) {
+        D("Could not find CapPrm in %s!\n---- cut here ----\n%.*s\n----- cut here -----\n",
+          path, len, buff);
+        errno = EINVAL;
+        goto EXIT;
+    }
+
+    /* Now read the hexadecimal value after 'CapPrm: ' */
+    errno = 0;
+    *cap = (uint64_t) strtoull(perm+8, &end, 16);
+    if (errno == 0) {
+        D("Found CapPerm of %lld in %s\n", *cap, path);
+        result = 0;
+    } else {
+        D("Cannot read CapPerm from %s: '%.*s'\n", path, 24, perm);
+    }
+EXIT:
+    close(fd);
+    return result;
+}
+
+td_err_e
+td_ta_new(struct ps_prochandle const * proc_handle, td_thragent_t ** agent_out)
+{
+    td_thragent_t * agent;
+
+    /* Platforms before Android 2.3 contain a system bug that prevents
+     * gdbserver to attach to all threads in a target process when
+     * it is run as the same userID than the target (works fine if
+     * run as root).
+     *
+     * Due to the way gdbserver is coded, this makes gdbserver exit()
+     * immediately (see linux_attach_lwp in linux-low.c). Even if we
+     * modify the source code to not exit(), then signals will not
+     * be properly rerouted to gdbserver, preventing breakpoints from
+     * working correctly.
+     *
+     * The following code is here to test for this problematic condition.
+     * If it is detected, we return TD_NOLIBTHREAD to indicate that there
+     * are no threads to attach to (gdbserver will attach to the main thread
+     * though).
+     */
+    do {
+        char  path[64];
+        DIR*  dir;
+        struct dirent *entry;
+        pid_t     my_pid = getpid();
+        int       target_pid = proc_handle->pid;
+        uint64_t  my_caps, tid_caps;
+
+        D("Probing system for platform bug.\n");
+
+        /* nothing to do if we run as root */
+        if (geteuid() == 0) {
+            D("Running as root, nothing to do.\n");
+            break;
+        }
+
+        /* First, get our own permitted capabilities */
+        if (_get_task_permitted_caps(my_pid, my_pid, &my_caps) < 0) {
+            /* something is really fishy here */
+            D("Could not get gdbserver permitted caps!\n");
+            return TD_NOLIBTHREAD;
+        }
+
+        /* Now, for each thread in the target process, compare the
+         * permitted capabilities set to our own. If they differ,
+         * the thread attach will fail. Booo...
+         */
+        snprintf(path, sizeof path, "/proc/%d/task", target_pid);
+        dir = opendir(path);
+        if (!dir) {
+            D("Could not open %s: %s\n", path, strerror(errno));
+            break;
+        }
+        while ((entry = readdir(dir)) != NULL) {
+            int  tid;
+
+            if (entry->d_name[0] == '.')   /* skip . and .. */
+                continue;
+
+            tid = atoi(entry->d_name);
+            if (tid == 0)  /* should not happen - be safe */
+                continue;
+
+            if (_get_task_permitted_caps(target_pid, tid, &tid_caps) < 0) {
+                /* again, something is fishy */
+                D("Could not get permitted caps for thread %d\n", tid);
+                closedir(dir);
+                return TD_NOLIBTHREAD;
+            }
+
+            if (tid_caps != my_caps) {
+                /* AAAARGH !! The permitted capabilities set differ. */
+                D("AAAAAH, Can't debug threads!\n");
+                fprintf(stderr, "Thread debugging is unsupported on this Android platform!\n");
+                closedir(dir);
+                return TD_NOLIBTHREAD;
+            }
+        }
+        closedir(dir);
+        D("Victory: We can debug theads!\n");
+    } while (0);
+
+    /* We now return to our regularly scheduled program */
+
+    agent = (td_thragent_t *)malloc(sizeof(td_thragent_t));
+    if (!agent) {
+        return TD_MALLOC;
+    }
+
+    agent->pid = proc_handle->pid;
+    *agent_out = agent;
+
+    return TD_OK;
+}
+
+
+td_err_e
+td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * events)
+{
+    return TD_OK;
+}
+
+
+static td_thrhandle_t gEventMsgHandle;
+
+static int
+_event_getmsg_helper(td_thrhandle_t const * handle, void * bkpt_addr)
+{
+    void * pc;
+
+    pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)60 /* r15/pc */, NULL);
+
+    if (pc == bkpt_addr) {
+        // The hook function takes the id of the new thread as it's first param,
+        // so grab it from r0.
+        gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)0 /* r0 */, NULL);
+        gEventMsgHandle.tid = gEventMsgHandle.pid;
+        return 0x42;
+    }
+    return 0;
+}
+
+td_err_e
+td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event)
+{
+    td_err_e err;
+    void * bkpt_addr;
+
+    err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr);
+    if (err) {
+        return err;
+    }
+
+    err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0);
+    if (err != 0x42) {
+        return TD_NOMSG;
+    }
+
+    event->event = TD_CREATE;
+    event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way!
+
+    return TD_OK;
+}
+
+
+td_err_e
+td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info)
+{
+    info->ti_tid = handle->tid;
+    info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids
+    info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>.
+                                      This is only used to see if the thread is a zombie or not */
+    return TD_OK;
+}
+
+
+td_err_e
+td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event)
+{
+    // I don't think we need to do anything here...
+    return TD_OK;
+}
+
+
+td_err_e
+td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out)
+{
+    int32_t err;
+
+    /*
+     * This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up
+     * the symbol from it's cache, which is populated at start time with the
+     * symbols returned from td_symbol_list via calls back to the host.
+     */
+
+    switch (event) {
+        case TD_CREATE:
+            err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &notify_out->u.bptaddr);
+            if (err) {
+                return TD_NOEVENT;
+            }
+            return TD_OK;
+    }
+    return TD_NOEVENT;
+}
+
+
+td_err_e
+td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
+               td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags)
+{
+    td_err_e err = TD_OK;
+    char path[32];
+    DIR * dir;
+    struct dirent * entry;
+    td_thrhandle_t handle;
+
+    snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid);
+    dir = opendir(path);
+    if (!dir) {
+        return TD_NOEVENT;
+    }
+
+    handle.pid = agent->pid;
+    while ((entry = readdir(dir)) != NULL) {
+        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
+            continue;
+        }
+        handle.tid = atoi(entry->d_name);
+        err = func(&handle, cookie);
+        if (err) {
+            break;
+        }
+    }
+
+    closedir(dir);
+
+    return err;
+}
+
diff --git a/sources/android/libthread_db/gdb-6.6/thread_db.h b/sources/android/libthread_db/gdb-6.6/thread_db.h
new file mode 100644
index 0000000..74848fc
--- /dev/null
+++ b/sources/android/libthread_db/gdb-6.6/thread_db.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ */
+
+#ifndef _LIBTHREAD_DB__THREAD_DB_H
+#define _LIBTHREAD_DB__THREAD_DB_H
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+
+#define TD_THR_ANY_USER_FLAGS       0xffffffff
+#define TD_THR_LOWEST_PRIORITY      -20
+#define TD_SIGNO_MASK               NULL
+
+/* td_err_e values */
+enum {
+    TD_OK,
+    TD_ERR,
+    TD_NOTHR,
+    TD_NOSV,
+    TD_NOLWP,
+    TD_BADPH,
+    TD_BADTH,
+    TD_BADSH,
+    TD_BADTA,
+    TD_BADKEY,
+    TD_NOMSG,
+    TD_NOFPREGS,
+    TD_NOLIBTHREAD,
+    TD_NOEVENT,
+    TD_NOCAPAB,
+    TD_DBERR,
+    TD_NOAPLIC,
+    TD_NOTSD,
+    TD_MALLOC,
+    TD_PARTIALREG,
+    TD_NOXREGS,
+    TD_VERSION
+};
+
+/*
+ * td_event_e values
+ * NOTE: There is a max of 32 events
+ */
+enum {
+    TD_CREATE,
+    TD_DEATH
+};
+
+/* td_thr_state_e values */
+enum {
+    TD_THR_ANY_STATE,
+    TD_THR_UNKNOWN,
+    TD_THR_SLEEP,
+    TD_THR_ZOMBIE
+};
+
+typedef int32_t td_err_e;
+typedef uint32_t td_event_e;
+typedef uint32_t td_notify_e;
+typedef uint32_t td_thr_state_e;
+typedef pthread_t thread_t;
+
+typedef struct
+{
+    pid_t pid;
+} td_thragent_t;
+
+typedef struct
+{
+    pid_t pid;
+    pid_t tid;
+} td_thrhandle_t;
+
+typedef struct
+{
+    td_event_e event;
+    td_thrhandle_t const * th_p;
+    union {
+        void * data;
+    } msg;
+} td_event_msg_t;
+
+typedef struct
+{
+    uint32_t events;
+} td_thr_events_t;
+
+typedef struct
+{
+    union {
+        void * bptaddr;
+    } u;
+} td_notify_t;
+
+typedef struct
+{
+    td_thr_state_e ti_state;
+    thread_t ti_tid; // pthread's id for the thread
+    int32_t ti_lid; // the kernel's id for the thread
+} td_thrinfo_t;
+
+
+#define td_event_emptyset(set) \
+    (set)->events = 0
+
+#define td_event_fillset(set) \
+    (set)->events = 0xffffffff
+
+#define td_event_addset(set, n) \
+    (set)->events |= (1 << n)
+
+
+typedef int td_thr_iter_f(td_thrhandle_t const *, void *);
+
+
+struct ps_prochandle;
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+extern td_err_e td_ta_new(struct ps_prochandle const * proc_handle, td_thragent_t ** thread_agent);
+
+extern td_err_e td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * event);
+
+extern td_err_e td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify);
+
+extern td_err_e td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event);
+
+extern td_err_e td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
+                               td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags);
+
+extern td_err_e td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event);
+
+extern td_err_e td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info);
+
+extern char const ** td_symbol_list(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sources/android/libthread_db/gdb-7.1.x/libthread_db.c b/sources/android/libthread_db/gdb-7.1.x/libthread_db.c
new file mode 100644
index 0000000..8dd8cfe
--- /dev/null
+++ b/sources/android/libthread_db/gdb-7.1.x/libthread_db.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ */
+
+#include <dirent.h>
+#include <sys/ptrace.h>
+#include <stdint.h>
+#include <thread_db.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define DEBUG 1
+#if DEBUG
+#  include <string.h>  /* for strerror() */
+#  define D(...)  fprintf(stderr, "libthread_db:%s: ", __FUNCTION__), fprintf(stderr, __VA_ARGS__)
+#else
+#  define D(...)  do{}while(0)
+#endif
+
+
+extern int ps_pglobal_lookup (void *, const char *obj, const char *name, void **sym_addr);
+extern pid_t ps_getpid(struct ps_prochandle *ph);
+
+/*
+ * This is the list of "special" symbols we care about whose addresses are
+ * cached by gdbserver from the host at init time.
+ */
+enum {
+    SYM_TD_CREATE,
+    SYM_THREAD_LIST,
+    NUM_SYMS
+};
+
+static char const * gSymbols[] = {
+    [SYM_TD_CREATE] = "_thread_created_hook",
+    NULL
+};
+
+
+char const **
+td_symbol_list(void)
+{
+    return gSymbols;
+}
+
+
+/* Extract the permitted capabilities of a given task */
+static int
+_get_task_permitted_caps(int pid, int tid, uint64_t *cap)
+{
+    char path[64];
+    char buff[1024];
+    int  len;
+    int  fd;
+    int  result = -1;
+    char*  perm;
+    char*  end;
+
+    /* Open task status file */
+    snprintf(path, sizeof path, "/proc/%d/task/%d/status", pid, tid);
+    fd = open(path, O_RDONLY);
+    if (fd < 0) {
+        D("Could not open %s: %s\n", path, strerror(errno));
+        return -1;
+    }
+
+    /* Read its content, up to sizeof buff-1, then zero-terminate */
+    do {
+        len = read(fd, buff, sizeof buff-1);
+    } while (len < 0 && errno == EINTR);
+
+    if (len < 0) {
+        D("Could not read %s: %s\n", path, strerror(errno));
+        goto EXIT;
+    }
+
+    buff[len] = 0;
+
+    /* Look for "CapPrm: " in it */
+    perm = strstr(buff, "CapPrm:");
+    if (perm == NULL) {
+        D("Could not find CapPrm in %s!\n---- cut here ----\n%.*s\n----- cut here -----\n",
+          path, len, buff);
+        errno = EINVAL;
+        goto EXIT;
+    }
+
+    /* Now read the hexadecimal value after 'CapPrm: ' */
+    errno = 0;
+    *cap = (uint64_t) strtoull(perm+8, &end, 16);
+    if (errno == 0) {
+        D("Found CapPerm of %lld in %s\n", *cap, path);
+        result = 0;
+    } else {
+        D("Cannot read CapPerm from %s: '%.*s'\n", path, 24, perm);
+    }
+EXIT:
+    close(fd);
+    return result;
+}
+
+
+td_err_e
+td_ta_new(struct ps_prochandle * proc_handle, td_thragent_t ** agent_out)
+{
+    td_thragent_t * agent;
+
+    /* Platforms before Android 2.3 contain a system bug that prevents
+     * gdbserver to attach to all threads in a target process when
+     * it is run as the same userID than the target (works fine if
+     * run as root).
+     *
+     * Due to the way gdbserver is coded, this makes gdbserver exit()
+     * immediately (see linux_attach_lwp in linux-low.c). Even if we
+     * modify the source code to not exit(), then signals will not
+     * be properly rerouted to gdbserver, preventing breakpoints from
+     * working correctly.
+     *
+     * The following code is here to test for this problematic condition.
+     * If it is detected, we return TD_NOLIBTHREAD to indicate that there
+     * are no threads to attach to (gdbserver will attach to the main thread
+     * though).
+     */
+    do {
+        char  path[64];
+        DIR*  dir;
+        struct dirent *entry;
+        pid_t     my_pid = getpid();
+        int       target_pid = ps_getpid(proc_handle);
+        uint64_t  my_caps, tid_caps;
+
+        D("Probing system for platform bug.\n");
+
+        /* nothing to do if we run as root */
+        if (geteuid() == 0) {
+            D("Running as root, nothing to do.\n");
+            break;
+        }
+
+        /* First, get our own permitted capabilities */
+        if (_get_task_permitted_caps(my_pid, my_pid, &my_caps) < 0) {
+            /* something is really fishy here */
+            D("Could not get gdbserver permitted caps!\n");
+            return TD_NOLIBTHREAD;
+        }
+
+        /* Now, for each thread in the target process, compare the
+         * permitted capabilities set to our own. If they differ,
+         * the thread attach will fail. Booo...
+         */
+        snprintf(path, sizeof path, "/proc/%d/task", target_pid);
+        dir = opendir(path);
+        if (!dir) {
+            D("Could not open %s: %s\n", path, strerror(errno));
+            break;
+        }
+        while ((entry = readdir(dir)) != NULL) {
+            int  tid;
+
+            if (entry->d_name[0] == '.')   /* skip . and .. */
+                continue;
+
+            tid = atoi(entry->d_name);
+            if (tid == 0)  /* should not happen - be safe */
+                continue;
+
+            if (_get_task_permitted_caps(target_pid, tid, &tid_caps) < 0) {
+                /* again, something is fishy */
+                D("Could not get permitted caps for thread %d\n", tid);
+                closedir(dir);
+                return TD_NOLIBTHREAD;
+            }
+
+            if (tid_caps != my_caps) {
+                /* AAAARGH !! The permitted capabilities set differ. */
+                D("AAAAAH, Can't debug threads!\n");
+                closedir(dir);
+                return TD_NOLIBTHREAD;
+            }
+        }
+        closedir(dir);
+        D("Victory: We can debug theads!\n");
+    } while (0);
+
+    /* We now return to our regularly scheduled program */
+
+    agent = (td_thragent_t *)malloc(sizeof(td_thragent_t));
+    if (!agent) {
+        return TD_MALLOC;
+    }
+
+    agent->pid = ps_getpid(proc_handle);
+    agent->ph = proc_handle;
+    *agent_out = agent;
+
+    return TD_OK;
+}
+
+
+td_err_e
+td_ta_delete(td_thragent_t * ta)
+{
+    free(ta);
+    // FIXME: anything else to do?
+    return TD_OK;
+}
+
+
+/* NOTE: not used by gdb 7.0 */
+
+td_err_e
+td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * events)
+{
+    return TD_OK;
+}
+
+
+/* NOTE: not used by gdb 7.0 */
+static td_thrhandle_t gEventMsgHandle;
+
+/* NOTE: not used by gdb 7.0 */
+
+static int
+_event_getmsg_helper(td_thrhandle_t const * handle, void * bkpt_addr)
+{
+    void * pc;
+
+    pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)60 /* r15/pc */, NULL);
+
+    if (pc == bkpt_addr) {
+        // The hook function takes the id of the new thread as it's first param,
+        // so grab it from r0.
+        gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)0 /* r0 */, NULL);
+        gEventMsgHandle.tid = gEventMsgHandle.pid;
+        return 0x42;
+    }
+    return 0;
+}
+
+/* NOTE: not used by gdb 7.0 */
+
+td_err_e
+td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event)
+{
+    td_err_e err;
+    void * bkpt_addr;
+
+    err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr);
+    if (err) {
+        return err;
+    }
+
+    err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0);
+    if (err != 0x42) {
+        return TD_NOMSG;
+    }
+
+    event->event = TD_CREATE;
+    event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way!
+
+    return TD_OK;
+}
+
+
+td_err_e
+td_ta_map_lwp2thr(td_thragent_t const * agent, lwpid_t lwpid,
+		  td_thrhandle_t *th)
+{
+    th->pid = ps_getpid(agent->ph);
+    th->tid = lwpid;
+    return TD_OK;
+}
+
+
+td_err_e
+td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info)
+{
+    info->ti_tid = handle->tid;
+    info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids
+    info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>.
+                                      This is only used to see if the thread is a zombie or not */
+    return TD_OK;
+}
+
+
+/* NOTE: not used by gdb 7.0 */
+
+td_err_e
+td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event)
+{
+    // I don't think we need to do anything here...
+    return TD_OK;
+}
+
+
+/* NOTE: not used by gdb 7.0 */
+
+td_err_e
+td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out)
+{
+    int32_t err;
+
+    /*
+     * This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up
+     * the symbol from it's cache, which is populated at start time with the
+     * symbols returned from td_symbol_list via calls back to the host.
+     */
+
+    switch (event) {
+        case TD_CREATE:
+            err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &notify_out->u.bptaddr);
+            if (err) {
+                return TD_NOEVENT;
+            }
+            return TD_OK;
+    }
+    return TD_NOEVENT;
+}
+
+
+td_err_e
+td_ta_clear_event(const td_thragent_t * ta_arg, td_thr_events_t * event)
+{
+    /* Given that gdb 7.0 doesn't use thread events,
+       there's nothing we need to do here.  */
+    return TD_OK;
+}
+
+
+td_err_e
+td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
+               td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags)
+{
+    td_err_e err = TD_OK;
+    char path[32];
+    DIR * dir;
+    struct dirent * entry;
+    td_thrhandle_t handle;
+
+    snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid);
+    dir = opendir(path);
+    if (!dir) {
+        return TD_NOEVENT;
+    }
+
+    handle.pid = agent->pid;
+    while ((entry = readdir(dir)) != NULL) {
+        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
+            continue;
+        }
+        handle.tid = atoi(entry->d_name);
+        if (func(&handle, cookie) != 0) {
+	    err = TD_DBERR;
+            break;
+        }
+    }
+
+    closedir(dir);
+
+    return err;
+}
+
+td_err_e
+td_thr_tls_get_addr(const td_thrhandle_t * th,
+		    psaddr_t map_address, size_t offset, psaddr_t * address)
+{
+    return TD_NOAPLIC; // FIXME: TODO
+}
diff --git a/sources/android/libthread_db/gdb-7.1.x/thread_db.h b/sources/android/libthread_db/gdb-7.1.x/thread_db.h
new file mode 100644
index 0000000..f064c10
--- /dev/null
+++ b/sources/android/libthread_db/gdb-7.1.x/thread_db.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ */
+
+#ifndef _LIBTHREAD_DB__THREAD_DB_H
+#define _LIBTHREAD_DB__THREAD_DB_H
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+typedef void *psaddr_t;
+#define HAVE_PSADDR_T 1
+
+typedef pid_t lwpid_t;
+#define HAVE_LWPID_T 1
+
+#define TD_THR_ANY_USER_FLAGS       0xffffffff
+#define TD_THR_LOWEST_PRIORITY      -20
+#define TD_SIGNO_MASK               NULL
+
+/* td_err_e values */
+enum {
+    TD_OK,
+    TD_ERR,
+    TD_NOTHR,
+    TD_NOSV,
+    TD_NOLWP,
+    TD_BADPH,
+    TD_BADTH,
+    TD_BADSH,
+    TD_BADTA,
+    TD_BADKEY,
+    TD_NOMSG,
+    TD_NOFPREGS,
+    TD_NOLIBTHREAD,
+    TD_NOEVENT,
+    TD_NOCAPAB,
+    TD_DBERR,
+    TD_NOAPLIC,
+    TD_NOTSD,
+    TD_MALLOC,
+    TD_PARTIALREG,
+    TD_NOXREGS,
+    TD_VERSION
+};
+
+/*
+ * td_event_e values
+ * NOTE: There is a max of 32 events
+ */
+enum {
+    TD_CREATE,
+    TD_DEATH
+};
+
+/* td_thr_state_e values */
+enum {
+    TD_THR_ANY_STATE,
+    TD_THR_UNKNOWN,
+    TD_THR_SLEEP,
+    TD_THR_ZOMBIE
+};
+
+typedef int32_t td_err_e;
+typedef uint32_t td_event_e;
+typedef uint32_t td_notify_e;
+typedef uint32_t td_thr_state_e;
+typedef pthread_t thread_t;
+
+typedef struct
+{
+    pid_t pid;
+    struct ps_prochandle *ph;
+} td_thragent_t;
+
+typedef struct
+{
+    pid_t pid;
+    pid_t tid;
+} td_thrhandle_t;
+
+typedef struct
+{
+    td_event_e event;
+    td_thrhandle_t const * th_p;
+    union {
+        void * data;
+    } msg;
+} td_event_msg_t;
+
+typedef struct
+{
+    uint32_t events;
+} td_thr_events_t;
+
+typedef struct
+{
+    union {
+        void * bptaddr;
+    } u;
+} td_notify_t;
+
+typedef struct
+{
+    td_thr_state_e ti_state;
+    thread_t ti_tid; // pthread's id for the thread
+    int32_t ti_lid; // the kernel's id for the thread
+} td_thrinfo_t;
+
+
+#define td_event_emptyset(set) \
+    (set)->events = 0
+
+#define td_event_fillset(set) \
+    (set)->events = 0xffffffff
+
+#define td_event_addset(set, n) \
+    (set)->events |= (1 << n)
+
+
+typedef int td_thr_iter_f(td_thrhandle_t const *, void *);
+
+
+struct ps_prochandle;
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+extern td_err_e td_ta_new(struct ps_prochandle * proc_handle, td_thragent_t ** thread_agent);
+
+extern td_err_e td_ta_delete(td_thragent_t * ta);
+
+extern td_err_e td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * event);
+
+extern td_err_e td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify);
+
+extern td_err_e td_ta_clear_event(const td_thragent_t * ta_arg,
+				  td_thr_events_t * event);
+
+extern td_err_e td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event);
+
+extern td_err_e td_ta_map_lwp2thr(td_thragent_t const * agent, lwpid_t lwpid,
+				  td_thrhandle_t *th);
+
+extern td_err_e td_thr_get_info(td_thrhandle_t const * handle,
+				td_thrinfo_t * info);
+
+extern td_err_e td_thr_event_enable(td_thrhandle_t const * handle,
+				    td_event_e event);
+
+extern td_err_e td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
+                               td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags);
+
+extern char const ** td_symbol_list(void);
+
+extern td_err_e td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event);
+
+extern td_err_e td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info);
+
+extern td_err_e td_thr_tls_get_addr(const td_thrhandle_t * th,
+				    psaddr_t map_address, size_t offset,
+				    psaddr_t * address);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif