blob: 8fc9d38392c4d37887b2d7ad37b99016d5b923f2 [file] [log] [blame]
Daniel Chenged0471b2019-05-10 11:43:361// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/immediate_crash.h"
6
7#include <stdint.h>
8
9#include <algorithm>
10
Daniel Chengf355d632019-05-14 17:25:3011#include "base/base_paths.h"
Daniel Chenged0471b2019-05-10 11:43:3612#include "base/containers/span.h"
13#include "base/files/file_path.h"
14#include "base/native_library.h"
15#include "base/optional.h"
Daniel Chengf355d632019-05-14 17:25:3016#include "base/path_service.h"
Daniel Chenged0471b2019-05-10 11:43:3617#include "base/strings/string_number_conversions.h"
18#include "build/build_config.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace base {
22
Daniel Cheng69359e92019-06-20 23:43:0223// Compile test.
24int TestImmediateCrashTreatedAsNoReturn() {
25 IMMEDIATE_CRASH();
26}
27
Daniel Chenged0471b2019-05-10 11:43:3628// iOS is excluded, since it doesn't support loading shared libraries.
29#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
30 defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) || \
31 defined(OS_FUCHSIA)
32
33// Checks that the IMMEDIATE_CRASH() macro produces specific instructions; see
34// comments in immediate_crash.h for the requirements.
35TEST(ImmediateCrashTest, ExpectedOpcodeSequence) {
36 // TestFunction1() and TestFunction2() are defined in a shared library in an
37 // attempt to guarantee that they are located next to each other.
38 NativeLibraryLoadError load_error;
Daniel Chengf355d632019-05-14 17:25:3039 FilePath helper_library_path;
40#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
Reid Klecknerc55cd142019-07-23 00:38:1741 // On Android M, DIR_EXE == /system/bin when running base_unittests.
42 // On Fuchsia, NativeLibrary understands the native convention that libraries
43 // are not colocated with the binary.
Daniel Chengf355d632019-05-14 17:25:3044 ASSERT_TRUE(PathService::Get(DIR_EXE, &helper_library_path));
45#endif
46 helper_library_path = helper_library_path.AppendASCII(
47 GetNativeLibraryName("immediate_crash_test_helper"));
Daniel Cheng79bb3cf22019-05-16 19:15:2948#if defined(OS_ANDROID) && defined(COMPONENT_BUILD)
49 helper_library_path = helper_library_path.ReplaceExtension(".cr.so");
50#endif
Daniel Chenged0471b2019-05-10 11:43:3651 // TODO(dcheng): Shouldn't GetNativeLibraryName just return a FilePath?
Daniel Chengf355d632019-05-14 17:25:3052 NativeLibrary helper_library =
53 LoadNativeLibrary(helper_library_path, &load_error);
Daniel Chenged0471b2019-05-10 11:43:3654 ASSERT_TRUE(helper_library)
55 << "shared library load failed: " << load_error.ToString();
56
57 // TestFunction1() and TestFunction2() each contain two IMMEDIATE_CRASH()
58 // invocations. IMMEDIATE_CRASH() should be treated as a noreturn sequence and
59 // optimized into the function epilogue. The general strategy is to find the
60 // return opcode, then scan the following bytes for the opcodes for two
61 // consecutive IMMEDIATE_CRASH() sequences.
62 void* a =
63 GetFunctionPointerFromNativeLibrary(helper_library, "TestFunction1");
64 ASSERT_TRUE(a);
65 void* b =
66 GetFunctionPointerFromNativeLibrary(helper_library, "TestFunction2");
67 ASSERT_TRUE(b);
68
69#if defined(ARCH_CPU_X86_FAMILY)
70
71 // X86 opcode reference:
72 // https://software.intel.com/en-us/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4
73 span<const uint8_t> function_body =
74 a < b ? make_span(static_cast<const uint8_t*>(a),
75 static_cast<const uint8_t*>(b))
76 : make_span(static_cast<const uint8_t*>(b),
77 static_cast<const uint8_t*>(a));
78 SCOPED_TRACE(HexEncode(function_body.data(), function_body.size_bytes()));
79
80 // Look for RETN opcode (0xC3). Note that 0xC3 is a substring of several
81 // other opcodes (VMRESUME, MOVNTI), and can also be encoded as part of an
82 // argument to another opcode. None of these other cases are expected to be
83 // present, so a simple byte scan should be Good Enoughâ„¢.
84 auto it = std::find(function_body.begin(), function_body.end(), 0xC3);
85 ASSERT_NE(function_body.end(), it) << "Failed to find return! ";
86
87 // Look for two IMMEDIATE_CRASH() opcode sequences.
Daniel Chenged0471b2019-05-10 11:43:3688 for (int i = 0; i < 2; ++i) {
Reid Klecknerc55cd142019-07-23 00:38:1789 // INT 3
Daniel Chenged0471b2019-05-10 11:43:3690 EXPECT_EQ(0xCC, *++it);
91 // UD2
92 EXPECT_EQ(0x0F, *++it);
93 EXPECT_EQ(0x0B, *++it);
Daniel Chenged0471b2019-05-10 11:43:3694 }
95
96#elif defined(ARCH_CPU_ARMEL)
97
98 // Routines loaded from a shared library will have the LSB in the pointer set
99 // if encoded as T32 instructions. The rest of this test assumes T32.
100 ASSERT_TRUE(reinterpret_cast<uintptr_t>(a) & 0x1)
101 << "Expected T32 opcodes but found A32 opcodes instead.";
102 ASSERT_TRUE(reinterpret_cast<uintptr_t>(b) & 0x1)
103 << "Expected T32 opcodes but found A32 opcodes instead.";
104
105 // Mask off the lowest bit.
106 a = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(a) & ~uintptr_t{0x1});
107 b = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(b) & ~uintptr_t{0x1});
108
109 // T32 opcode reference: https://developer.arm.com/docs/ddi0487/latest
110 span<const uint16_t> function_body =
111 a < b ? make_span(static_cast<const uint16_t*>(a),
112 static_cast<const uint16_t*>(b))
113 : make_span(static_cast<const uint16_t*>(b),
114 static_cast<const uint16_t*>(a));
115 SCOPED_TRACE(HexEncode(function_body.data(), function_body.size_bytes()));
116
117 // Look for the standard return opcode sequence (BX LR).
118 auto it = std::find(function_body.begin(), function_body.end(), 0x4770);
119 ASSERT_NE(function_body.end(), it) << "Failed to find return! ";
120
121 // Look for two IMMEDIATE_CRASH() opcode sequences.
Daniel Chenged0471b2019-05-10 11:43:36122 for (int i = 0; i < 2; ++i) {
Reid Klecknerc55cd142019-07-23 00:38:17123 // BKPT #0
124 EXPECT_EQ(0xBE00, *++it);
Daniel Cheng69359e92019-06-20 23:43:02125 // UDF #0
126 EXPECT_EQ(0xDE00, *++it);
Daniel Chenged0471b2019-05-10 11:43:36127 }
128
129#elif defined(ARCH_CPU_ARM64)
130
131 // A64 opcode reference: https://developer.arm.com/docs/ddi0487/latest
132 span<const uint32_t> function_body =
133 a < b ? make_span(static_cast<const uint32_t*>(a),
134 static_cast<const uint32_t*>(b))
135 : make_span(static_cast<const uint32_t*>(b),
136 static_cast<const uint32_t*>(a));
137 SCOPED_TRACE(HexEncode(function_body.data(), function_body.size_bytes()));
138
139 // Look for RET. There appears to be multiple valid encodings, so this is
140 // hardcoded to whatever clang currently emits...
141 auto it = std::find(function_body.begin(), function_body.end(), 0XD65F03C0);
142 ASSERT_NE(function_body.end(), it) << "Failed to find return! ";
143
144 // Look for two IMMEDIATE_CRASH() opcode sequences.
Daniel Chenged0471b2019-05-10 11:43:36145 for (int i = 0; i < 2; ++i) {
Reid Klecknerc55cd142019-07-23 00:38:17146 // BRK #0
147 EXPECT_EQ(0XD4200000, *++it);
Daniel Cheng69359e92019-06-20 23:43:02148 // HLT #0
149 EXPECT_EQ(0xD4400000, *++it);
Daniel Chenged0471b2019-05-10 11:43:36150 }
151
152#endif // defined(ARCH_CPU_X86_FAMILY)
153
154 UnloadNativeLibrary(helper_library);
155}
156
157#endif
158
159} // namespace base