Implement Android Linux PTRACE support

* Fork upstream libunwind and cross-compile with Android NDK
* libunwind is also used for proc symbol resolve instead of bfd
* Replace BDF lib with capstone for disassembling actions
* Engineer build & patch scripts to support Android ARM, ARM64, x86, x86_64
* Rename linux/ptrace.* to linux/ptrace_utils.* since it conflicts with Android platform includes for ptrace API
* Wrap register & instruction sizes under macros to reflect sizes for supported CPU arch (makes debugging easier)
* Add / Implement missing definitions / functions for Android
* Improve Android build process
diff --git a/Makefile b/Makefile
index e8915ee..e0b305c 100644
--- a/Makefile
+++ b/Makefile
@@ -103,6 +103,14 @@
 INTERCEPTOR_SRCS = $(wildcard interceptor/*.c)
 INTERCEPTOR_LIBS = $(INTERCEPTOR_SRCS:.c=.so)
 
+# Control Android builds
+ANDROID_DEBUG_ENABLED ?= false
+ANDROID_APP_ABI       ?= armeabi-v7a
+NDK_BUILD_ARGS :=
+ifeq ($(ANDROID_DEBUG_ENABLED),true)
+	NDK_BUILD_ARGS += V=1 NDK_DEBUG=1 APP_OPTIM=debug
+endif
+
 all: warn_libs $(BIN) $(INTERCEPTOR_LIBS)
 
 %.o: %.c
@@ -141,7 +149,8 @@
 	
 .PHONY:android
 android:
-	ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./android/Android.mk APP_PLATFORM=android-21
+	ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./android/Android.mk \
+	          APP_PLATFORM=android-21 APP_ABI=$(ANDROID_APP_ABI) $(NDK_BUILD_ARGS)
 
 # DO NOT DELETE
 
@@ -151,7 +160,7 @@
 fuzz.o: common.h fuzz.h arch.h files.h log.h report.h util.h
 util.o: common.h log.h
 report.o: common.h report.h log.h util.h
-linux/arch.o: common.h arch.h linux/perf.h linux/ptrace.h log.h util.h
+linux/arch.o: common.h arch.h linux/perf.h linux/ptrace_utils.h log.h util.h
 linux/bfd.o: common.h linux/bfd.h files.h log.h util.h
 linux/perf.o: common.h linux/perf.h log.h
 linux/ptrace.o: common.h linux/ptrace.h files.h linux/bfd.h linux/unwind.h
diff --git a/android/Android.mk b/android/Android.mk
index d1b6090..b11f09b 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -14,18 +14,103 @@
 #   limitations under the License.
 
 LOCAL_PATH := $(abspath $(call my-dir)/..)
+
+# Enable Linux ptrace inesead of POSIX by default 
+ANDROID_WITH_PTRACE ?= true
+
+ifeq ($(APP_ABI),$(filter $(APP_ABI),armeabi armeabi-v7a))
+  ARCH_ABI := arm
+  UNW_ARCH := arm
+else ifeq ($(APP_ABI),$(filter $(APP_ABI),x86))
+  ARCH_ABI := x86
+  UNW_ARCH := x86
+  # TODO: Remove this when x86 testing is completed
+  $(info $(APP_ABI) Android not fully tested yet (consider providing feedback if tested))
+else ifeq ($(APP_ABI),$(filter $(APP_ABI),arm64-v8a))
+  ARCH_ABI := arm64
+  UNW_ARCH := aarch64
+  # TODO: Remove this when arm64 testing is completed
+  $(info $(APP_ABI) Android not fully tested yet (consider providing feedback if tested))
+else ifeq ($(APP_ABI),$(filter $(APP_ABI),x86_64))
+  ARCH_ABI := x86_64
+  UNW_ARCH := x86_64
+  $(error $(APP_ABI) Android not supported (issues with libunwind))
+else
+  # ndk-build will have already failed, so just in case
+  $(error Unknown APP_API '$(APP_ABI)')
+endif
+
+ifeq ($(ANDROID_WITH_PTRACE),true)
+  # Upstream libunwind compiled from sources with Android NDK toolchain
+  LIBUNWIND_A := third_party/android/libunwind/$(ARCH_ABI)/libunwind-$(UNW_ARCH).a
+  ifeq ("$(wildcard $(LIBUNWIND_A))","")
+    $(error libunwind-$(UNW_ARCH). is missing. Please execute \
+            'third_party/android/scripts/compile-libunwind.sh third_party/android/libunwind $(ARCH_ABI)')
+  endif
+
+  include $(CLEAR_VARS)
+  LOCAL_MODULE := libunwind
+  LOCAL_SRC_FILES := third_party/android/libunwind/$(ARCH_ABI)/libunwind.a
+  LOCAL_EXPORT_C_INCLUDES := third_party/android/libunwind/include
+  include $(PREBUILT_STATIC_LIBRARY)
+
+  include $(CLEAR_VARS)
+  LOCAL_MODULE := libunwind-arch
+  LOCAL_SRC_FILES := third_party/android/libunwind/$(ARCH_ABI)/libunwind-$(UNW_ARCH).a
+  LOCAL_EXPORT_C_INCLUDES := third_party/android/libunwind/include
+  include $(PREBUILT_STATIC_LIBRARY)
+
+  include $(CLEAR_VARS)
+  LOCAL_MODULE := libunwind-ptrace
+  LOCAL_SRC_FILES := third_party/android/libunwind/$(ARCH_ABI)/libunwind-ptrace.a
+  LOCAL_EXPORT_C_INCLUDES := third_party/android/libunwind/include
+  include $(PREBUILT_STATIC_LIBRARY)
+
+  LOCAL_MODULE := libunwind-dwarf-generic
+  LOCAL_SRC_FILES := third_party/android/libunwind/$(ARCH_ABI)/libunwind-dwarf-generic.a
+  LOCAL_EXPORT_C_INCLUDES := third_party/android/libunwind/include
+  include $(PREBUILT_STATIC_LIBRARY)
+
+  # Upstream capstone compiled from sources with Android NDK toolchain
+  LIBCAPSTONE_A := third_party/android/capstone/$(ARCH_ABI)/libcapstone.a
+  ifeq ("$(wildcard $(LIBCAPSTONE_A))","")
+    $(error libunwind-$(UNW_ARCH). is missing. Please execute \
+            'third_party/android/scripts/compile-capstone.sh third_party/android/capstone $(ARCH_ABI)')
+  endif
+  include $(CLEAR_VARS)
+  LOCAL_MODULE := libcapstone
+  LOCAL_SRC_FILES := $(LIBCAPSTONE_A)
+  LOCAL_EXPORT_C_INCLUDES := third_party/android/capstone/include
+  include $(PREBUILT_STATIC_LIBRARY)
+endif
+
+# Main honggfuzz module
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := honggfuzz
 LOCAL_SRC_FILES := honggfuzz.c log.c files.c fuzz.c report.c mangle.c util.c
 LOCAL_CFLAGS := -std=c11 -I. \
     -D_GNU_SOURCE \
-    -Wall -Wextra -Wno-initializer-overrides -Wno-override-init -Wno-unknown-warning-option -Werror \
-    -funroll-loops -O2
+    -Wall -Wextra -Wno-initializer-overrides -Wno-override-init \
+    -Wno-unknown-warning-option -Werror -funroll-loops -O2
 LOCAL_LDFLAGS := -lm
 
-ARCH_SRCS := $(wildcard posix/*.c)
-ARCH = POSIX
+ifeq ($(ANDROID_WITH_PTRACE),true)
+  LOCAL_C_INCLUDES := third_party/android/libunwind/include third_party/android/capstone/include
+  LOCAL_STATIC_LIBRARIES := libunwind libunwind-arch libunwind-ptrace libunwind-dwarf-generic libcapstone
+  LOCAL_CFLAGS += -D__HF_USE_CAPSTONE__
+  ARCH_SRCS := linux/arch.c linux/ptrace_utils.c linux/perf.c linux/unwind.c
+  ARCH := LINUX
+  $(info $(shell (echo "********************************************************************")))
+  $(info $(shell (echo "Android PTRACE build: Will prevent debuggerd from processing crashes")))
+  $(info $(shell (echo "********************************************************************")))
+else
+  ARCH_SRCS := posix/arch.c
+  ARCH := POSIX
+  $(info $(shell (echo "********************************************************************")))
+  $(info $(shell (echo "Android POSIX build: Will allow debuggerd to process crashes")))
+  $(info $(shell (echo "********************************************************************")))
+endif
 
 LOCAL_SRC_FILES += $(ARCH_SRCS)
 LOCAL_CFLAGS += -D_HF_ARCH_${ARCH}
diff --git a/common.h b/common.h
index bcd357f..2183338 100644
--- a/common.h
+++ b/common.h
@@ -48,6 +48,9 @@
 /* Align to the upper-page boundary */
 #define _HF_PAGE_ALIGN_UP(x)  (((size_t)x + (size_t)getpagesize() - (size_t)1) & ~((size_t)getpagesize() - (size_t)1))
 
+/* String buffer size for function names in stack traces produced from libunwind */
+#define _HF_FUNC_NAME_SZ    256  //Should be alright for mangled C++ procs too
+
 typedef enum {
     _HF_DYNFILE_NONE = 0x0,
     _HF_DYNFILE_INSTR_COUNT = 0x1,
@@ -110,11 +113,11 @@
     size_t dynamicFileSz;
 } fuzzer_t;
 
-#define _HF_MAX_FUNCS 200
+#define _HF_MAX_FUNCS 80
 typedef struct {
     void *pc;
-    char func[64];
-    int line;
+    char func[_HF_FUNC_NAME_SZ];
+    size_t line;
 } funcs_t;
 
 #define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
diff --git a/fuzz.c b/fuzz.c
index 28e86de..b7e6617 100644
--- a/fuzz.c
+++ b/fuzz.c
@@ -52,6 +52,18 @@
 #include "report.h"
 #include "util.h"
 
+#if defined(__ANDROID__)
+#if defined(__aarch64__) && !defined(__NR_fork)
+#include <sys/syscall.h>
+
+pid_t honggfuzz_aarch64_fork(void)
+{
+	return syscall(__NR_clone, SIGCHLD, NULL);
+}
+# define fork honggfuzz_aarch64_fork
+#endif
+#endif
+
 static int fuzz_sigReceived = 0;
 
 static void fuzz_sigHandler(int sig, siginfo_t * si, void *v)
@@ -255,7 +267,7 @@
         }
     }
 
