[go: nahoru, domu]

[Android Unwinder] Add support for refuse to unwind

This CL adds the support for unwind instruction
10000000 00000000.

Bug: 1240698
Change-Id: Ie8b04daf034631518c4d13ab5471f22db4983b87
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3153978
Commit-Queue: Charlie Hu <chenleihu@google.com>
Reviewed-by: Mike Wittman <wittman@chromium.org>
Cr-Commit-Position: refs/heads/main@{#921309}
diff --git a/base/profiler/chrome_unwind_table_android.cc b/base/profiler/chrome_unwind_table_android.cc
index 16fe750a..f2652e4f 100644
--- a/base/profiler/chrome_unwind_table_android.cc
+++ b/base/profiler/chrome_unwind_table_android.cc
@@ -79,7 +79,7 @@
         CheckedNumeric<uintptr_t>(RegisterContextStackPointer(thread_context)) +
         offset;
     if (!new_sp.AssignIfValid(&RegisterContextStackPointer(thread_context))) {
-      return UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS;
+      return UnwindInstructionResult::kAborted;
     }
   } else if (GetTopBits(*instruction, 2) == 0b01) {
     // 01xxxxxx
@@ -89,7 +89,7 @@
         CheckedNumeric<uintptr_t>(RegisterContextStackPointer(thread_context)) -
         offset;
     if (!new_sp.AssignIfValid(&RegisterContextStackPointer(thread_context))) {
-      return UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS;
+      return UnwindInstructionResult::kAborted;
     }
   } else if (GetTopBits(*instruction, 4) == 0b1001) {
     // 1001nnnn (nnnn != 13,15)
@@ -109,25 +109,27 @@
     const uint8_t max_register_index = (*instruction++ & 0b00000111) + 4;
     for (int n = 4; n <= max_register_index; n++) {
       if (!PopRegister(thread_context, n)) {
-        return UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS;
+        return UnwindInstructionResult::kAborted;
       }
     }
     if (!PopRegister(thread_context, 14)) {
-      return UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS;
+      return UnwindInstructionResult::kAborted;
     }
+  } else if (*instruction == 0b10000000 && *(instruction + 1) == 0) {
+    // 10000000 00000000
+    // Refuse to unwind.
+    instruction += 2;
+    return UnwindInstructionResult::kAborted;
   } else if (GetTopBits(*instruction, 4) == 0b1000) {
-    // 1000iiii iiiiiiii
-    // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
     const uint32_t register_bitmask =
         ((*instruction & 0xf) << 8) + *(instruction + 1);
-    // 10000000 00000000 is reserved for 'Refused to unwind'.
-    DCHECK_NE(register_bitmask, 0ul);
     instruction += 2;
-
+    // 1000iiii iiiiiiii
+    // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
     for (int register_index = 4; register_index < 16; register_index++) {
       if (register_bitmask & (1 << (register_index - 4))) {
         if (!PopRegister(thread_context, register_index)) {
-          return UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS;
+          return UnwindInstructionResult::kAborted;
         }
       }
     }
@@ -145,7 +147,7 @@
     if (!pc_was_updated)
       thread_context->arm_pc = thread_context->arm_lr;
 
-    return UnwindInstructionResult::COMPLETED;
+    return UnwindInstructionResult::kCompleted;
   } else if (*instruction == 0b10110010) {
     // 10110010 uleb128
     // vsp = vsp + 0x204 + (uleb128 << 2)
@@ -156,12 +158,12 @@
         (CheckedNumeric<uintptr_t>(DecodeULEB128(instruction)) << 2) + 0x204;
 
     if (!new_sp.AssignIfValid(&RegisterContextStackPointer(thread_context))) {
-      return UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS;
+      return UnwindInstructionResult::kAborted;
     }
   } else {
     NOTREACHED();
   }
