1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/immediate_crash.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include <optional>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include "base/base_paths.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/clang_profiling_buildflags.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/path_service.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/scoped_native_library.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
19*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
20*6777b538SAndroid Build Coastguard Worker #include "build/buildflag.h"
21*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker namespace base {
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker namespace {
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker // If ImmediateCrash() is not treated as noreturn by the compiler, the compiler
28*6777b538SAndroid Build Coastguard Worker // will complain that not all paths through this function return a value.
TestImmediateCrashTreatedAsNoReturn()29*6777b538SAndroid Build Coastguard Worker [[maybe_unused]] int TestImmediateCrashTreatedAsNoReturn() {
30*6777b538SAndroid Build Coastguard Worker ImmediateCrash();
31*6777b538SAndroid Build Coastguard Worker }
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_X86_FAMILY)
34*6777b538SAndroid Build Coastguard Worker // This is tricksy and false, since x86 instructions are not all one byte long,
35*6777b538SAndroid Build Coastguard Worker // but there is no better alternative short of implementing an x86 instruction
36*6777b538SAndroid Build Coastguard Worker // decoder.
37*6777b538SAndroid Build Coastguard Worker using Instruction = uint8_t;
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Worker // 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
40*6777b538SAndroid Build Coastguard Worker // Look for RET opcode (0xc3). Note that 0xC3 is a substring of several
41*6777b538SAndroid Build Coastguard Worker // other opcodes (VMRESUME, MOVNTI), and can also be encoded as part of an
42*6777b538SAndroid Build Coastguard Worker // argument to another opcode. None of these other cases are expected to be
43*6777b538SAndroid Build Coastguard Worker // present, so a simple byte scan should be Good Enough™.
44*6777b538SAndroid Build Coastguard Worker constexpr Instruction kRet = 0xc3;
45*6777b538SAndroid Build Coastguard Worker // INT3 ; UD2
46*6777b538SAndroid Build Coastguard Worker constexpr Instruction kRequiredBody[] = {0xcc, 0x0f, 0x0b};
47*6777b538SAndroid Build Coastguard Worker constexpr Instruction kOptionalFooter[] = {};
48*6777b538SAndroid Build Coastguard Worker
49*6777b538SAndroid Build Coastguard Worker #elif defined(ARCH_CPU_ARMEL)
50*6777b538SAndroid Build Coastguard Worker using Instruction = uint16_t;
51*6777b538SAndroid Build Coastguard Worker
52*6777b538SAndroid Build Coastguard Worker // T32 opcode reference: https://developer.arm.com/docs/ddi0487/latest
53*6777b538SAndroid Build Coastguard Worker // Actually BX LR, canonical encoding:
54*6777b538SAndroid Build Coastguard Worker constexpr Instruction kRet = 0x4770;
55*6777b538SAndroid Build Coastguard Worker // BKPT #0; UDF #0
56*6777b538SAndroid Build Coastguard Worker constexpr Instruction kRequiredBody[] = {0xbe00, 0xde00};
57*6777b538SAndroid Build Coastguard Worker constexpr Instruction kOptionalFooter[] = {};
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker #elif defined(ARCH_CPU_ARM64)
60*6777b538SAndroid Build Coastguard Worker using Instruction = uint32_t;
61*6777b538SAndroid Build Coastguard Worker
62*6777b538SAndroid Build Coastguard Worker // A64 opcode reference: https://developer.arm.com/docs/ddi0487/latest
63*6777b538SAndroid Build Coastguard Worker // Use an enum here rather than separate constexpr vars because otherwise some
64*6777b538SAndroid Build Coastguard Worker // of the vars will end up unused on each platform, upsetting
65*6777b538SAndroid Build Coastguard Worker // -Wunused-const-variable.
66*6777b538SAndroid Build Coastguard Worker enum : Instruction {
67*6777b538SAndroid Build Coastguard Worker // There are multiple valid encodings of return (which is really a special
68*6777b538SAndroid Build Coastguard Worker // form of branch). This is the one clang seems to use:
69*6777b538SAndroid Build Coastguard Worker kRet = 0xd65f03c0,
70*6777b538SAndroid Build Coastguard Worker kBrk0 = 0xd4200000,
71*6777b538SAndroid Build Coastguard Worker kBrk1 = 0xd4200020,
72*6777b538SAndroid Build Coastguard Worker kBrkF000 = 0xd43e0000,
73*6777b538SAndroid Build Coastguard Worker kHlt0 = 0xd4400000,
74*6777b538SAndroid Build Coastguard Worker };
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker constexpr Instruction kRequiredBody[] = {kBrkF000, kBrk1};
79*6777b538SAndroid Build Coastguard Worker constexpr Instruction kOptionalFooter[] = {};
80*6777b538SAndroid Build Coastguard Worker
81*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_MAC)
82*6777b538SAndroid Build Coastguard Worker
83*6777b538SAndroid Build Coastguard Worker constexpr Instruction kRequiredBody[] = {kBrk0, kHlt0};
84*6777b538SAndroid Build Coastguard Worker // Some clangs emit a BRK #1 for __builtin_unreachable(), but some do not, so
85*6777b538SAndroid Build Coastguard Worker // it is allowed but not required to occur.
86*6777b538SAndroid Build Coastguard Worker constexpr Instruction kOptionalFooter[] = {kBrk1};
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker #else
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker constexpr Instruction kRequiredBody[] = {kBrk0, kHlt0};
91*6777b538SAndroid Build Coastguard Worker constexpr Instruction kOptionalFooter[] = {};
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker #endif
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker #endif
96*6777b538SAndroid Build Coastguard Worker
97*6777b538SAndroid Build Coastguard Worker // This function loads a shared library that defines two functions,
98*6777b538SAndroid Build Coastguard Worker // TestFunction1 and TestFunction2. It then returns the bytes of the body of
99*6777b538SAndroid Build Coastguard Worker // whichever of those functions happens to come first in the library.
GetTestFunctionInstructions(std::vector<Instruction> * body)100*6777b538SAndroid Build Coastguard Worker void GetTestFunctionInstructions(std::vector<Instruction>* body) {
101*6777b538SAndroid Build Coastguard Worker FilePath helper_library_path;
102*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
103*6777b538SAndroid Build Coastguard Worker // On Android M, DIR_EXE == /system/bin when running base_unittests.
104*6777b538SAndroid Build Coastguard Worker // On Fuchsia, NativeLibrary understands the native convention that libraries
105*6777b538SAndroid Build Coastguard Worker // are not colocated with the binary.
106*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(PathService::Get(DIR_EXE, &helper_library_path));
107*6777b538SAndroid Build Coastguard Worker #endif
108*6777b538SAndroid Build Coastguard Worker helper_library_path = helper_library_path.AppendASCII(
109*6777b538SAndroid Build Coastguard Worker GetNativeLibraryName("immediate_crash_test_helper"));
110*6777b538SAndroid Build Coastguard Worker ScopedNativeLibrary helper_library(helper_library_path);
111*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(helper_library.is_valid())
112*6777b538SAndroid Build Coastguard Worker << "shared library load failed: "
113*6777b538SAndroid Build Coastguard Worker << helper_library.GetError()->ToString();
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker void* a = helper_library.GetFunctionPointer("TestFunction1");
116*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(a);
117*6777b538SAndroid Build Coastguard Worker void* b = helper_library.GetFunctionPointer("TestFunction2");
118*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(b);
119*6777b538SAndroid Build Coastguard Worker
120*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_ARMEL)
121*6777b538SAndroid Build Coastguard Worker // Routines loaded from a shared library will have the LSB in the pointer set
122*6777b538SAndroid Build Coastguard Worker // if encoded as T32 instructions. The rest of this test assumes T32.
123*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(reinterpret_cast<uintptr_t>(a) & 0x1)
124*6777b538SAndroid Build Coastguard Worker << "Expected T32 opcodes but found A32 opcodes instead.";
125*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(reinterpret_cast<uintptr_t>(b) & 0x1)
126*6777b538SAndroid Build Coastguard Worker << "Expected T32 opcodes but found A32 opcodes instead.";
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker // Mask off the lowest bit.
129*6777b538SAndroid Build Coastguard Worker a = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(a) & ~uintptr_t{0x1});
130*6777b538SAndroid Build Coastguard Worker b = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(b) & ~uintptr_t{0x1});
131*6777b538SAndroid Build Coastguard Worker #endif
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker // There are two identical test functions starting at a and b, which may
134*6777b538SAndroid Build Coastguard Worker // occur in the library in either order. Grab whichever one comes first,
135*6777b538SAndroid Build Coastguard Worker // and use the address of the other to figure out where it ends.
136*6777b538SAndroid Build Coastguard Worker const Instruction* const start = static_cast<Instruction*>(std::min(a, b));
137*6777b538SAndroid Build Coastguard Worker const Instruction* const end = static_cast<Instruction*>(std::max(a, b));
138*6777b538SAndroid Build Coastguard Worker
139*6777b538SAndroid Build Coastguard Worker for (const Instruction& instruction : make_span(start, end))
140*6777b538SAndroid Build Coastguard Worker body->push_back(instruction);
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker
ExpectImmediateCrashInvocation(std::vector<Instruction> instructions)143*6777b538SAndroid Build Coastguard Worker std::optional<std::vector<Instruction>> ExpectImmediateCrashInvocation(
144*6777b538SAndroid Build Coastguard Worker std::vector<Instruction> instructions) {
145*6777b538SAndroid Build Coastguard Worker auto iter = instructions.begin();
146*6777b538SAndroid Build Coastguard Worker for (const auto inst : kRequiredBody) {
147*6777b538SAndroid Build Coastguard Worker if (iter == instructions.end())
148*6777b538SAndroid Build Coastguard Worker return std::nullopt;
149*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(inst, *iter);
150*6777b538SAndroid Build Coastguard Worker iter++;
151*6777b538SAndroid Build Coastguard Worker }
152*6777b538SAndroid Build Coastguard Worker return std::make_optional(std::vector<Instruction>(iter, instructions.end()));
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker
MaybeSkipOptionalFooter(std::vector<Instruction> instructions)155*6777b538SAndroid Build Coastguard Worker std::vector<Instruction> MaybeSkipOptionalFooter(
156*6777b538SAndroid Build Coastguard Worker std::vector<Instruction> instructions) {
157*6777b538SAndroid Build Coastguard Worker auto iter = instructions.begin();
158*6777b538SAndroid Build Coastguard Worker for (const auto inst : kOptionalFooter) {
159*6777b538SAndroid Build Coastguard Worker if (iter == instructions.end() || *iter != inst)
160*6777b538SAndroid Build Coastguard Worker break;
161*6777b538SAndroid Build Coastguard Worker iter++;
162*6777b538SAndroid Build Coastguard Worker }
163*6777b538SAndroid Build Coastguard Worker return std::vector<Instruction>(iter, instructions.end());
164*6777b538SAndroid Build Coastguard Worker }
165*6777b538SAndroid Build Coastguard Worker
166*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_CLANG_COVERAGE) || BUILDFLAG(CLANG_PROFILING)
MatchPrefix(const std::vector<Instruction> & haystack,const base::span<const Instruction> & needle)167*6777b538SAndroid Build Coastguard Worker bool MatchPrefix(const std::vector<Instruction>& haystack,
168*6777b538SAndroid Build Coastguard Worker const base::span<const Instruction>& needle) {
169*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < needle.size(); i++) {
170*6777b538SAndroid Build Coastguard Worker if (i >= haystack.size() || needle[i] != haystack[i])
171*6777b538SAndroid Build Coastguard Worker return false;
172*6777b538SAndroid Build Coastguard Worker }
173*6777b538SAndroid Build Coastguard Worker return true;
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker
DropUntilMatch(std::vector<Instruction> haystack,const base::span<const Instruction> & needle)176*6777b538SAndroid Build Coastguard Worker std::vector<Instruction> DropUntilMatch(
177*6777b538SAndroid Build Coastguard Worker std::vector<Instruction> haystack,
178*6777b538SAndroid Build Coastguard Worker const base::span<const Instruction>& needle) {
179*6777b538SAndroid Build Coastguard Worker while (!haystack.empty() && !MatchPrefix(haystack, needle))
180*6777b538SAndroid Build Coastguard Worker haystack.erase(haystack.begin());
181*6777b538SAndroid Build Coastguard Worker return haystack;
182*6777b538SAndroid Build Coastguard Worker }
183*6777b538SAndroid Build Coastguard Worker #endif // USE_CLANG_COVERAGE || BUILDFLAG(CLANG_PROFILING)
184*6777b538SAndroid Build Coastguard Worker
MaybeSkipCoverageHook(std::vector<Instruction> instructions)185*6777b538SAndroid Build Coastguard Worker std::vector<Instruction> MaybeSkipCoverageHook(
186*6777b538SAndroid Build Coastguard Worker std::vector<Instruction> instructions) {
187*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_CLANG_COVERAGE) || BUILDFLAG(CLANG_PROFILING)
188*6777b538SAndroid Build Coastguard Worker // Warning: it is not illegal for the entirety of the expected crash sequence
189*6777b538SAndroid Build Coastguard Worker // to appear as a subsequence of the coverage hook code. If that happens, this
190*6777b538SAndroid Build Coastguard Worker // code will falsely exit early, having not found the real expected crash
191*6777b538SAndroid Build Coastguard Worker // sequence, so this may not adequately ensure that the immediate crash
192*6777b538SAndroid Build Coastguard Worker // sequence is present. We do check when not under coverage, at least.
193*6777b538SAndroid Build Coastguard Worker return DropUntilMatch(instructions, base::make_span(kRequiredBody));
194*6777b538SAndroid Build Coastguard Worker #else
195*6777b538SAndroid Build Coastguard Worker return instructions;
196*6777b538SAndroid Build Coastguard Worker #endif // USE_CLANG_COVERAGE || BUILDFLAG(CLANG_PROFILING)
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker } // namespace
200*6777b538SAndroid Build Coastguard Worker
201*6777b538SAndroid Build Coastguard Worker // Attempts to verify the actual instructions emitted by ImmediateCrash().
202*6777b538SAndroid Build Coastguard Worker // While the test results are highly implementation-specific, this allows macro
203*6777b538SAndroid Build Coastguard Worker // changes (e.g. CLs like https://crrev.com/671123) to be verified using the
204*6777b538SAndroid Build Coastguard Worker // trybots/waterfall, without having to build and disassemble Chrome on
205*6777b538SAndroid Build Coastguard Worker // multiple platforms. This makes it easier to evaluate changes to
206*6777b538SAndroid Build Coastguard Worker // ImmediateCrash() against its requirements (e.g. size of emitted sequence,
207*6777b538SAndroid Build Coastguard Worker // whether or not multiple ImmediateCrash sequences can be folded together, et
208*6777b538SAndroid Build Coastguard Worker // cetera). Please see immediate_crash.h for more details about the
209*6777b538SAndroid Build Coastguard Worker // requirements.
210*6777b538SAndroid Build Coastguard Worker //
211*6777b538SAndroid Build Coastguard Worker // Note that C++ provides no way to get the size of a function. Instead, the
212*6777b538SAndroid Build Coastguard Worker // test relies on a shared library which defines only two functions and assumes
213*6777b538SAndroid Build Coastguard Worker // the two functions will be laid out contiguously as a heuristic for finding
214*6777b538SAndroid Build Coastguard Worker // the size of the function.
TEST(ImmediateCrashTest,ExpectedOpcodeSequence)215*6777b538SAndroid Build Coastguard Worker TEST(ImmediateCrashTest, ExpectedOpcodeSequence) {
216*6777b538SAndroid Build Coastguard Worker std::vector<Instruction> body;
217*6777b538SAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(GetTestFunctionInstructions(&body));
218*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(HexEncode(body.data(), body.size() * sizeof(Instruction)));
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker auto it = ranges::find(body, kRet);
221*6777b538SAndroid Build Coastguard Worker ASSERT_NE(body.end(), it) << "Failed to find return opcode";
222*6777b538SAndroid Build Coastguard Worker it++;
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker body = std::vector<Instruction>(it, body.end());
225*6777b538SAndroid Build Coastguard Worker std::optional<std::vector<Instruction>> result = MaybeSkipCoverageHook(body);
226*6777b538SAndroid Build Coastguard Worker result = ExpectImmediateCrashInvocation(result.value());
227*6777b538SAndroid Build Coastguard Worker result = MaybeSkipOptionalFooter(result.value());
228*6777b538SAndroid Build Coastguard Worker result = MaybeSkipCoverageHook(result.value());
229*6777b538SAndroid Build Coastguard Worker result = ExpectImmediateCrashInvocation(result.value());
230*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(result);
231*6777b538SAndroid Build Coastguard Worker }
232*6777b538SAndroid Build Coastguard Worker
233*6777b538SAndroid Build Coastguard Worker } // namespace base
234