-#if defined(_HF_ARCH_LINUX)
+#if defined(_HF_ARCH_LINUX) && defined(__NR_fork)
 #include <unistd.h>
 #include <sys/syscall.h>
     fuzzer.pid = syscall(__NR_fork);
@@ -407,7 +419,7 @@
     }
     hfuzz->sem = &semName;
 #endif                          /* defined(__ANDROID__) */
-    
+
     if (hfuzz->sem == SEM_FAILED) {
         LOGMSG_P(l_FATAL, "sem_open() failed");
     }
diff --git a/linux/arch.c b/linux/arch.c
index a7a7721..fffd4bc 100644
--- a/linux/arch.c
+++ b/linux/arch.c
@@ -46,7 +46,7 @@
 #include <unistd.h>
 
 #include "linux/perf.h"
-#include "linux/ptrace.h"
+#include "linux/ptrace_utils.h"
 #include "log.h"
 #include "util.h"
 
@@ -271,7 +271,13 @@
 
     for (;;) {
         int status;
+
+    // wait3 syscall is no longer present in Android
+#if !defined(__ANDROID__)
         pid_t pid = wait3(&status, __WNOTHREAD | __WALL, NULL);
+#else
+        pid_t pid = wait4(-1, &status, __WNOTHREAD | __WALL, NULL);
+#endif
 
         LOGMSG_P(l_DEBUG, "PID '%d' returned with status '%d'", pid, status);
 
@@ -284,7 +290,11 @@
             break;
         }
         if (pid == -1) {
-            LOGMSG_P(l_FATAL, "wait3() failed");
+#if !defined(__ANDROID__)
+            LOGMSG_P(l_FATAL, "wait3() failed");  
+#else
+            LOGMSG_P(l_FATAL, "wait4() failed");
+#endif
         }
 
         uint64_t tmp;