-  return UnwindInstructionResult::INSTRUCTION_PENDING;
+  return UnwindInstructionResult::kInstructionPending;
 }
 
 const uint8_t* GetFirstUnwindInstructionFromFunctionOffsetTableIndex(
diff --git a/base/profiler/chrome_unwind_table_android.h b/base/profiler/chrome_unwind_table_android.h
index 15e2d12..7c01c07 100644
--- a/base/profiler/chrome_unwind_table_android.h
+++ b/base/profiler/chrome_unwind_table_android.h
@@ -14,11 +14,10 @@
 
 namespace base {
 
-enum UnwindInstructionResult {
-  COMPLETED,                    // Signals the end of unwind process.
-  INSTRUCTION_PENDING,          // Continues to unwind next instruction.
-  STACK_POINTER_OUT_OF_BOUNDS,  // Stack pointer is out of bounds after
-                                // execution of unwind instruction.
+enum class UnwindInstructionResult {
+  kCompleted,           // Signals the end of unwind process.
+  kInstructionPending,  // Continues to unwind next instruction.
+  kAborted,             // Unable to unwind.
 };
 
 // Execute a single unwind instruction on the given thread_context,
diff --git a/base/profiler/chrome_unwind_table_android_unittest.cc b/base/profiler/chrome_unwind_table_android_unittest.cc
index 6d9dc02b..51538e8 100644
--- a/base/profiler/chrome_unwind_table_android_unittest.cc
+++ b/base/profiler/chrome_unwind_table_android_unittest.cc
@@ -19,7 +19,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0x10000004ul, thread_context.arm_sp);
@@ -35,7 +35,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0x10000014ul, thread_context.arm_sp);
@@ -50,7 +50,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0x10000100ul, thread_context.arm_sp);
@@ -65,7 +65,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
+            UnwindInstructionResult::kAborted);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0xffffffff, thread_context.arm_sp);
 }
@@ -79,7 +79,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0x0ffffffcul, thread_context.arm_sp);
@@ -95,7 +95,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0x0fffffecul, thread_context.arm_sp);
@@ -110,7 +110,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0x0fffff00ul, thread_context.arm_sp);
@@ -125,7 +125,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
+            UnwindInstructionResult::kAborted);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0x0ul, thread_context.arm_sp);
@@ -168,7 +168,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(100ul + register_index, thread_context.arm_sp);
@@ -183,7 +183,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::COMPLETED);
+            UnwindInstructionResult::kCompleted);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(114ul, thread_context.arm_pc);
 }
@@ -197,7 +197,7 @@
   bool pc_was_updated = true;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::COMPLETED);
+            UnwindInstructionResult::kCompleted);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(115ul, thread_context.arm_pc);
 }
@@ -233,7 +233,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_TRUE(pc_was_updated);
   ASSERT_EQ(current_instruction, instruction + 2);
   EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 4), thread_context.arm_sp);
@@ -285,7 +285,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, instruction + 2);
   EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 3), thread_context.arm_sp);
@@ -336,7 +336,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
+            UnwindInstructionResult::kAborted);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, instruction + 2);
   EXPECT_EQ(0xffffffff, thread_context.arm_sp);
@@ -358,6 +358,20 @@
   EXPECT_EQ(114ul, thread_context.arm_pc);
 }
 
+TEST(ChromeAndroidUnwindInstructionTest, TestRefuseToUnwind) {
+  RegisterContext thread_context = {};
+
+  const uint8_t instruction[] = {0b10000000, 0b0};
+  const uint8_t* current_instruction = instruction;
+
+  bool pc_was_updated = false;
+  ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
+                                     &thread_context),
+            UnwindInstructionResult::kAborted);
+  EXPECT_FALSE(pc_was_updated);
+  ASSERT_EQ(current_instruction, instruction + 2);
+}
+
 TEST(ChromeAndroidUnwindInstructionTest,
      TestPopRegistersIncludingR14MinRegisters) {
   RegisterContext thread_context = {};
@@ -387,7 +401,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 2), thread_context.arm_sp);
@@ -437,7 +451,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 6), thread_context.arm_sp);
@@ -487,7 +501,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 9), thread_context.arm_sp);
@@ -534,7 +548,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
+            UnwindInstructionResult::kAborted);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, &instruction + 1);
   EXPECT_EQ(0xffffffff, thread_context.arm_sp);
@@ -567,7 +581,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, increment_0 + sizeof(increment_0));
   // vsp + 0x204 + (0 << 2)
@@ -591,7 +605,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, increment_4 + sizeof(increment_4));
   EXPECT_EQ(0x10000214ul, thread_context.arm_sp);
@@ -615,7 +629,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::INSTRUCTION_PENDING);
+            UnwindInstructionResult::kInstructionPending);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction, increment_128 + sizeof(increment_128));
   EXPECT_EQ(0x10000404ul, thread_context.arm_sp);
@@ -634,7 +648,7 @@
   bool pc_was_updated = false;
   ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
                                      &thread_context),
-            UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
+            UnwindInstructionResult::kAborted);
   EXPECT_FALSE(pc_was_updated);
   ASSERT_EQ(current_instruction,
             increment_overflow + sizeof(increment_overflow));