Merge "Add support for getting TLS on all arches." into main
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 15e8319..00b861a 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -22,9 +22,14 @@
 #include <sys/ptrace.h>
 #include <sys/types.h>
 #include <sys/un.h>
+#include <sys/user.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
+#if defined(__i386__)
+#include <asm/ldt.h>
+#endif
+
 #include <cstdint>
 #include <limits>
 #include <map>
@@ -430,18 +435,12 @@
   return true;
 }
 
-static bool GetGuestRegistersFromCrashedProcess([[maybe_unused]] pid_t tid,
-                                                NativeBridgeGuestRegs* guest_regs) {
+static bool GetGuestRegistersFromCrashedProcess(pid_t tid, NativeBridgeGuestRegs* guest_regs) {
   auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(tid);
 
   uintptr_t header_ptr = 0;
   uintptr_t base = 0;
-#if defined(__x86_64__)
-  if (!PtracePeek(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr,
-                  "failed to read thread register for thread " + std::to_string(tid), &base)) {
-    return false;
-  }
-#elif defined(__aarch64__)
+#if defined(__aarch64__)
   // base is implicitly casted to uint64_t.
   struct iovec pt_iov {
     .iov_base = &base, .iov_len = sizeof(base),
@@ -451,6 +450,26 @@
     PLOG(ERROR) << "failed to read thread register for thread " << tid;
     return false;
   }
+#elif defined(__arm__)
+  if (ptrace(PTRACE_GET_THREAD_AREA, tid, nullptr, &base) == 0) {
+    PLOG(ERROR) << "failed to get thread area for thread " << tid;
+    return false;
+  }
+#elif defined(__i386__)
+  struct user_regs_struct regs;
+  struct iovec pt_iov = {.iov_base = &regs, .iov_len = sizeof(regs)};
+  if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) != 0) {
+    PLOG(ERROR) << "failed to get registers for thread " << tid;
+    return false;
+  }
+
+  struct user_desc desc;
+  desc.entry_number = regs.xgs >> 3;
+  if (ptrace(PTRACE_GET_THREAD_AREA, tid, desc.entry_number, &desc) != 0) {
+    PLOG(ERROR) << "failed to get thread area for thread " << tid;
+    return false;
+  }
+  base = desc.base_addr;
 #elif defined(__riscv)
   struct user_regs_struct regs;
   struct iovec pt_iov = {.iov_base = &regs, .iov_len = sizeof(regs)};
@@ -459,6 +478,11 @@
     return false;
   }
   base = reinterpret_cast<uintptr_t>(regs.tp);
+#elif defined(__x86_64__)
+  if (!PtracePeek(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr,
+                  "failed to read thread register for thread " + std::to_string(tid), &base)) {
+    return false;
+  }
 #else
   // TODO(b/339287219): Add case for Riscv host.
   return false;
@@ -487,9 +511,7 @@
   return true;
 }
 
-static void ReadGuestRegisters([[maybe_unused]] std::unique_ptr<unwindstack::Regs>* regs,
-                               pid_t tid) {
-  // TODO: remove [[maybe_unused]], when the ARM32 case is removed from the native bridge support.
+static void ReadGuestRegisters(std::unique_ptr<unwindstack::Regs>* regs, pid_t tid) {
   NativeBridgeGuestRegs guest_regs;
   if (!GetGuestRegistersFromCrashedProcess(tid, &guest_regs)) {
     return;
@@ -521,6 +543,17 @@
       g_guest_arch = Architecture::RISCV64;
       break;
     }
+#else
+    case NATIVE_BRIDGE_ARCH_ARM: {
+      unwindstack::arm_user_regs arm_user_regs = {};
+      regs->reset(unwindstack::RegsArm::Read(&arm_user_regs));
+      for (size_t i = 0; i < unwindstack::ARM_REG_LAST; i++) {
+        arm_user_regs.regs[i] = guest_regs.regs_arm.r[i];
+      }
+
+      g_guest_arch = Architecture::ARM32;
+      break;
+    }
 #endif
     default:
       break;
@@ -796,16 +829,17 @@
       ATRACE_NAME("engrave_tombstone");
       unwindstack::ArchEnum regs_arch = unwindstack::ARCH_UNKNOWN;
       switch (g_guest_arch) {
-        case Architecture::ARM64: {
+        case Architecture::ARM32:
+          regs_arch = unwindstack::ARCH_ARM;
+          break;
+        case Architecture::ARM64:
           regs_arch = unwindstack::ARCH_ARM64;
           break;
-        }
-        case Architecture::RISCV64: {
+        case Architecture::RISCV64:
           regs_arch = unwindstack::ARCH_RISCV64;
           break;
-        }
-        default: {
-        }
+        default:
+          break;
       }
       if (regs_arch == unwindstack::ARCH_UNKNOWN) {
         engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info,