diff --git a/linux/ptrace.c b/linux/ptrace_utils.c
similarity index 72%
rename from linux/ptrace.c
rename to linux/ptrace_utils.c
index 0b03289..eb371d7 100644
--- a/linux/ptrace.c
+++ b/linux/ptrace_utils.c
@@ -22,7 +22,7 @@
  */
 
 #include "common.h"
-#include "ptrace.h"
+#include "ptrace_utils.h"
 
 #include <ctype.h>
 #include <dirent.h>
@@ -55,6 +55,132 @@
 #include "log.h"
 #include "util.h"
 
+#if defined(__ANDROID__)
+#include <linux/ptrace.h>
+#include <asm/ptrace.h>
+#include <sys/syscall.h>
+#include "capstone.h"
+#endif
+
+#if defined(__i386__) || defined(__arm__) || defined(__powerpc__)
+#define REG_TYPE uint32_t
+#define REG_PM   PRIx32
+#define REG_PD   "0x%08"
+#elif defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__)
+#define REG_TYPE uint64_t
+#define REG_PM   PRIx64
+#define REG_PD   "0x%016"
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+#define MAX_INSTR_SZ 16
+#elif defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)
+#define MAX_INSTR_SZ 4
+#elif defined(__aarch64__)
+#define MAX_INSTR_SZ 8
+#endif
+
+#ifdef __ANDROID__
+#ifndef WIFCONTINUED
+#define WIFCONTINUED(x) WEXITSTATUS(0)
+#endif
+#endif
+
+#if defined(__ANDROID__)
+#if defined(__NR_process_vm_readv)
+static ssize_t honggfuzz_process_vm_readv(pid_t pid,
+            const struct iovec *lvec,
+            unsigned long liovcnt,
+            const struct iovec *rvec,
+            unsigned long riovcnt,
+            unsigned long flags)
+{
+	return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
+}
+# define process_vm_readv honggfuzz_process_vm_readv
+#else                           /* defined(__NR_process_vm_readv) */
+# define process_vm_readv(...) (errno = ENOSYS, -1)
+#endif                           /* !defined(__NR_process_vm_readv) */
+
+// Naming compatibilities
+#if !defined(PT_TRACE_ME)
+# define PT_TRACE_ME PTRACE_TRACEME
+#endif
+
+#if !defined(PT_READ_I)
+# define PT_READ_I PTRACE_PEEKTEXT
+#endif
+
+#if !defined(PT_READ_D)
+# define PT_READ_D PTRACE_PEEKDATA
+#endif
+
+#if !defined(PT_READ_U)
+# define PT_READ_U PTRACE_PEEKUSR
+#endif
+
+#if !defined(PT_WRITE_I)
+# define PT_WRITE_I PTRACE_POKETEXT
+#endif
+
+#if !defined(PT_WRITE_D)
+# define PT_WRITE_D PTRACE_POKEDATA
+#endif
+
+#if !defined(PT_WRITE_U)
+# define PT_WRITE_U PTRACE_POKEUSR
+#endif
+
+#if !defined(PT_CONT)
+# define PT_CONT PTRACE_CONT
+#endif
+
+#if !defined(PT_CONTINUE)
+# define PT_CONTINUE PTRACE_CONT
+#endif
+
+#if !defined(PT_KILL)
+# define PT_KILL PTRACE_KILL
+#endif
+
+#if !defined(PT_STEP)
+# define PT_STEP PTRACE_SINGLESTEP
+#endif
+
+#if !defined(PT_GETFPREGS)
+# define PT_GETFPREGS PTRACE_GETFPREGS
+#endif
+
+#if !defined(PT_ATTACH)
+# define PT_ATTACH PTRACE_ATTACH
+#endif
+
+#if !defined(PT_DETACH)
+# define PT_DETACH PTRACE_DETACH
+#endif
+
+#if !defined(PT_SYSCALL)
+# define PT_SYSCALL PTRACE_SYSCALL
+#endif
+
+#if !defined(PT_SETOPTIONS)
+# define PT_SETOPTIONS PTRACE_SETOPTIONS
+#endif
+
+#if !defined(PT_GETEVENTMSG)
+# define PT_GETEVENTMSG PTRACE_GETEVENTMSG
+#endif
+
+#if !defined(PT_GETSIGINFO)
+# define PT_GETSIGINFO PTRACE_GETSIGINFO
+#endif
+
+#if !defined(PT_SETSIGINFO)
+# define PT_SETSIGINFO PTRACE_SETSIGINFO
+#endif
+
+#endif                           /* defined(__ANDROID__) */
+
 /*  *INDENT-OFF* */
 struct {
     bool important;
@@ -76,7 +202,7 @@
 };
 /*  *INDENT-ON* */
 
