diff --git a/include/dwarf.h b/include/dwarf.h
index 633868b..3fe3a3f 100644
--- a/include/dwarf.h
+++ b/include/dwarf.h
@@ -311,6 +311,7 @@ typedef struct dwarf_cursor
     unw_word_t ret_addr_column; /* column for return-address */
     unw_word_t eh_args[UNW_TDEP_NUM_EH_REGS];
     unsigned int eh_valid_mask;
+    unsigned int frame;
 
     dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS];
 
diff --git a/include/libunwind-aarch64.h b/include/libunwind-aarch64.h
index cd01e57..3be8251 100644
--- a/include/libunwind-aarch64.h
+++ b/include/libunwind-aarch64.h
@@ -168,15 +168,37 @@ typedef struct unw_tdep_save_loc
   }
 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/src/aarch64/Gstep.c b/src/aarch64/Gstep.c
index 0c35f98..2fe00ba 100644
--- a/src/aarch64/Gstep.c
+++ b/src/aarch64/Gstep.c
@@ -121,6 +121,30 @@ unw_step (unw_cursor_t *cursor)
   ret = dwarf_step (&c->dwarf);
   Debug(1, "dwarf_step()=%d\n", ret);
 
+  if (ret < 0 && c->dwarf.frame == 0)
+    {
+      /* If this is the first frame, the code may be executing garbage
+       * in the middle of nowhere. In this case, try using the lr as
+       * the pc.
+       */
+      unw_word_t lr;
+      if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_AARCH64_X30], &lr) >= 0)
+        {
+          if (lr != c->dwarf.ip)
+            {
+              ret = 1;
+              c->dwarf.ip = lr;
+            }
+        }
+    }
+
+  if (ret >= 0)
+  {
+    if (c->dwarf.ip >= 4)
+      c->dwarf.ip -= 4;
+    c->dwarf.frame++;
+  }
+
   if (unlikely (ret == -UNW_ESTOPUNWIND))
     return ret;
 
diff --git a/src/aarch64/init.h b/src/aarch64/init.h
index 0cedc1a..c418932 100644
--- a/src/aarch64/init.h
+++ b/src/aarch64/init.h
@@ -122,6 +122,7 @@ common_init (struct cursor *c, unsigned use_prev_instr)
   c->dwarf.pi_is_dynamic = 0;
   c->dwarf.hint = 0;
   c->dwarf.prev_rs = 0;
+  c->dwarf.frame = 0;
 
   return 0;
 }
diff --git a/src/arm/Gstep.c b/src/arm/Gstep.c
index 79f2dd2..28aa4c0 100644
--- a/src/arm/Gstep.c
+++ b/src/arm/Gstep.c
@@ -73,6 +73,39 @@ arm_exidx_step (struct cursor *c)
   return (c->dwarf.ip == 0) ? 0 : 1;
 }
 
+/* When taking a step back up the stack, the pc will point to the next
+ * instruction to execute, not the currently executing instruction. This
+ * function adjusts the pc to the currently executing instruction.
+ */
+static void adjust_ip(struct cursor *c)
+{
+  unw_word_t ip, value;
+  ip = c->dwarf.ip;
+
+  if (ip)
+    {
+      int adjust = 4;
+      if (ip & 1)
+        {
+          /* Thumb instructions, the currently executing instruction could be
+          * 2 or 4 bytes, so adjust appropriately.
+          */
+          unw_addr_space_t as;
+          unw_accessors_t *a;
+          void *arg;
+
+          as = c->dwarf.as;
+          a = unw_get_accessors (as);
+          arg = c->dwarf.as_arg;
+
+          if (ip < 5 || (*a->access_mem) (as, ip-5, &value, 0, arg) < 0 ||
+              (value & 0xe000f000) != 0xe000f000)
+            adjust = 2;
+        }
+      c->dwarf.ip -= adjust;
+    }
+}
+
 PROTECTED int
 unw_handle_signal_frame (unw_cursor_t *cursor)
 {
@@ -268,5 +301,28 @@ unw_step (unw_cursor_t *cursor)
             }
         }
     }
+
+  if (ret < 0 && c->dwarf.frame == 0)
+    {
+      /* If this is the first frame, the code may be executing garbage
+       * in the middle of nowhere. In this case, try using the lr as
+       * the pc.
+       */
+      unw_word_t lr;
+      if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R14], &lr) >= 0)
+        {
+          if (lr != c->dwarf.ip)
+            {
+              ret = 1;
+              c->dwarf.ip = lr;
+            }
+        }
+    }
+
+  if (ret >= 0)
+    {
+      c->dwarf.frame++;
+    }
+
   return ret == -UNW_ENOINFO ? 0 : 1;
 }
diff --git a/src/arm/init.h b/src/arm/init.h
index 6379d8e..8222c02 100644
--- a/src/arm/init.h
+++ b/src/arm/init.h
@@ -73,6 +73,7 @@ common_init (struct cursor *c, unsigned use_prev_instr)
   c->dwarf.pi_is_dynamic = 0;
   c->dwarf.hint = 0;
   c->dwarf.prev_rs = 0;
+  c->dwarf.frame = 0;
 
   return 0;
 }
diff --git a/src/ptrace/_UPT_access_fpreg.c b/src/ptrace/_UPT_access_fpreg.c
index e90ec47..50a4c25 100644
--- a/src/ptrace/_UPT_access_fpreg.c
+++ b/src/ptrace/_UPT_access_fpreg.c
@@ -46,8 +46,8 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
 #ifdef HAVE_TTRACE
 #       warning No support for ttrace() yet.
 #else