-static size_t arch_getProcMem(pid_t pid, uint8_t * buf, size_t len, uint64_t pc)
+static size_t arch_getProcMem(pid_t pid, uint8_t * buf, size_t len, REG_TYPE pc)
 {
     /*
      * Let's try process_vm_readv first
@@ -93,6 +219,9 @@
         return len;
     }
 
+    // Debug if failed since it shouldn't happen very often
+    LOGMSG_P(l_DEBUG, "process_vm_readv() failed");
+
     /*
      * Ok, let's do it via ptrace() then.
      * len must be aligned to the sizeof(long)
@@ -115,6 +244,9 @@
     return memsz;
 }
 
+// Non i386 / x86_64 ISA fail build due to unused pid argument
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
 uint64_t arch_ptraceGetCustomPerf(honggfuzz_t * hfuzz, pid_t pid)
 {
     if ((hfuzz->dynFileMethod & _HF_DYNFILE_CUSTOM) == 0) {
@@ -197,8 +329,9 @@
 #endif
     return 0ULL;
 }
+#pragma GCC diagnostic pop
 
-static bool arch_getPC(pid_t pid, uint64_t * pc)
+static bool arch_getPC(pid_t pid, REG_TYPE *pc, REG_TYPE *status_reg)
 {
     char buf[1024];
     struct iovec pt_iov = {
@@ -266,6 +399,7 @@
     if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
         struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
         *pc = r32->eip;
+        *status_reg = r32->eflags;
         return true;
     }
     /*
@@ -274,6 +408,7 @@
     if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
         struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
         *pc = r64->ip;
+        *status_reg = r64->flags;
         return true;
     }
     LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
@@ -286,10 +421,23 @@
     };
     if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
         struct user_regs_struct_32 *r32 = (struct user_regs_struct_32 *)buf;
+
 #ifndef ARM_pc
+#ifdef __ANDROID__              /* Building with NDK headers */
+#define ARM_pc uregs[15]
+#else                           /* Building with glibc headers */
 #define ARM_pc 15
+#endif
 #endif                          /* ARM_pc */
+
+#ifdef __ANDROID__
+        *pc = r32->ARM_pc;
+        *status_reg = r32->ARM_cpsr;
+#else
         *pc = r32->uregs[ARM_pc];
+        *status_reg = r32->uregs[ARM_cpsr];
+#endif
+
         return true;
     }
     LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
@@ -305,6 +453,7 @@
     if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
         struct user_regs_struct_64 *r64 = (struct user_regs_struct_64 *)buf;
         *pc = r64->pc;
+        *status_reg = r64->pstate;
         return true;
     }
     LOGMSG(l_WARN, "Unknown PTRACE_GETREGSET structure size: '%d'", pt_iov.iov_len);
@@ -375,18 +524,20 @@
     return false;
 }
 
-static void arch_getInstrStr(pid_t pid, uint64_t * pc, char *instr)
+static void arch_getInstrStr(pid_t pid, REG_TYPE *pc, char *instr)
 {
     /*
      * We need a value aligned to 8
      * which is sizeof(long) on 64bit CPU archs (on most of them, I hope;)
      */
-    uint8_t buf[16];
+    uint8_t buf[MAX_INSTR_SZ];
     size_t memsz;
 
+    REG_TYPE status_reg = 0;
+
     snprintf(instr, _HF_INSTR_SZ, "%s", "[UNKNOWN]");
 
-    if (!arch_getPC(pid, pc)) {
+    if (!arch_getPC(pid, pc, &status_reg)) {
         LOGMSG(l_WARN, "Current architecture not supported for disassembly");
         return;
     }
@@ -396,8 +547,49 @@
         return;
     }
 
+#if !defined(__ANDROID__)
     arch_bfdDisasm(pid, buf, memsz, instr);
 
+#else
+#if defined(__arm__)
+    cs_arch arch = CS_ARCH_ARM;
+    cs_mode mode = (status_reg & 0x20) ? CS_MODE_THUMB : CS_MODE_ARM;
+#elif defined(__aarch64__)
+    // We shouldn't need any execution detection logic here
+    cs_arch arch = CS_ARCH_ARM64;
+    cs_mode mode = CS_MODE_ARM;
+#elif defined(__i386__)
+    cs_arch arch = CS_ARCH_X86;
+    cs_mode mode = CS_MODE_32;
+#elif defined(__x86_64__)
+    cs_arch arch = CS_ARCH_X86;
+    cs_mode mode = CS_MODE_64;
+#else
+    LOGMSG(l_ERROR, "Unknown/unsupported Android CPU architecture");
+#endif
+
+    csh handle;
+    cs_err err = cs_open(arch, mode, &handle);
+    if (err != CS_ERR_OK) {
+        LOGMSG(l_WARN, "Capstone initilization failed: '%s'", cs_strerror(err));
+        return;
+    }
+
+    cs_insn *insn;
+    size_t count = cs_disasm(handle, buf, sizeof(buf), *pc, 0, &insn);
+
+    if (count < 1) {
+        LOGMSG(l_WARN, "Couldn't disassemble the assembler instructions' stream: '%s'",
+                cs_strerror(cs_errno(handle)));
+        cs_close(&handle);
+        return;
+    }
+
+    snprintf(instr, _HF_INSTR_SZ, "%s %s", insn[0].mnemonic, insn[0].op_str);
+    cs_free(insn, count);
+    cs_close(&handle);
+#endif
+
     for (int x = 0; instr[x] && x < _HF_INSTR_SZ; x++) {
         if (instr[x] == '/' || instr[x] == '\\' || isspace(instr[x])
             || !isprint(instr[x])) {
@@ -423,8 +615,18 @@
     util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "INSTRUCTION: %s\n", instr);
     util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "STACK:\n");
     for (size_t i = 0; i < funcCnt; i++) {
-        util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " <0x%016" PRIx64 "> [%s():%d]\n",
-                       (uint64_t) (long)funcs[i].pc, funcs[i].func, funcs[i].line);
+#ifdef __HF_USE_CAPSTONE__
+        util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " <"REG_PD REG_PM "> ",
+                       (REG_TYPE) (long)funcs[i].pc, funcs[i].func, funcs[i].line);
+        if (funcs[i].func[0] != '\0')
+             util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "[%s + 0x%x]\n", 
+                     funcs[i].func, funcs[i].line);
+        else
+            util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), "[]\n");
+#else
+        util_ssnprintf(fuzzer->report, sizeof(fuzzer->report), " <"REG_PD REG_PM "> [%s():%u]\n",
+                       (REG_TYPE) (long)funcs[i].pc, funcs[i].func, funcs[i].line);
+#endif
     }
 
     return;
@@ -432,7 +634,7 @@
 
 static void arch_ptraceSaveData(honggfuzz_t * hfuzz, pid_t pid, fuzzer_t * fuzzer)
 {
-    uint64_t pc = 0ULL;
+    REG_TYPE pc = 0;
 
     char instr[_HF_INSTR_SZ] = "\x00";
     siginfo_t si;
@@ -446,7 +648,7 @@
 
     LOGMSG(l_DEBUG,
            "Pid: %d, signo: %d, errno: %d, code: %d, addr: %p, pc: %"
-           PRIx64 ", instr: '%s'", pid, si.si_signo, si.si_errno, si.si_code, si.si_addr, pc,
+           REG_PM ", instr: '%s'", pid, si.si_signo, si.si_errno, si.si_code, si.si_addr, pc,
            instr);
 
     if (si.si_addr < hfuzz->ignoreAddr) {
@@ -459,14 +661,14 @@
     char newname[PATH_MAX];
     if (hfuzz->saveUnique) {
         snprintf(newname, sizeof(newname),
-                 "%s.PC.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s.%s",
+                 "%s.PC.%" REG_PM ".CODE.%d.ADDR.%p.INSTR.%s.%s.%s",
                  arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr,
                  instr, fuzzer->origFileName, hfuzz->fileExtn);
     } else {
         char localtmstr[PATH_MAX];
         util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr));
         snprintf(newname, sizeof(newname),
-                 "%s.PC.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s.%s",
+                 "%s.PC.%" REG_PM ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s.%s",
                  arch_sigs[si.si_signo].descr, pc, si.si_code, si.si_addr,
                  instr, localtmstr, pid, fuzzer->origFileName, hfuzz->fileExtn);
     }
@@ -476,6 +678,8 @@
     } else {
         if (errno == EEXIST) {
             LOGMSG(l_INFO, "It seems that '%s' already exists, skipping", newname);
+            // Don't bother unwinding & generating reports for duplicate crashes
+            return;
         } else {
             LOGMSG_P(l_ERROR, "Couldn't link '%s' to '%s'", fuzzer->fileName, newname);
         }
@@ -488,8 +692,12 @@
         ,
     };
 
+#if !defined(__ANDROID__)
     size_t funcCnt = arch_unwindStack(pid, funcs);
     arch_bfdResolveSyms(pid, funcs, funcCnt);
+#else
+    size_t funcCnt = arch_unwindStack(pid, funcs);
+#endif
 
     arch_ptraceGenerateReport(pid, fuzzer, funcs, funcCnt, &si, instr);
 }
@@ -512,13 +720,25 @@
     }
 
     if (WIFSTOPPED(status)) {
+        int curStatus = WSTOPSIG(status);
+
         /*
          * If it's an interesting signal, save the testcase
          */
         if (arch_sigs[WSTOPSIG(status)].important) {
             arch_ptraceSaveData(hfuzz, pid, fuzzer);
+
+            /* 
+             * An kind of ugly (although necessary) hack due to custom signal handlers
+             * in Android from debuggerd. If we pass one of the monitored signals, 
+             * we'll end-up running the processing routine twice. A cost that we 
+             * don't want to pay.
+             */
+#if defined(__ANDROID__)
+            curStatus = SIGINT;
+#endif
         }
-        ptrace(PT_CONTINUE, pid, 0, WSTOPSIG(status));
+        ptrace(PT_CONTINUE, pid, 0, curStatus);
         return;
     }
 
diff --git a/linux/ptrace.h b/linux/ptrace_utils.h
similarity index 93%
rename from linux/ptrace.h
rename to linux/ptrace_utils.h
index 7d4215f..ec3d7a0 100644
--- a/linux/ptrace.h
+++ b/linux/ptrace_utils.h
@@ -21,8 +21,8 @@
  *
  */
 
-#ifndef _LINUX_PTRACE_H_
-#define _LINUX_PTRACE_H_
+#ifndef _LINUX_PTRACE_UTILS_H_
+#define _LINUX_PTRACE_UTILS_H_
 
 extern bool arch_ptraceEnable(honggfuzz_t * fuzz);
 extern void arch_ptraceAnalyze(honggfuzz_t * fuzz, int status, pid_t pid, fuzzer_t * fuzzer);
diff --git a/linux/unwind.c b/linux/unwind.c
index b612da9..6a585f4 100644
--- a/linux/unwind.c
+++ b/linux/unwind.c
@@ -28,33 +28,69 @@
 
 #include "log.h"
 