-        ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg] + i * sizeof(wp[i]),
-                wp[i]);
+        ptrace (PTRACE_POKEUSER, pid, (void*) (_UPT_reg_offset[reg] + i * sizeof(wp[i])),
+                (void*) wp[i]);
 #endif
         if (errno)
           return -UNW_EBADREG;
@@ -59,7 +59,7 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
 #       warning No support for ttrace() yet.
 #else
         wp[i] = ptrace (PTRACE_PEEKUSER, pid,
-                        _UPT_reg_offset[reg] + i * sizeof(wp[i]), 0);
+                        (void*) (_UPT_reg_offset[reg] + i * sizeof(wp[i])), 0);
 #endif
         if (errno)
           return -UNW_EBADREG;
@@ -100,6 +100,14 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
 #endif
   return 0;
 }
+#elif defined(__aarch64__)
+int
+_UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
+           int write, void *arg)
+{
+# pragma message("_UPT_access_fpreg is not implemented and not currently used.")
+  return -UNW_EBADREG;
+}
 #else
 #error Fix me
 #endif
diff --git a/src/ptrace/_UPT_access_reg.c b/src/ptrace/_UPT_access_reg.c
index ae71608..8d40bcc 100644
--- a/src/ptrace/_UPT_access_reg.c
+++ b/src/ptrace/_UPT_access_reg.c
@@ -32,6 +32,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #   include <asm/ptrace_offsets.h>
 # endif
 # include "tdep-ia64/rse.h"
+#elif defined(__aarch64__)
+# include <sys/uio.h>
 #endif
 
 #if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
@@ -239,13 +241,13 @@ _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
 #else
   errno = 0;
   if (write)
-    ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg], *val);
+    ptrace (PTRACE_POKEUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], (void*) *val);
   else {
 #if UNW_DEBUG
     Debug(16, "ptrace PEEKUSER pid: %lu , reg: %lu , offs: %lu\n", (unsigned long)pid, (unsigned long)reg,
         (unsigned long)_UPT_reg_offset[reg]);
 #endif
-    *val = ptrace (PTRACE_PEEKUSER, pid, _UPT_reg_offset[reg], 0);
+    *val = ptrace (PTRACE_PEEKUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], 0);
   }
   if (errno) {
 #if UNW_DEBUG
@@ -304,6 +306,60 @@ _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
   Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno));
   return -UNW_EBADREG;
 }
+#elif HAVE_DECL_PT_GETREGSET
+int
+_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
+         int write, void *arg)
+{
+  struct UPT_info *ui = arg;
+  pid_t pid = ui->pid;
+#if defined(__aarch64__)
+  struct user_pt_regs regs;
+  struct iovec io;
+  io.iov_base = &regs;
+  io.iov_len = sizeof(regs);
+
+#if UNW_DEBUG
+  Debug(16, "using getregset: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write);
+
+  if (write)
+    Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val);
+#endif
+  if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1)
+    goto badreg;
+  if (write)
+    {
+      if (reg == UNW_AARCH64_SP)
+        regs.sp = *val;
+      else if (reg == UNW_AARCH64_PC)
+        regs.pc = *val;
+      else if (reg < UNW_AARCH64_SP)
+        regs.regs[reg] = *val;
+      else
+        goto badreg;
+      if (ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1)
+        goto badreg;
+    }
+  else
+    {
+      if (reg == UNW_AARCH64_SP)
+        *val = regs.sp;
+      else if (reg == UNW_AARCH64_PC)
+        *val = regs.pc;
+      else if (reg < UNW_AARCH64_SP)
+        *val = regs.regs[reg];
+      else
+        goto badreg;
+    }
+#else
+#error Unsupported architecture for getregset
+#endif
+  return 0;
+
+ badreg:
+  Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno));
+  return -UNW_EBADREG;
+}
 #else
 #error Port me
 #endif
diff --git a/src/x86/Gos-linux.c b/src/x86/Gos-linux.c
index 17aebc2..bafca96 100644
--- a/src/x86/Gos-linux.c
+++ b/src/x86/Gos-linux.c
@@ -283,7 +283,9 @@ HIDDEN int
 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 @@ x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
       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/src/x86/Gstep.c b/src/x86/Gstep.c
index 10e2cbc..49a830d 100644
--- a/src/x86/Gstep.c
+++ b/src/x86/Gstep.c
@@ -110,6 +110,20 @@ unw_step (unw_cursor_t *cursor)
       else
         c->dwarf.ip = 0;
     }
+
+  if (ret >= 0)
+    {
+      if (c->dwarf.ip)
+        {
+          /* Adjust the pc to the instruction before. */
+          c->dwarf.ip--;
+        }
+      c->dwarf.frame++;
+    }
+
+  if (unlikely (ret <= 0))
+    return 0;
+
   ret = (c->dwarf.ip == 0) ? 0 : 1;
   Debug (2, "returning %d\n", ret);
   return ret;
diff --git a/src/x86/init.h b/src/x86/init.h
index 027aedc..4218aa3 100644
--- a/src/x86/init.h
+++ b/src/x86/init.h
@@ -65,6 +65,7 @@ common_init (struct cursor *c, unsigned use_prev_instr)
   c->dwarf.pi_is_dynamic = 0;
   c->dwarf.hint = 0;
   c->dwarf.prev_rs = 0;
+  c->dwarf.frame = 0;
 
   return 0;
 }
diff --git a/src/x86_64/init.h b/src/x86_64/init.h
index 442b2bf..737b9f7 100644
--- a/src/x86_64/init.h
+++ b/src/x86_64/init.h
@@ -84,6 +84,7 @@ common_init (struct cursor *c, unsigned use_prev_instr)
   c->dwarf.pi_is_dynamic = 0;
   c->dwarf.hint = 0;
   c->dwarf.prev_rs = 0;
+  c->dwarf.frame = 0;
 
   return 0;
 }