-size_t arch_unwindStack(pid_t pid, funcs_t * funcs)
+#if defined(__ANDROID__)
+#include <sys/endian.h>         /* For __BYTE_ORDER */
+#endif
+
+/*
+ * WARNING: Ensure that _UPT-info structs are not shared between threads
+ * http://www.nongnu.org/libunwind/man/libunwind-ptrace(3).html
+ */
+
+/*
+ * TODO: Subtract from load map to have relative PC stored in report file. 
+ * link_map seems to be the easiest road for that.
+ */
+
+// libunwind error codes used for debugging
+static const char *UNW_ER[] = {
+    "UNW_ESUCCESS",             /* no error */
+    "UNW_EUNSPEC",              /* unspecified (general) error */
+    "UNW_ENOMEM",               /* out of memory */
+    "UNW_EBADREG",              /* bad register number */
+    "UNW_EREADONLYREG",         /* attempt to write read-only register */
+    "UNW_ESTOPUNWIND",          /* stop unwinding */
+    "UNW_EINVALIDIP",           /* invalid IP */
+    "UNW_EBADFRAME",            /* bad frame */
+    "UNW_EINVAL",               /* unsupported operation or bad value */
+    "UNW_EBADVERSION",          /* unwind info has unsupported version */
+    "UNW_ENOINFO"               /* no unwind info found */
+};
+
+#ifndef __ANDROID__
+size_t arch_unwindStack(pid_t pid, funcs_t *funcs)
 {
-    size_t ret = 0;
+    size_t frames = 0;
     void *ui = NULL;
 
     unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
     if (!as) {
-        LOGMSG(l_ERROR, "unw_create_addr_space(pid='%d') failed", pid);
+        LOGMSG(l_ERROR, "[pid='%d'] unw_create_addr_space failed", pid);
         goto out;
     }
 
     ui = _UPT_create(pid);
     if (ui == NULL) {
-        LOGMSG(l_ERROR, "_UPT_create(pid='%d') failed", pid);
+        LOGMSG(l_ERROR, "[pid='%d'] _UPT_create failed", pid);
         goto out;
     }
 
     unw_cursor_t c;
-    if (unw_init_remote(&c, as, ui) != 0) {
-        LOGMSG(l_ERROR, "unw_init_remote(pid='%d') failed", pid);
+    int ret = unw_init_remote(&c, as, ui);
+    if (ret < 0) {
+        LOGMSG(l_ERROR, "[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
         goto out;
     }
 
-    for (ret = 0; unw_step(&c) > 0 && ret < _HF_MAX_FUNCS; ret++) {
+    for (frames = 0; unw_step(&c) > 0 && frames < _HF_MAX_FUNCS; frames++) {
         unw_word_t ip;
-        unw_get_reg(&c, UNW_REG_IP, &ip);
-        funcs[ret].pc = (void *)ip;
+        ret = unw_get_reg(&c, UNW_REG_IP, &ip);
+        if (ret < 0) {
+            LOMGSG(l_ERROR, "[pid='%d'] [%d] failed to read IP (%s)", pid, frames, UNW_ER[-ret]);
+            funcs[ret].pc = 0;
+        }
+        else
+            funcs[ret].pc = (void *)ip;
     }
 
  out:
@@ -62,3 +98,81 @@
     as ? unw_destroy_addr_space(as) : 0;
     return ret;
 }
+
+#else                          /* !defined(__ANDROID__) */
+size_t arch_unwindStack(pid_t pid, funcs_t *funcs)
+{
+    size_t num_frames = 0;    
+    struct UPT_info *ui = NULL;
+    unw_addr_space_t as = NULL;
+
+    as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
+    if (!as) {
+        LOGMSG(l_ERROR, "[pid='%d'] unw_create_addr_space failed", pid);
+        goto out;
+    }
+
+    ui = (struct UPT_info*)_UPT_create(pid);
+    if (ui == NULL) {
+        LOGMSG(l_ERROR, "[pid='%d'] _UPT_create failed", pid);
+        goto out;
+    }
+
+    unw_cursor_t cursor;
+    int ret = unw_init_remote(&cursor, as, ui);
+    if (ret < 0) {
+        LOGMSG(l_ERROR, "[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
+        goto out;
+    }
+
+    do {
+        unw_word_t pc = 0, offset = 0;
+        char buf[_HF_FUNC_NAME_SZ] = { 0 };
+
+        unw_proc_info_t frameInfo;
+        ret = unw_get_proc_info(&cursor, &frameInfo);
+        if (ret < 0) {
+            LOGMSG(l_DEBUG, "[pid='%d'] [%d] unw_get_proc_info (%s)",
+                    pid, num_frames, UNW_ER[-ret]);
+            // Not safe to keep reading
+            goto out;
+        }
+
+        ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
+        if (ret < 0) {
+            LOGMSG(l_ERROR, "[pid='%d'] [%d] failed to read IP (%s)",
+                    pid, num_frames, UNW_ER[-ret]);
+            // We don't want to try to extract info from an arbitrary IP
+            // TODO: Maybe abort completely (goto out))
+            goto skip_frame_info;
+        }
+
+        ret = unw_get_proc_name(&cursor, buf, sizeof(buf), &offset);
+        if (ret < 0) {
+            LOGMSG(l_DEBUG, "[pid='%d'] [%d] unw_get_proc_name() failed (%s)",
+                    pid, num_frames, UNW_ER[-ret]);
+            buf[0] = '\0';
+        }
+
+skip_frame_info:
+        // Compared to bfd, line var plays the role of offset from func_name
+        // Reports format is adjusted accordingly to reflect in saved file
+        funcs[num_frames].line = offset;
+        funcs[num_frames].pc = (void *)pc;
+        memcpy(funcs[num_frames].func, buf, sizeof(funcs[num_frames].func));
+
+        num_frames++;
+
+        ret = unw_step(&cursor);
+    } while (ret > 0 && num_frames < _HF_MAX_FUNCS);
+
+ out:
+    ui ? _UPT_destroy(ui) : NULL;
+    as ? unw_destroy_addr_space(as) : NULL;
+
+    ui = NULL;
+    as = NULL;
+
+    return num_frames;
+}
+#endif                          /* defined(__ANDROID__) */
diff --git a/third_party/android/patches/aarch64-libunwind.patch b/third_party/android/patches/aarch64-libunwind.patch
new file mode 100644
index 0000000..b156800
--- /dev/null
+++ b/third_party/android/patches/aarch64-libunwind.patch
@@ -0,0 +1,43 @@
+--- libunwind/include/libunwind-aarch64.h	2015-08-03 19:24:10.000000000 +0300
++++ patches/libunwind-aarch64.h	2015-08-05 05:22:46.000000000 +0300
+@@ -168,15 +168,37 @@
+   }
+ unw_tdep_save_loc_t;
+ 
+-
+ /* On AArch64, we can directly use ucontext_t as the unwind context.  */
+ typedef ucontext_t unw_tdep_context_t;
+ 
+ #include "libunwind-common.h"
+ #include "libunwind-dynamic.h"
+ 
+-#define unw_tdep_getcontext(uc)         (getcontext (uc), 0)
+-#define unw_tdep_is_fpreg               UNW_ARCH_OBJ(is_fpreg)
++/* There is no getcontext in Android. */
++#define unw_tdep_getcontext(uc) (({                 \
++  unw_tdep_context_t *unw_ctx = (uc);                   \
++  register uint64_t *unw_base asm ("x0") = (uint64_t*) unw_ctx->uc_mcontext.regs;       \
++  __asm__ __volatile__ (                        \
++     "stp x0, x1, [%[base], #0]\n" \
++     "stp x2, x3, [%[base], #16]\n" \
++     "stp x4, x5, [%[base], #32]\n" \
++     "stp x6, x7, [%[base], #48]\n" \
++     "stp x8, x9, [%[base], #64]\n" \
++     "stp x10, x11, [%[base], #80]\n" \
++     "stp x12, x13, [%[base], #96]\n" \
++     "stp x14, x13, [%[base], #112]\n" \
++     "stp x16, x17, [%[base], #128]\n" \
++     "stp x18, x19, [%[base], #144]\n" \
++     "stp x20, x21, [%[base], #160]\n" \
++     "stp x22, x23, [%[base], #176]\n" \
++     "stp x24, x25, [%[base], #192]\n" \
++     "stp x26, x27, [%[base], #208]\n" \
++     "stp x28, x29, [%[base], #224]\n" \
++     "str x30, [%[base], #240]\n" \
++     "mov x1, sp\n" \
++     "stp x1, x30, [%[base], #248]\n" \
++     : [base] "+r" (unw_base) : : "x1", "memory"); \
++  }), 0)
+ 
+ extern int unw_tdep_is_fpreg (int);
+ 
diff --git a/third_party/android/patches/x86-libunwind.patch b/third_party/android/patches/x86-libunwind.patch
new file mode 100644
index 0000000..aee4751
--- /dev/null
+++ b/third_party/android/patches/x86-libunwind.patch
@@ -0,0 +1,29 @@
+--- libunwind/src/x86/Gos-linux.c	2015-08-03 19:24:10.000000000 +0300
++++ patches/Gos-linux.c	2015-08-05 05:34:22.000000000 +0300
+@@ -283,7 +283,9 @@
+ x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
+ {
+   struct cursor *c = (struct cursor *) cursor;
++#if !defined(__ANDROID__)
+   ucontext_t *uc = c->uc;
++#endif
+ 
+   /* Ensure c->pi is up-to-date.  On x86, it's relatively common to be
+      missing DWARF unwind info.  We don't want to fail in that case,
+@@ -296,12 +298,16 @@
+       struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
+ 
+       Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
++#if !defined(__ANDROID__)
+       sigreturn (sc);
++#endif
+     }
+   else
+     {
+       Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip);
++#if !defined(__ANDROID__)
+       setcontext (uc);
++#endif
+     }
+   return -UNW_EINVAL;
+ }
diff --git a/third_party/android/scripts/compile-capstone.sh b/third_party/android/scripts/compile-capstone.sh
new file mode 100755
index 0000000..5474bbb
--- /dev/null
+++ b/third_party/android/scripts/compile-capstone.sh
@@ -0,0 +1,121 @@
+#!/bin/bash
+#
+#   honggfuzz capstone build help script
+#   -----------------------------------------
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+if [ -z "$NDK" ]; then
+  # Search in $PATH
+  if [[ $(which ndk-build) != "" ]]; then
+    $NDK=$(dirname $(which ndk-build))
+  else
+    echo "[-] Could not detect Android NDK dir"
+    exit 1
+  fi
+fi 
+
+if [ $# -ne 2 ]; then
+  echo "[-] Invalid arguments"
+  echo "[!] $0 <CAPSTONE_DIR> <ARCH>"
+  echo "    ARCH: arm arm64 x86 x86_64"
+  exit 1
+fi
+
+readonly CAPSTONE_DIR=$1
+
+# Fetch if not already there
+if [ ! -d $CAPSTONE_DIR ]; then
+    echo "[!] capstone not found. Fetching a fresh copy"
+    git clone https://github.com/aquynh/capstone $CAPSTONE_DIR
+fi
+
+case "$2" in
+  arm|arm64|x86|x86_64)
+    readonly ARCH=$2
+    if [ ! -d $CAPSTONE_DIR/$ARCH ] ; then mkdir -p $CAPSTONE_DIR/$ARCH; fi
+    ;;
+  *)
+    echo "[-] Invalid CPU architecture"
+    exit 1
+    ;;
+esac
+
+case "$ARCH" in
+  arm)
+    CS_ARCH=arm
+    CS_BUILD_BIN="./make.sh cross-android $ARCH"
+    ;;
+  arm64)
+    CS_ARCH=aarch64
+    CS_BUILD_BIN="./make.sh cross-android $ARCH"
+    ;;
+  x86)
+    CS_ARCH=x86
+    CS_BUILD_BIN="make"
+    TOOLCHAIN=i686-linux-android
+    TOOLCHAIN_S=x86-4.9
+    ;;
+  x86_64)
+    CS_ARCH=x86
+    CS_BUILD_BIN="make"
+    TOOLCHAIN=x86_64-linux-android
+    TOOLCHAIN_S=x86_64-4.9
+    ;;
+esac
+
+# Capstone handles internally only Android ARM cross builds not Intel x86/x86_x64
+# We need to prepare the Android NDK toolchains manually for these builds
+if [[ "$ARCH" == "x86" || "$ARCH" == "x86_64" ]]; then
+  if [ -z "$NDK" ]; then
+    # Search in $PATH
+    if [[ $(which ndk-build) != "" ]]; then
+      $NDK=$(dirname $(which ndk-build))
+    else
+      echo "[-] Could not detect Android NDK dir"
+      exit 1
+    fi
+  fi
+
+  # Support both Linux & Darwin
+  HOST_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
+  HOST_ARCH=$(uname -m)
+
+  SYSROOT="$NDK/platforms/android-21/arch-$ARCH"
+  export CC="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-gcc --sysroot=$SYSROOT"
+  export CXX="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-g++ --sysroot=$SYSROOT"
+  export PATH="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin":$PATH
+  # We need to construct a cross variable that capstone Makefile can pick ar, strip & ranlib from
+  export CROSS="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-" CFLAGS="--sysroot=$SYSROOT" LDFLAGS="--sysroot=$SYSROOT"
+fi
+
+# Change workdir to simplify args
+cd $CAPSTONE_DIR
+
+# Build it
+make clean
+
+NDK=$NDK CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_ARCHS=$CS_ARCH \
+CAPSTONE_SHARED=no CAPSTONE_STATIC=yes \
+eval $CS_BUILD_BIN
+if [ $? -ne 0 ]; then
+    echo "[-] Compilation failed"
+    exit 1
+else
+    echo "[*] '$ARCH' libcapstone  available at '$CAPSTONE_DIR/$ARCH'"
+fi
+
+cp libcapstone.a $ARCH/
+
+# Revert workdir to caller
+cd -
diff --git a/third_party/android/scripts/compile-libunwind.sh b/third_party/android/scripts/compile-libunwind.sh
new file mode 100755
index 0000000..aac271f
--- /dev/null
+++ b/third_party/android/scripts/compile-libunwind.sh
@@ -0,0 +1,143 @@
+#!/bin/bash
+#
+#   honggfuzz libunwind build help script
+#   -----------------------------------------
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+if [ -z "$NDK" ]; then
+  # Search in $PATH
+  if [[ $(which ndk-build) != "" ]]; then
+    $NDK=$(dirname $(which ndk-build))
+  else
+    echo "[-] Could not detect Android NDK dir"
+    exit 1
+  fi
+fi 
+
+if [ $# -ne 2 ]; then
+  echo "[-] Invalid arguments"
+  echo "[!] $0 <LIBUNWIND_DIR> <ARCH>"
+  echo "    ARCH: arm arm64 x86 x86_64"
+  exit 1
+fi
+
+readonly LIBUNWIND_DIR=$1
+
+# Fetch if not already there
+if [ ! -d $LIBUNWIND_DIR ]; then
+    echo "[!] libunwind not found. Fetching a fresh copy"
+    git clone git://git.sv.gnu.org/libunwind.git $LIBUNWIND_DIR
+fi
+
+case "$2" in
+  arm|arm64|x86|x86_64)
+    readonly ARCH=$2
+    if [ ! -d $LIBUNWIND_DIR/$ARCH ] ; then mkdir -p $LIBUNWIND_DIR/$ARCH; fi
+    ;;
+  *)
+    echo "[-] Invalid architecture"
+    exit 1
+    ;;
+esac
+
+# Change workdir to simplify args
+cd $LIBUNWIND_DIR
+
+# Prepare toolchain
+case "$ARCH" in
+  arm)
+    TOOLCHAIN=arm-linux-androideabi
+    TOOLCHAIN_S=arm-linux-androideabi-4.9
+    ;;
+  arm64)
+    TOOLCHAIN=aarch64-linux-android
+    TOOLCHAIN_S=aarch64-linux-android-4.9
+    ;;
+  x86)
+    TOOLCHAIN=i686-linux-android
+    TOOLCHAIN_S=x86-4.9
+    ;;
+  x86_64)
+    TOOLCHAIN=x86_64-linux-android
+    TOOLCHAIN_S=x86_64-4.9
+    ;;
+esac
+
+# Apply patches required for Android
+# TODO: Automate global patching when all archs have been tested
+if [ "$ARCH" == "arm64" ]; then
+  # Missing libc functionality
+  patch -N --dry-run --silent include/libunwind-aarch64.h < ../patches/aarch64-libunwind.patch &>/dev/null
+  if [ $? -eq 0 ]; then
+    patch include/libunwind-aarch64.h < ../patches/aarch64-libunwind.patch
+    if [ $? -ne 0 ]; then
+      echo "[-] aarch64-libunwind patch failed"
+      exit 1
+    fi
+  fi
+fi
+
+if [ "$ARCH" == "x86" ]; then
+  # Missing syscalls
+  patch -N --dry-run --silent src/x86/Gos-linux.c < ../patches/x86-libunwind.patch &>/dev/null
+  if [ $? -eq 0 ]; then
+    patch src/x86/Gos-linux.c < ../patches/x86-libunwind.patch
+    if [ $? -ne 0 ]; then
+      echo "[-] x86-libunwind patch failed"
+      exit 1
+    fi
+  fi
+fi
+
+# Support both Linux & Darwin
+HOST_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
+HOST_ARCH=$(uname -m)
+
+SYSROOT="$NDK/platforms/android-21/arch-$ARCH"
+export CC="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-gcc --sysroot=$SYSROOT"
+export CXX="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-g++ --sysroot=$SYSROOT"
+export PATH="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin":$PATH
+
+if [ ! -f configure ]; then
+  autoreconf -i
+  if [ $? -ne 0 ]; then
+    echo "[-] autoreconf failed"
+    exit 1
+  fi
+  # Patch configure
+  sed -i -e 's/-lgcc_s/-lgcc/g' configure
+else
+  make clean
+  if [ $? -ne 0 ]; then
+    echo "[-] Old build detected, although clean failed. Consider manual clean-up."
+    exit 1
+  fi
+fi
+
+./configure --host=$TOOLCHAIN --disable-coredump
+if [ $? -ne 0 ]; then
+  echo "[-] configure failed"
+  exit 1
+fi
+
+make CFLAGS="-static" LDFLAGS="-static"
+if [ $? -ne 0 ]; then
+    echo "[-] Compilation failed"
+    cd -
+    exit 1
+else
+    echo "[*] '$ARCH' libunwind  available at '$LIBUNWIND_DIR/$ARCH'"
+    cp src/.libs/*.a $ARCH
+    cd -
+fi