xref: /llvm-project/compiler-rt/lib/interception/tests/interception_win_test.cpp (revision bbf377060adc8607e1187952388c7eeea7cf4933)
1 //===-- interception_win_test.cpp -----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10 // Tests for interception_win.h.
11 //
12 //===----------------------------------------------------------------------===//
13 #include "interception/interception.h"
14 
15 #include "gtest/gtest.h"
16 
17 // Too slow for debug build
18 // Disabling for ARM64 since testcases are x86/x64 assembly.
19 #if !SANITIZER_DEBUG
20 #if SANITIZER_WINDOWS
21 #    if !SANITIZER_WINDOWS_ARM64
22 
23 #      include <stdarg.h>
24 
25 #      define WIN32_LEAN_AND_MEAN
26 #      include <windows.h>
27 
28 namespace __interception {
29 namespace {
30 
31 enum FunctionPrefixKind {
32   FunctionPrefixNone,
33   FunctionPrefixPadding,
34   FunctionPrefixHotPatch,
35   FunctionPrefixDetour,
36 };
37 
38 typedef bool (*TestOverrideFunction)(uptr, uptr, uptr*);
39 typedef int (*IdentityFunction)(int);
40 
41 #if SANITIZER_WINDOWS64
42 
43 const u8 kIdentityCodeWithPrologue[] = {
44     0x55,                   // push        rbp
45     0x48, 0x89, 0xE5,       // mov         rbp,rsp
46     0x8B, 0xC1,             // mov         eax,ecx
47     0x5D,                   // pop         rbp
48     0xC3,                   // ret
49 };
50 
51 const u8 kIdentityCodeWithPushPop[] = {
52     0x55,                   // push        rbp
53     0x48, 0x89, 0xE5,       // mov         rbp,rsp
54     0x53,                   // push        rbx
55     0x50,                   // push        rax
56     0x58,                   // pop         rax
57     0x8B, 0xC1,             // mov         rax,rcx
58     0x5B,                   // pop         rbx
59     0x5D,                   // pop         rbp
60     0xC3,                   // ret
61 };
62 
63 const u8 kIdentityTwiceOffset = 16;
64 const u8 kIdentityTwice[] = {
65     0x55,                   // push        rbp
66     0x48, 0x89, 0xE5,       // mov         rbp,rsp
67     0x8B, 0xC1,             // mov         eax,ecx
68     0x5D,                   // pop         rbp
69     0xC3,                   // ret
70     0x90, 0x90, 0x90, 0x90,
71     0x90, 0x90, 0x90, 0x90,
72     0x55,                   // push        rbp
73     0x48, 0x89, 0xE5,       // mov         rbp,rsp
74     0x8B, 0xC1,             // mov         eax,ecx
75     0x5D,                   // pop         rbp
76     0xC3,                   // ret
77 };
78 
79 const u8 kIdentityCodeWithMov[] = {
80     0x89, 0xC8,             // mov         eax, ecx
81     0xC3,                   // ret
82 };
83 
84 const u8 kIdentityCodeWithJump[] = {
85     0xE9, 0x04, 0x00, 0x00,
86     0x00,                   // jmp + 4
87     0xCC, 0xCC, 0xCC, 0xCC,
88     0x89, 0xC8,             // mov         eax, ecx
89     0xC3,                   // ret
90 };
91 
92 const u8 kIdentityCodeWithJumpBackwards[] = {
93     0x89, 0xC8,  // mov         eax, ecx
94     0xC3,        // ret
95     0xE9, 0xF8, 0xFF, 0xFF,
96     0xFF,  // jmp - 8
97     0xCC, 0xCC, 0xCC, 0xCC,
98 };
99 const u8 kIdentityCodeWithJumpBackwardsOffset = 3;
100 
101 #    else
102 
103 const u8 kIdentityCodeWithPrologue[] = {
104     0x55,                   // push        ebp
105     0x8B, 0xEC,             // mov         ebp,esp
106     0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]
107     0x5D,                   // pop         ebp
108     0xC3,                   // ret
109 };
110 
111 const u8 kIdentityCodeWithPushPop[] = {
112     0x55,                   // push        ebp
113     0x8B, 0xEC,             // mov         ebp,esp
114     0x53,                   // push        ebx
115     0x50,                   // push        eax
116     0x58,                   // pop         eax
117     0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]
118     0x5B,                   // pop         ebx
119     0x5D,                   // pop         ebp
120     0xC3,                   // ret
121 };
122 
123 const u8 kIdentityTwiceOffset = 8;
124 const u8 kIdentityTwice[] = {
125     0x55,                   // push        ebp
126     0x8B, 0xEC,             // mov         ebp,esp
127     0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]
128     0x5D,                   // pop         ebp
129     0xC3,                   // ret
130     0x55,                   // push        ebp
131     0x8B, 0xEC,             // mov         ebp,esp
132     0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]
133     0x5D,                   // pop         ebp
134     0xC3,                   // ret
135 };
136 
137 const u8 kIdentityCodeWithMov[] = {
138     0x8B, 0x44, 0x24, 0x04, // mov         eax,dword ptr [esp + 4]
139     0xC3,                   // ret
140 };
141 
142 const u8 kIdentityCodeWithJump[] = {
143     0xE9, 0x04, 0x00, 0x00,
144     0x00,                   // jmp + 4
145     0xCC, 0xCC, 0xCC, 0xCC,
146     0x8B, 0x44, 0x24, 0x04, // mov         eax,dword ptr [esp + 4]
147     0xC3,                   // ret
148 };
149 
150 const u8 kIdentityCodeWithJumpBackwards[] = {
151     0x8B, 0x44, 0x24, 0x04,  // mov         eax,dword ptr [esp + 4]
152     0xC3,                    // ret
153     0xE9, 0xF6, 0xFF, 0xFF,
154     0xFF,  // jmp - 10
155     0xCC, 0xCC, 0xCC, 0xCC,
156 };
157 const u8 kIdentityCodeWithJumpBackwardsOffset = 5;
158 
159 #    endif
160 
161 const u8 kPatchableCode1[] = {
162     0xB8, 0x4B, 0x00, 0x00, 0x00,   // mov eax,4B
163     0x33, 0xC9,                     // xor ecx,ecx
164     0xC3,                           // ret
165 };
166 
167 const u8 kPatchableCode2[] = {
168     0x55,                           // push ebp
169     0x8B, 0xEC,                     // mov ebp,esp
170     0x33, 0xC0,                     // xor eax,eax
171     0x5D,                           // pop ebp
172     0xC3,                           // ret
173 };
174 
175 const u8 kPatchableCode3[] = {
176     0x55,                           // push ebp
177     0x8B, 0xEC,                     // mov ebp,esp
178     0x6A, 0x00,                     // push 0
179     0xE8, 0x3D, 0xFF, 0xFF, 0xFF,   // call <func>
180 };
181 
182 const u8 kPatchableCode4[] = {
183     0xE9, 0xCC, 0xCC, 0xCC, 0xCC,   // jmp <label>
184     0x90, 0x90, 0x90, 0x90,
185 };
186 
187 const u8 kPatchableCode5[] = {
188     0x55,                                      // push    ebp
189     0x8b, 0xec,                                // mov     ebp,esp
190     0x8d, 0xa4, 0x24, 0x30, 0xfd, 0xff, 0xff,  // lea     esp,[esp-2D0h]
191     0x54,                                      // push    esp
192 };
193 
194 #if SANITIZER_WINDOWS64
195 u8 kLoadGlobalCode[] = {
196   0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov    eax [rip + global]
197   0xC3,                               // ret
198 };
199 #endif
200 
201 const u8 kUnpatchableCode1[] = {
202     0xC3,                           // ret
203 };
204 
205 const u8 kUnpatchableCode2[] = {
206     0x33, 0xC9,                     // xor ecx,ecx
207     0xC3,                           // ret
208 };
209 
210 const u8 kUnpatchableCode3[] = {
211     0x75, 0xCC,                     // jne <label>
212     0x33, 0xC9,                     // xor ecx,ecx
213     0xC3,                           // ret
214 };
215 
216 const u8 kUnpatchableCode4[] = {
217     0x74, 0xCC,                     // jne <label>
218     0x33, 0xC9,                     // xor ecx,ecx
219     0xC3,                           // ret
220 };
221 
222 const u8 kUnpatchableCode5[] = {
223     0xEB, 0x02,                     // jmp <label>
224     0x33, 0xC9,                     // xor ecx,ecx
225     0xC3,                           // ret
226 };
227 
228 const u8 kUnpatchableCode6[] = {
229     0xE8, 0xCC, 0xCC, 0xCC, 0xCC,   // call <func>
230     0x90, 0x90, 0x90, 0x90,
231 };
232 
233 #      if SANITIZER_WINDOWS64
234 const u8 kUnpatchableCode7[] = {
235     0x33, 0xc0,                     // xor     eax,eax
236     0x48, 0x85, 0xd2,               // test    rdx,rdx
237     0x74, 0x10,                     // je      +16  (unpatchable)
238 };
239 
240 const u8 kUnpatchableCode8[] = {
241     0x48, 0x8b, 0xc1,               // mov     rax,rcx
242     0x0f, 0xb7, 0x10,               // movzx   edx,word ptr [rax]
243     0x48, 0x83, 0xc0, 0x02,         // add     rax,2
244     0x66, 0x85, 0xd2,               // test    dx,dx
245     0x75, 0xf4,                     // jne     -12  (unpatchable)
246 };
247 
248 const u8 kUnpatchableCode9[] = {
249     0x4c, 0x8b, 0xc1,               // mov     r8,rcx
250     0x8a, 0x01,                     // mov     al,byte ptr [rcx]
251     0x48, 0xff, 0xc1,               // inc     rcx
252     0x84, 0xc0,                     // test    al,al
253     0x75, 0xf7,                     // jne     -9  (unpatchable)
254 };
255 
256 const u8 kPatchableCode6[] = {
257     0x48, 0x89, 0x54, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], rdx
258     0x33, 0xC9,                   // xor ecx,ecx
259     0xC3,                         // ret
260 };
261 
262 const u8 kPatchableCode7[] = {
263     0x4c, 0x89, 0x4c, 0x24, 0xBB,  // mov QWORD PTR [rsp + 0xBB], r9
264     0x33, 0xC9,                   // xor ecx,ecx
265     0xC3,                         // ret
266 };
267 
268 const u8 kPatchableCode8[] = {
269     0x4c, 0x89, 0x44, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r8
270     0x33, 0xC9,                   // xor ecx,ecx
271     0xC3,                         // ret
272 };
273 
274 const u8 kPatchableCode9[] = {
275     0x8a, 0x01,                     // al,byte ptr [rcx]
276     0x45, 0x33, 0xc0,               // xor     r8d,r8d
277     0x84, 0xc0,                     // test    al,al
278 };
279 
280 const u8 kPatchableCode10[] = {
281     0x45, 0x33, 0xc0,               // xor     r8d,r8d
282     0x41, 0x8b, 0xc0,               // mov     eax,r8d
283     0x48, 0x85, 0xd2,               // test    rdx,rdx
284 };
285 
286 const u8 kPatchableCode11[] = {
287     0x48, 0x83, 0xec, 0x38,         // sub     rsp,38h
288     0x83, 0x64, 0x24, 0x28, 0x00,   // and     dword ptr [rsp+28h],0
289 };
290 #      endif
291 
292 #      if !SANITIZER_WINDOWS64
293 const u8 kPatchableCode12[] = {
294     0x55,                           // push    ebp
295     0x53,                           // push    ebx
296     0x57,                           // push    edi
297     0x56,                           // push    esi
298     0x8b, 0x6c, 0x24, 0x18,         // mov     ebp,dword ptr[esp+18h]
299 };
300 
301 const u8 kPatchableCode13[] = {
302     0x55,                           // push    ebp
303     0x53,                           // push    ebx
304     0x57,                           // push    edi
305     0x56,                           // push    esi
306     0x8b, 0x5c, 0x24, 0x14,         // mov     ebx,dword ptr[esp+14h]
307 };
308 #      endif
309 
310 const u8 kPatchableCode14[] = {
311     0x55,                           // push    ebp
312     0x89, 0xe5,                     // mov     ebp,esp
313     0x53,                           // push    ebx
314     0x57,                           // push    edi
315     0x56,                           // push    esi
316 };
317 
318 const u8 kUnsupportedCode1[] = {
319     0x0f, 0x0b,                     // ud2
320     0x0f, 0x0b,                     // ud2
321     0x0f, 0x0b,                     // ud2
322     0x0f, 0x0b,                     // ud2
323 };
324 
325 // A buffer holding the dynamically generated code under test.
326 u8* ActiveCode;
327 const size_t ActiveCodeLength = 4096;
328 
329 int InterceptorFunction(int x);
330 
331 /// Allocate code memory more than 2GB away from Base.
332 u8 *AllocateCode2GBAway(u8 *Base) {
333   // Find a 64K aligned location after Base plus 2GB.
334   size_t TwoGB = 0x80000000;
335   size_t AllocGranularity = 0x10000;
336   Base = (u8 *)((((uptr)Base + TwoGB + AllocGranularity)) & ~(AllocGranularity - 1));
337 
338   // Check if that location is free, and if not, loop over regions until we find
339   // one that is.
340   MEMORY_BASIC_INFORMATION mbi = {};
341   while (sizeof(mbi) == VirtualQuery(Base, &mbi, sizeof(mbi))) {
342     if (mbi.State & MEM_FREE) break;
343     Base += mbi.RegionSize;
344   }
345 
346   // Allocate one RWX page at the free location.
347   return (u8 *)::VirtualAlloc(Base, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE,
348                               PAGE_EXECUTE_READWRITE);
349 }
350 
351 template<class T>
352 static void LoadActiveCode(
353     const T &code,
354     uptr *entry_point,
355     FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
356   if (ActiveCode == nullptr) {
357     ActiveCode = AllocateCode2GBAway((u8*)&InterceptorFunction);
358     ASSERT_NE(ActiveCode, nullptr) << "failed to allocate RWX memory 2GB away";
359   }
360 
361   size_t position = 0;
362 
363   // Add padding to avoid memory violation when scanning the prefix.
364   for (int i = 0; i < 16; ++i)
365     ActiveCode[position++] = 0xC3;  // Instruction 'ret'.
366 
367   // Add function padding.
368   size_t padding = 0;
369   if (prefix_kind == FunctionPrefixPadding)
370     padding = 16;
371   else if (prefix_kind == FunctionPrefixDetour ||
372            prefix_kind == FunctionPrefixHotPatch)
373     padding = FIRST_32_SECOND_64(5, 6);
374   // Insert |padding| instructions 'nop'.
375   for (size_t i = 0; i < padding; ++i)
376     ActiveCode[position++] = 0x90;
377 
378   // Keep track of the entry point.
379   *entry_point = (uptr)&ActiveCode[position];
380 
381   // Add the detour instruction (i.e. mov edi, edi)
382   if (prefix_kind == FunctionPrefixDetour) {
383 #if SANITIZER_WINDOWS64
384     // Note that "mov edi,edi" is NOP in 32-bit only, in 64-bit it clears
385     // higher bits of RDI.
386     // Use 66,90H as NOP for Windows64.
387     ActiveCode[position++] = 0x66;
388     ActiveCode[position++] = 0x90;
389 #else
390     // mov edi,edi.
391     ActiveCode[position++] = 0x8B;
392     ActiveCode[position++] = 0xFF;
393 #endif
394 
395   }
396 
397   // Copy the function body.
398   for (size_t i = 0; i < sizeof(T); ++i)
399     ActiveCode[position++] = code[i];
400 }
401 
402 int InterceptorFunctionCalled;
403 IdentityFunction InterceptedRealFunction;
404 
405 int InterceptorFunction(int x) {
406   ++InterceptorFunctionCalled;
407   return InterceptedRealFunction(x);
408 }
409 
410 }  // namespace
411 
412 // Tests for interception_win.h
413 TEST(Interception, InternalGetProcAddress) {
414   HMODULE ntdll_handle = ::GetModuleHandle("ntdll");
415   ASSERT_NE(nullptr, ntdll_handle);
416   uptr DbgPrint_expected = (uptr)::GetProcAddress(ntdll_handle, "DbgPrint");
417   uptr isdigit_expected = (uptr)::GetProcAddress(ntdll_handle, "isdigit");
418   uptr DbgPrint_adddress = InternalGetProcAddress(ntdll_handle, "DbgPrint");
419   uptr isdigit_address = InternalGetProcAddress(ntdll_handle, "isdigit");
420 
421   EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress);
422   EXPECT_EQ(isdigit_expected, isdigit_address);
423   EXPECT_NE(DbgPrint_adddress, isdigit_address);
424 }
425 
426 template <class T>
427 static void TestIdentityFunctionPatching(
428     const T &code, TestOverrideFunction override,
429     FunctionPrefixKind prefix_kind = FunctionPrefixNone,
430     int function_start_offset = 0) {
431   uptr identity_address;
432   LoadActiveCode(code, &identity_address, prefix_kind);
433   identity_address += function_start_offset;
434   IdentityFunction identity = (IdentityFunction)identity_address;
435 
436   // Validate behavior before dynamic patching.
437   InterceptorFunctionCalled = 0;
438   EXPECT_EQ(0, identity(0));
439   EXPECT_EQ(42, identity(42));
440   EXPECT_EQ(0, InterceptorFunctionCalled);
441 
442   // Patch the function.
443   uptr real_identity_address = 0;
444   bool success = override(identity_address,
445                          (uptr)&InterceptorFunction,
446                          &real_identity_address);
447   EXPECT_TRUE(success);
448   EXPECT_NE(0U, real_identity_address);
449   IdentityFunction real_identity = (IdentityFunction)real_identity_address;
450   InterceptedRealFunction = real_identity;
451 
452   // Don't run tests if hooking failed or the real function is not valid.
453   if (!success || !real_identity_address)
454     return;
455 
456   // Calling the redirected function.
457   InterceptorFunctionCalled = 0;
458   EXPECT_EQ(0, identity(0));
459   EXPECT_EQ(42, identity(42));
460   EXPECT_EQ(2, InterceptorFunctionCalled);
461 
462   // Calling the real function.
463   InterceptorFunctionCalled = 0;
464   EXPECT_EQ(0, real_identity(0));
465   EXPECT_EQ(42, real_identity(42));
466   EXPECT_EQ(0, InterceptorFunctionCalled);
467 
468   TestOnlyReleaseTrampolineRegions();
469 }
470 
471 #    if !SANITIZER_WINDOWS64
472 TEST(Interception, OverrideFunctionWithDetour) {
473   TestOverrideFunction override = OverrideFunctionWithDetour;
474   FunctionPrefixKind prefix = FunctionPrefixDetour;
475   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
476   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
477   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
478   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
479 }
480 #endif  // !SANITIZER_WINDOWS64
481 
482 TEST(Interception, OverrideFunctionWithRedirectJump) {
483   TestOverrideFunction override = OverrideFunctionWithRedirectJump;
484   TestIdentityFunctionPatching(kIdentityCodeWithJump, override);
485   TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards, override,
486                                FunctionPrefixNone,
487                                kIdentityCodeWithJumpBackwardsOffset);
488 }
489 
490 TEST(Interception, OverrideFunctionWithHotPatch) {
491   TestOverrideFunction override = OverrideFunctionWithHotPatch;
492   FunctionPrefixKind prefix = FunctionPrefixHotPatch;
493   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
494 }
495 
496 TEST(Interception, OverrideFunctionWithTrampoline) {
497   TestOverrideFunction override = OverrideFunctionWithTrampoline;
498   FunctionPrefixKind prefix = FunctionPrefixNone;
499   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
500   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
501 
502   prefix = FunctionPrefixPadding;
503   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
504   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
505 }
506 
507 TEST(Interception, OverrideFunction) {
508   TestOverrideFunction override = OverrideFunction;
509   FunctionPrefixKind prefix = FunctionPrefixNone;
510   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
511   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
512   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
513 
514   prefix = FunctionPrefixPadding;
515   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
516   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
517   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
518   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
519 
520   prefix = FunctionPrefixHotPatch;
521   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
522   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
523   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
524   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
525 
526   prefix = FunctionPrefixDetour;
527   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
528   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
529   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
530   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
531 }
532 
533 template<class T>
534 static void TestIdentityFunctionMultiplePatching(
535     const T &code,
536     TestOverrideFunction override,
537     FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
538   uptr identity_address;
539   LoadActiveCode(code, &identity_address, prefix_kind);
540 
541   // Patch the function.
542   uptr real_identity_address = 0;
543   bool success = override(identity_address,
544                           (uptr)&InterceptorFunction,
545                           &real_identity_address);
546   EXPECT_TRUE(success);
547   EXPECT_NE(0U, real_identity_address);
548 
549   // Re-patching the function should not work.
550   success = override(identity_address,
551                      (uptr)&InterceptorFunction,
552                      &real_identity_address);
553   EXPECT_FALSE(success);
554 
555   TestOnlyReleaseTrampolineRegions();
556 }
557 
558 TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) {
559 #if !SANITIZER_WINDOWS64
560   TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue,
561                                        OverrideFunctionWithDetour,
562                                        FunctionPrefixDetour);
563 #endif
564 
565   TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov,
566                                        OverrideFunctionWithHotPatch,
567                                        FunctionPrefixHotPatch);
568 
569   TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop,
570                                        OverrideFunctionWithTrampoline,
571                                        FunctionPrefixPadding);
572 }
573 
574 TEST(Interception, OverrideFunctionTwice) {
575   uptr identity_address1;
576   LoadActiveCode(kIdentityTwice, &identity_address1);
577   uptr identity_address2 = identity_address1 + kIdentityTwiceOffset;
578   IdentityFunction identity1 = (IdentityFunction)identity_address1;
579   IdentityFunction identity2 = (IdentityFunction)identity_address2;
580 
581   // Patch the two functions.
582   uptr real_identity_address = 0;
583   EXPECT_TRUE(OverrideFunction(identity_address1,
584                                (uptr)&InterceptorFunction,
585                                &real_identity_address));
586   EXPECT_TRUE(OverrideFunction(identity_address2,
587                                (uptr)&InterceptorFunction,
588                                &real_identity_address));
589   IdentityFunction real_identity = (IdentityFunction)real_identity_address;
590   InterceptedRealFunction = real_identity;
591 
592   // Calling the redirected function.
593   InterceptorFunctionCalled = 0;
594   EXPECT_EQ(42, identity1(42));
595   EXPECT_EQ(42, identity2(42));
596   EXPECT_EQ(2, InterceptorFunctionCalled);
597 
598   TestOnlyReleaseTrampolineRegions();
599 }
600 
601 template<class T>
602 static bool TestFunctionPatching(
603     const T &code,
604     TestOverrideFunction override,
605     FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
606   uptr address;
607   LoadActiveCode(code, &address, prefix_kind);
608   uptr unused_real_address = 0;
609   bool result = override(
610       address, (uptr)&InterceptorFunction, &unused_real_address);
611 
612   TestOnlyReleaseTrampolineRegions();
613   return result;
614 }
615 
616 TEST(Interception, PatchableFunction) {
617   TestOverrideFunction override = OverrideFunction;
618   // Test without function padding.
619   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override));
620   EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override));
621 #if SANITIZER_WINDOWS64
622   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
623 #else
624   EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override));
625 #endif
626   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
627   EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override));
628 #if SANITIZER_WINDOWS64
629   EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override));
630 #endif
631 
632   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
633   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
634   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
635   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
636   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
637   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
638 }
639 
640 #if !SANITIZER_WINDOWS64
641 TEST(Interception, PatchableFunctionWithDetour) {
642   TestOverrideFunction override = OverrideFunctionWithDetour;
643   // Without the prefix, no function can be detoured.
644   EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
645   EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
646   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
647   EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override));
648   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
649   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
650   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
651   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
652   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
653   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
654 
655   // With the prefix, all functions can be detoured.
656   FunctionPrefixKind prefix = FunctionPrefixDetour;
657   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
658   EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
659   EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
660   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
661   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
662   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
663   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
664   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
665   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
666   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
667 }
668 #endif  // !SANITIZER_WINDOWS64
669 
670 TEST(Interception, PatchableFunctionWithRedirectJump) {
671   TestOverrideFunction override = OverrideFunctionWithRedirectJump;
672   EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
673   EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
674   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
675   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
676   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
677   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
678   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
679   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
680   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
681   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
682 }
683 
684 TEST(Interception, PatchableFunctionWithHotPatch) {
685   TestOverrideFunction override = OverrideFunctionWithHotPatch;
686   FunctionPrefixKind prefix = FunctionPrefixHotPatch;
687 
688   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
689   EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override, prefix));
690   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
691   EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
692 #if SANITIZER_WINDOWS64
693   EXPECT_TRUE(TestFunctionPatching(kPatchableCode6, override, prefix));
694   EXPECT_TRUE(TestFunctionPatching(kPatchableCode7, override, prefix));
695   EXPECT_TRUE(TestFunctionPatching(kPatchableCode8, override, prefix));
696 #endif
697   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
698   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
699   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
700   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
701   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
702   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
703 }
704 
705 TEST(Interception, PatchableFunctionWithTrampoline) {
706   TestOverrideFunction override = OverrideFunctionWithTrampoline;
707   FunctionPrefixKind prefix = FunctionPrefixPadding;
708 
709   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
710   EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
711 #if SANITIZER_WINDOWS64
712   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
713   EXPECT_TRUE(TestFunctionPatching(kPatchableCode9, override, prefix));
714   EXPECT_TRUE(TestFunctionPatching(kPatchableCode10, override, prefix));
715   EXPECT_TRUE(TestFunctionPatching(kPatchableCode11, override, prefix));
716   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode7, override, prefix));
717   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode8, override, prefix));
718   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode9, override, prefix));
719 #else
720   EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
721   EXPECT_TRUE(TestFunctionPatching(kPatchableCode12, override, prefix));
722   EXPECT_TRUE(TestFunctionPatching(kPatchableCode13, override, prefix));
723 #endif
724   EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
725   EXPECT_TRUE(TestFunctionPatching(kPatchableCode14, override, prefix));
726 
727   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
728   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
729   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
730   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
731   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
732   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
733 }
734 
735 TEST(Interception, UnsupportedInstructionWithTrampoline) {
736   TestOverrideFunction override = OverrideFunctionWithTrampoline;
737   FunctionPrefixKind prefix = FunctionPrefixPadding;
738 
739   static bool reportCalled;
740   reportCalled = false;
741 
742   struct Local {
743     static void Report(const char *format, ...) {
744       if (reportCalled)
745         FAIL() << "Report called more times than expected";
746       reportCalled = true;
747       ASSERT_STREQ(
748           "interception_win: unhandled instruction at %p: %02x %02x %02x %02x "
749           "%02x %02x %02x %02x\n",
750           format);
751       va_list args;
752       va_start(args, format);
753       u8 *ptr = va_arg(args, u8 *);
754       for (int i = 0; i < 8; i++) EXPECT_EQ(kUnsupportedCode1[i], ptr[i]);
755       int bytes[8];
756       for (int i = 0; i < 8; i++) {
757         bytes[i] = va_arg(args, int);
758         EXPECT_EQ(kUnsupportedCode1[i], bytes[i]);
759       }
760       va_end(args);
761     }
762   };
763 
764   SetErrorReportCallback(Local::Report);
765   EXPECT_FALSE(TestFunctionPatching(kUnsupportedCode1, override, prefix));
766   SetErrorReportCallback(nullptr);
767 
768   if (!reportCalled)
769     ADD_FAILURE() << "Report not called";
770 }
771 
772 TEST(Interception, PatchableFunctionPadding) {
773   TestOverrideFunction override = OverrideFunction;
774   FunctionPrefixKind prefix = FunctionPrefixPadding;
775 
776   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
777   EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
778 #if SANITIZER_WINDOWS64
779   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
780 #else
781   EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
782 #endif
783   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
784 
785   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
786   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
787   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
788   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
789   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
790   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
791 }
792 
793 TEST(Interception, EmptyExportTable) {
794   // We try to get a pointer to a function from an executable that doesn't
795   // export any symbol (empty export table).
796   uptr FunPtr = InternalGetProcAddress((void *)GetModuleHandleA(0), "example");
797   EXPECT_EQ(0U, FunPtr);
798 }
799 
800 const struct InstructionSizeData {
801   size_t size;  // hold instruction size or 0 for failure,
802                 // e.g. on control instructions
803   u8 instr[16];
804   size_t rel_offset;  // adjustment for RIP-relative addresses when copying
805                       // instructions during hooking via hotpatch or trampoline.
806   const char *comment;
807 } data[] = {
808     // clang-format off
809     // sorted list
810     { 0, {0x70, 0x71}, 0, "70 XX : jo XX (short conditional jump)"},
811     { 0, {0x71, 0x71}, 0, "71 XX : jno XX (short conditional jump)"},
812     { 0, {0x72, 0x71}, 0, "72 XX : jb XX (short conditional jump)"},
813     { 0, {0x73, 0x71}, 0, "73 XX : jae XX (short conditional jump)"},
814     { 0, {0x74, 0x71}, 0, "74 XX : je XX (short conditional jump)"},
815     { 0, {0x75, 0x71}, 0, "75 XX : jne XX (short conditional jump)"},
816     { 0, {0x76, 0x71}, 0, "76 XX : jbe XX (short conditional jump)"},
817     { 0, {0x77, 0x71}, 0, "77 XX : ja XX (short conditional jump)"},
818     { 0, {0x78, 0x71}, 0, "78 XX : js XX (short conditional jump)"},
819     { 0, {0x79, 0x71}, 0, "79 XX : jns XX (short conditional jump)"},
820     { 0, {0x7A, 0x71}, 0, "7A XX : jp XX (short conditional jump)"},
821     { 0, {0x7B, 0x71}, 0, "7B XX : jnp XX (short conditional jump)"},
822     { 0, {0x7C, 0x71}, 0, "7C XX : jl XX (short conditional jump)"},
823     { 0, {0x7D, 0x71}, 0, "7D XX : jge XX (short conditional jump)"},
824     { 0, {0x7E, 0x71}, 0, "7E XX : jle XX (short conditional jump)"},
825     { 0, {0x7F, 0x71}, 0, "7F XX : jg XX (short conditional jump)"},
826     { 0, {0xE8, 0x71, 0x72, 0x73, 0x74}, 0, "E8 XX XX XX XX : call <func>"},
827     { 0, {0xE9, 0x71, 0x72, 0x73, 0x74}, 0, "E9 XX XX XX XX : jmp <label>"},
828     { 0, {0xEB, 0x71}, 0, "EB XX : jmp XX (short jump)"},
829     { 0, {0xFF, 0x25, 0x72, 0x73, 0x74, 0x75}, 0, "FF 25 XX YY ZZ WW : jmp dword ptr ds:[WWZZYYXX]"},
830     { 1, {0x50}, 0, "50 : push eax / rax"},
831     { 1, {0x51}, 0, "51 : push ecx / rcx"},
832     { 1, {0x52}, 0, "52 : push edx / rdx"},
833     { 1, {0x53}, 0, "53 : push ebx / rbx"},
834     { 1, {0x54}, 0, "54 : push esp / rsp"},
835     { 1, {0x55}, 0, "55 : push ebp / rbp"},
836     { 1, {0x56}, 0, "56 : push esi / rsi"},
837     { 1, {0x57}, 0, "57 : push edi / rdi"},
838     { 1, {0x5D}, 0, "5D : pop ebp / rbp"},
839     { 1, {0x90}, 0, "90 : nop"},
840     { 1, {0xC3}, 0, "C3 : ret   (for small/empty function interception"},
841     { 1, {0xCC}, 0, "CC : int 3  i.e. registering weak functions)"},
842     { 2, {0x31, 0xC0}, 0, "31 C0 : xor eax, eax"},
843     { 2, {0x31, 0xC9}, 0, "31 C9 : xor ecx, ecx"},
844     { 2, {0x31, 0xD2}, 0, "31 D2 : xor edx, edx"},
845     { 2, {0x33, 0xC0}, 0, "33 C0 : xor eax, eax"},
846     { 2, {0x33, 0xC9}, 0, "33 C9 : xor ecx, ecx"},
847     { 2, {0x33, 0xD2}, 0, "33 D2 : xor edx, edx"},
848     { 2, {0x6A, 0x71}, 0, "6A XX : push XX"},
849     { 2, {0x84, 0xC0}, 0, "84 C0 : test al,al"},
850     { 2, {0x84, 0xC9}, 0, "84 C9 : test cl,cl"},
851     { 2, {0x84, 0xD2}, 0, "84 D2 : test dl,dl"},
852     { 2, {0x84, 0xDB}, 0, "84 DB : test bl,bl"},
853     { 2, {0x89, 0xc8}, 0, "89 C8 : mov eax, ecx"},
854     { 2, {0x89, 0xD1}, 0, "89 D1 : mov ecx, edx"},
855     { 2, {0x89, 0xE5}, 0, "89 E5 : mov ebp, esp"},
856     { 2, {0x8A, 0x01}, 0, "8A 01 : mov al, byte ptr [ecx]"},
857     { 2, {0x8B, 0xC1}, 0, "8B C1 : mov eax, ecx"},
858     { 2, {0x8B, 0xEC}, 0, "8B EC : mov ebp, esp"},
859     { 2, {0x8B, 0xFF}, 0, "8B FF : mov edi, edi"},
860     { 3, {0x80, 0x39, 0x72}, 0, "80 39 XX : cmp BYTE PTR [rcx], XX"},
861     { 3, {0x83, 0xE4, 0x72}, 0, "83 E4 XX : and esp, XX"},
862     { 3, {0x83, 0xEC, 0x72}, 0, "83 EC XX : sub esp, XX"},
863     { 3, {0x8B, 0x4D, 0x72}, 0, "8B 4D XX : mov XX(%ebp), ecx"},
864     { 3, {0x8B, 0x55, 0x72}, 0, "8B 55 XX : mov XX(%ebp), edx"},
865     { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov XX(%ebp), esp"},
866     { 3, {0xc2, 0x71, 0x72}, 0, "C2 XX XX : ret XX (needed for registering weak functions)"},
867     { 4, {0x8D, 0x4C, 0x24, 0x73}, 0, "8D 4C 24 XX : lea ecx, [esp + XX]"},
868     { 4, {0xFF, 0x74, 0x24, 0x73}, 0, "FF 74 24 XX : push qword ptr [rsp + XX]"},
869     { 5, {0x68, 0x71, 0x72, 0x73, 0x74}, 0, "68 XX XX XX XX : push imm32"},
870     { 5, {0xb8, 0x71, 0x72, 0x73, 0x74}, 0, "b8 XX XX XX XX : mov eax, XX XX XX XX"},
871     { 5, {0xB9, 0x71, 0x72, 0x73, 0x74}, 0, "b9 XX XX XX XX : mov ecx, XX XX XX XX"},
872     { 5, {0xBA, 0x71, 0x72, 0x73, 0x74}, 0, "ba XX XX XX XX : mov edx, XX XX XX XX"},
873     { 6, {0x81, 0xEC, 0x72, 0x73, 0x74, 0x75}, 0, "81 EC XX XX XX XX : sub esp, XX XX XX XX"},
874     { 6, {0xFF, 0x89, 0x72, 0x73, 0x74, 0x75}, 0, "FF 89 XX XX XX XX : dec dword ptr [ecx + XX XX XX XX]"},
875     { 7, {0x8D, 0xA4, 0x24, 0x73, 0x74, 0x75, 0x76}, 0, "8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX]"},
876 #if SANITIZER_WINDOWS_x64
877     // sorted list
878     { 2, {0x40, 0x50}, 0, "40 50 : push rax"},
879     { 2, {0x40, 0x51}, 0, "40 51 : push rcx"},
880     { 2, {0x40, 0x52}, 0, "40 52 : push rdx"},
881     { 2, {0x40, 0x53}, 0, "40 53 : push rbx"},
882     { 2, {0x40, 0x54}, 0, "40 54 : push rsp"},
883     { 2, {0x40, 0x55}, 0, "40 55 : push rbp"},
884     { 2, {0x40, 0x56}, 0, "40 56 : push rsi"},
885     { 2, {0x40, 0x57}, 0, "40 57 : push rdi"},
886     { 2, {0x41, 0x54}, 0, "41 54 : push r12"},
887     { 2, {0x41, 0x55}, 0, "41 55 : push r13"},
888     { 2, {0x41, 0x56}, 0, "41 56 : push r14"},
889     { 2, {0x41, 0x57}, 0, "41 57 : push r15"},
890     { 2, {0x66, 0x90}, 0, "66 90 : Two-byte NOP"},
891     { 2, {0x84, 0xc0}, 0, "84 c0 : test al, al"},
892     { 2, {0x8a, 0x01}, 0, "8a 01 : mov al, byte ptr [rcx]"},
893     { 3, {0x0f, 0xb6, 0x01}, 0, "0f b6 01 : movzx eax, BYTE PTR [rcx]"},
894     { 3, {0x0f, 0xb6, 0x09}, 0, "0f b6 09 : movzx ecx, BYTE PTR [rcx]"},
895     { 3, {0x0f, 0xb6, 0x11}, 0, "0f b6 11 : movzx edx, BYTE PTR [rcx]"},
896     { 3, {0x0f, 0xb6, 0xc2}, 0, "0f b6 c2 : movzx eax, dl"},
897     { 3, {0x0f, 0xb6, 0xd2}, 0, "0f b6 d2 : movzx edx, dl"},
898     { 3, {0x0f, 0xb7, 0x10}, 0, "0f b7 10 : movzx edx, WORD PTR [rax]"},
899     { 3, {0x0f, 0xbe, 0xd2}, 0, "0f be d2 : movsx edx, dl"},
900     { 3, {0x41, 0x8b, 0xc0}, 0, "41 8b c0 : mov eax, r8d"},
901     { 3, {0x41, 0x8b, 0xc1}, 0, "41 8b c1 : mov eax, r9d"},
902     { 3, {0x41, 0x8b, 0xc2}, 0, "41 8b c2 : mov eax, r10d"},
903     { 3, {0x41, 0x8b, 0xc3}, 0, "41 8b c3 : mov eax, r11d"},
904     { 3, {0x41, 0x8b, 0xc4}, 0, "41 8b c4 : mov eax, r12d"},
905     { 3, {0x45, 0x31, 0xc0}, 0, "45 31 c0 : xor r8d,r8d"},
906     { 3, {0x45, 0x31, 0xc9}, 0, "45 31 c9 : xor r9d,r9d"},
907     { 3, {0x45, 0x33, 0xc0}, 0, "45 33 c0 : xor r8d, r8d"},
908     { 3, {0x45, 0x33, 0xc9}, 0, "45 33 c9 : xor r9d, r9d"},
909     { 3, {0x45, 0x33, 0xdb}, 0, "45 33 db : xor r11d, r11d"},
910     { 3, {0x45, 0x84, 0xc0}, 0, "45 84 c0 : test r8b,r8b"},
911     { 3, {0x45, 0x84, 0xd2}, 0, "45 84 d2 : test r10b,r10b"},
912     { 3, {0x48, 0x29, 0xd1}, 0, "48 29 d1 : sub rcx, rdx"},
913     { 3, {0x48, 0x2b, 0xca}, 0, "48 2b ca : sub rcx, rdx"},
914     { 3, {0x48, 0x2b, 0xd1}, 0, "48 2b d1 : sub rdx, rcx"},
915     { 3, {0x48, 0x3b, 0xca}, 0, "48 3b ca : cmp rcx, rdx"},
916     { 3, {0x48, 0x85, 0xc0}, 0, "48 85 c0 : test rax, rax"},
917     { 3, {0x48, 0x85, 0xc9}, 0, "48 85 c9 : test rcx, rcx"},
918     { 3, {0x48, 0x85, 0xd2}, 0, "48 85 d2 : test rdx, rdx"},
919     { 3, {0x48, 0x85, 0xdb}, 0, "48 85 db : test rbx, rbx"},
920     { 3, {0x48, 0x85, 0xe4}, 0, "48 85 e4 : test rsp, rsp"},
921     { 3, {0x48, 0x85, 0xed}, 0, "48 85 ed : test rbp, rbp"},
922     { 3, {0x48, 0x89, 0xc8}, 0, "48 89 c8 : mov rax,rcx"},
923     { 3, {0x48, 0x89, 0xcb}, 0, "48 89 cb : mov rbx,rcx"},
924     { 3, {0x48, 0x89, 0xd0}, 0, "48 89 d0 : mov rax,rdx"},
925     { 3, {0x48, 0x89, 0xd1}, 0, "48 89 d1 : mov rcx,rdx"},
926     { 3, {0x48, 0x89, 0xd3}, 0, "48 89 d3 : mov rbx,rdx"},
927     { 3, {0x48, 0x89, 0xe5}, 0, "48 89 e5 : mov rbp, rsp"},
928     { 3, {0x48, 0x8b, 0xc1}, 0, "48 8b c1 : mov rax, rcx"},
929     { 3, {0x48, 0x8b, 0xc4}, 0, "48 8b c4 : mov rax, rsp"},
930     { 3, {0x48, 0x8b, 0xd1}, 0, "48 8b d1 : mov rdx, rcx"},
931     { 3, {0x48, 0xf7, 0xd9}, 0, "48 f7 d9 : neg rcx"},
932     { 3, {0x48, 0xff, 0xc0}, 0, "48 ff c0 : inc rax"},
933     { 3, {0x48, 0xff, 0xc1}, 0, "48 ff c1 : inc rcx"},
934     { 3, {0x48, 0xff, 0xc2}, 0, "48 ff c2 : inc rdx"},
935     { 3, {0x48, 0xff, 0xc3}, 0, "48 ff c3 : inc rbx"},
936     { 3, {0x48, 0xff, 0xc6}, 0, "48 ff c6 : inc rsi"},
937     { 3, {0x48, 0xff, 0xc7}, 0, "48 ff c7 : inc rdi"},
938     { 3, {0x49, 0x89, 0xc8}, 0, "49 89 c8 : mov r8, rcx"},
939     { 3, {0x49, 0x89, 0xc9}, 0, "49 89 c9 : mov r9, rcx"},
940     { 3, {0x49, 0x89, 0xca}, 0, "49 89 ca : mov r10,rcx"},
941     { 3, {0x49, 0x89, 0xd0}, 0, "49 89 d0 : mov r8, rdx"},
942     { 3, {0x49, 0x89, 0xd1}, 0, "49 89 d1 : mov r9, rdx"},
943     { 3, {0x49, 0x89, 0xd2}, 0, "49 89 d2 : mov r10, rdx"},
944     { 3, {0x49, 0x89, 0xd3}, 0, "49 89 d3 : mov r11, rdx"},
945     { 3, {0x49, 0xff, 0xc0}, 0, "49 ff c0 : inc r8"},
946     { 3, {0x49, 0xff, 0xc1}, 0, "49 ff c1 : inc r9"},
947     { 3, {0x49, 0xff, 0xc2}, 0, "49 ff c2 : inc r10"},
948     { 3, {0x49, 0xff, 0xc3}, 0, "49 ff c3 : inc r11"},
949     { 3, {0x49, 0xff, 0xc4}, 0, "49 ff c4 : inc r12"},
950     { 3, {0x49, 0xff, 0xc5}, 0, "49 ff c5 : inc r13"},
951     { 3, {0x49, 0xff, 0xc6}, 0, "49 ff c6 : inc r14"},
952     { 3, {0x49, 0xff, 0xc7}, 0, "49 ff c7 : inc r15"},
953     { 3, {0x4c, 0x8b, 0xc1}, 0, "4c 8b c1 : mov r8, rcx"},
954     { 3, {0x4c, 0x8b, 0xc9}, 0, "4c 8b c9 : mov r9, rcx"},
955     { 3, {0x4c, 0x8b, 0xd1}, 0, "4c 8b d1 : mov r10, rcx"},
956     { 3, {0x4c, 0x8b, 0xd2}, 0, "4c 8b d2 : mov r10, rdx"},
957     { 3, {0x4c, 0x8b, 0xd9}, 0, "4c 8b d9 : mov r11, rcx"},
958     { 3, {0x4c, 0x8b, 0xdc}, 0, "4c 8b dc : mov r11, rsp"},
959     { 3, {0x4d, 0x0b, 0xc0}, 0, "4d 0b c0 : or r8, r8"},
960     { 3, {0x4d, 0x85, 0xc0}, 0, "4d 85 c0 : test r8, r8"},
961     { 3, {0x4d, 0x85, 0xc9}, 0, "4d 85 c9 : test r9, r9"},
962     { 3, {0x4d, 0x85, 0xd2}, 0, "4d 85 d2 : test r10, r10"},
963     { 3, {0x4d, 0x85, 0xdb}, 0, "4d 85 db : test r11, r11"},
964     { 3, {0x4d, 0x85, 0xe4}, 0, "4d 85 e4 : test r12, r12"},
965     { 3, {0x4d, 0x85, 0xed}, 0, "4d 85 ed : test r13, r13"},
966     { 3, {0x4d, 0x85, 0xf6}, 0, "4d 85 f6 : test r14, r14"},
967     { 3, {0x4d, 0x85, 0xff}, 0, "4d 85 ff : test r15, r15"},
968     { 3, {0xf6, 0xc1, 0x72}, 0, "f6 c1 XX : test cl, XX"},
969     { 4, {0x44, 0x0f, 0xb6, 0x01}, 0, "44 0f b6 01 : movzx r8d, BYTE PTR [rcx]"},
970     { 4, {0x44, 0x0f, 0xb6, 0x09}, 0, "44 0f b6 09 : movzx r9d, BYTE PTR [rcx]"},
971     { 4, {0x44, 0x0f, 0xb6, 0x0a}, 0, "44 0f b6 0a : movzx r8d, BYTE PTR [rdx]"},
972     { 4, {0x44, 0x0f, 0xb6, 0x11}, 0, "44 0f b6 11 : movzx r10d, BYTE PTR [rcx]"},
973     { 4, {0x44, 0x0f, 0xb6, 0x1a}, 0, "44 0f b6 1a : movzx r11d, BYTE PTR [rdx]"},
974     { 4, {0x44, 0x8d, 0x42, 0x73}, 0, "44 8d 42 XX : lea r8d , [rdx + XX]"},
975     { 4, {0x48, 0x83, 0xec, 0x73}, 0, "48 83 ec XX : sub rsp, XX"},
976     { 4, {0x48, 0x89, 0x58, 0x73}, 0, "48 89 58 XX : mov QWORD PTR[rax + XX], rbx"},
977     { 4, {0x49, 0x83, 0xf8, 0x73}, 0, "49 83 f8 XX : cmp r8, XX"},
978     { 4, {0x49, 0x8d, 0x48, 0x73}, 0, "49 8d 48 XX : lea rcx, [...]"},
979     { 4, {0x4c, 0x8d, 0x04, 0x73}, 0, "4c 8d 04 XX : lea r8, [...]"},
980     { 4, {0x4e, 0x8d, 0x14, 0x73}, 0, "4e 8d 14 XX : lea r10, [...]"},
981     { 4, {0x66, 0x83, 0x39, 0x73}, 0, "66 83 39 XX : cmp WORD PTR [rcx], XX"},
982     { 4, {0x80, 0x78, 0x72, 0x73}, 0, "80 78 YY XX : cmp BYTE PTR [rax+YY], XX"},
983     { 4, {0x80, 0x79, 0x72, 0x73}, 0, "80 79 YY XX : cmp BYTE ptr [rcx+YY], XX"},
984     { 4, {0x80, 0x7A, 0x72, 0x73}, 0, "80 7A YY XX : cmp BYTE PTR [rdx+YY], XX"},
985     { 4, {0x80, 0x7B, 0x72, 0x73}, 0, "80 7B YY XX : cmp BYTE PTR [rbx+YY], XX"},
986     { 4, {0x80, 0x7D, 0x72, 0x73}, 0, "80 7D YY XX : cmp BYTE PTR [rbp+YY], XX"},
987     { 4, {0x80, 0x7E, 0x72, 0x73}, 0, "80 7E YY XX : cmp BYTE PTR [rsi+YY], XX"},
988     { 4, {0x89, 0x54, 0x24, 0x73}, 0, "89 54 24 XX : mov DWORD PTR[rsp + XX], edx"},
989     { 5, {0x0F, 0x1F, 0x44, 0x73, 0x74}, 0, "0F 1F 44 XX XX : nop DWORD PTR [...]"},
990     { 5, {0x44, 0x89, 0x44, 0x24, 0x74}, 0, "44 89 44 24 XX : mov DWORD PTR [rsp + XX], r8d"},
991     { 5, {0x44, 0x89, 0x4c, 0x24, 0x74}, 0, "44 89 4c 24 XX : mov DWORD PTR [rsp + XX], r9d"},
992     { 5, {0x48, 0x89, 0x4C, 0x24, 0x74}, 0, "48 89 4C 24 XX : mov QWORD PTR [rsp + XX], rcx"},
993     { 5, {0x48, 0x89, 0x54, 0x24, 0x74}, 0, "48 89 54 24 XX : mov QWORD PTR [rsp + XX], rdx"},
994     { 5, {0x48, 0x89, 0x5c, 0x24, 0x74}, 0, "48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx"},
995     { 5, {0x48, 0x89, 0x6c, 0x24, 0x74}, 0, "48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp"},
996     { 5, {0x48, 0x89, 0x74, 0x24, 0x74}, 0, "48 89 74 24 XX : mov QWORD PTR [rsp + XX], rsi"},
997     { 5, {0x48, 0x89, 0x7c, 0x24, 0x74}, 0, "48 89 7c 24 XX : mov QWORD PTR [rsp + XX], rdi"},
998     { 5, {0x48, 0x8b, 0x44, 0x24, 0x74}, 0, "48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX]"},
999     { 5, {0x48, 0x8d, 0x6c, 0x24, 0x74}, 0, "48 8d 6c 24 XX : lea rbp, [rsp + XX]"},
1000     { 5, {0x4c, 0x89, 0x44, 0x24, 0x74}, 0, "4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8"},
1001     { 5, {0x4c, 0x89, 0x4c, 0x24, 0x74}, 0, "4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9"},
1002     { 5, {0x66, 0x48, 0x0F, 0x7E, 0xC0}, 0, "66 48 0F 7E C0 : movq rax, xmm0"},
1003     { 5, {0x83, 0x44, 0x72, 0x73, 0x74}, 0, "83 44 72 XX YY : add DWORD PTR [rdx+rsi*2+XX],YY"},
1004     { 5, {0x83, 0x64, 0x24, 0x73, 0x74}, 0, "83 64 24 XX YY : and DWORD PTR [rsp+XX], YY"},
1005     { 6, {0x41, 0xB8, 0x72, 0x73, 0x74, 0x75}, 0, "41 B8 XX XX XX XX : mov r8d, XX XX XX XX"},
1006     { 6, {0x48, 0x83, 0x64, 0x24, 0x74, 0x75}, 0, "48 83 64 24 XX YY : and QWORD PTR [rsp + XX], YY"},
1007     { 6, {0x66, 0x81, 0x78, 0x73, 0x74, 0x75}, 0, "66 81 78 XX YY YY : cmp WORD PTR [rax+XX], YY YY"},
1008     { 6, {0x66, 0x81, 0x79, 0x73, 0x74, 0x75}, 0, "66 81 79 XX YY YY : cmp WORD PTR [rcx+XX], YY YY"},
1009     { 6, {0x66, 0x81, 0x7a, 0x73, 0x74, 0x75}, 0, "66 81 7a XX YY YY : cmp WORD PTR [rdx+XX], YY YY"},
1010     { 6, {0x66, 0x81, 0x7b, 0x73, 0x74, 0x75}, 0, "66 81 7b XX YY YY : cmp WORD PTR [rbx+XX], YY YY"},
1011     { 6, {0x66, 0x81, 0x7e, 0x73, 0x74, 0x75}, 0, "66 81 7e XX YY YY : cmp WORD PTR [rsi+XX], YY YY"},
1012     { 6, {0x66, 0x81, 0x7f, 0x73, 0x74, 0x75}, 0, "66 81 7f XX YY YY : cmp WORD PTR [rdi+XX], YY YY"},
1013     { 6, {0x8A, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8A 05 XX XX XX XX : mov al, byte ptr [XX XX XX XX]"},
1014     { 6, {0x8B, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]"},
1015     { 6, {0xF2, 0x0f, 0x11, 0x44, 0x24, 0x75}, 0, "f2 0f 11 44 24 XX : movsd QWORD PTR [rsp + XX], xmm0"},
1016     { 6, {0xF2, 0x0f, 0x11, 0x4c, 0x24, 0x75}, 0, "f2 0f 11 4c 24 XX : movsd QWORD PTR [rsp + XX], xmm1"},
1017     { 6, {0xF2, 0x0f, 0x11, 0x54, 0x24, 0x75}, 0, "f2 0f 11 54 24 XX : movsd QWORD PTR [rsp + XX], xmm2"},
1018     { 6, {0xF2, 0x0f, 0x11, 0x5c, 0x24, 0x75}, 0, "f2 0f 11 5c 24 XX : movsd QWORD PTR [rsp + XX], xmm3"},
1019     { 6, {0xF2, 0x0f, 0x11, 0x64, 0x24, 0x75}, 0, "f2 0f 11 64 24 XX : movsd QWORD PTR [rsp + XX], xmm4"},
1020     { 7, {0x48, 0x81, 0xec, 0x73, 0x74, 0x75, 0x76}, 0, "48 81 EC XX XX XX XX : sub rsp, XXXXXXXX"},
1021     { 7, {0x48, 0x89, 0x0d, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 0d XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rcx"},
1022     { 7, {0x48, 0x89, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 15 XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rdx"},
1023     { 7, {0x48, 0x8b, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8b 05 XX XX XX XX : mov rax, QWORD PTR [rip + XXXXXXXX]"},
1024     { 7, {0x48, 0x8d, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8d 05 XX XX XX XX : lea rax, QWORD PTR [rip + XXXXXXXX]"},
1025     { 7, {0x48, 0xc7, 0xc0, 0x73, 0x74, 0x75, 0x76}, 0, "48 C7 C0 XX XX XX XX : mov rax, XX XX XX XX"},
1026     { 7, {0x48, 0xff, 0x25, 0x73, 0x74, 0x75, 0x76}, 3, "48 ff 25 XX XX XX XX : rex.W jmp QWORD PTR [rip + XXXXXXXX]"},
1027     { 7, {0x4C, 0x8D, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "4c 8d 15 XX XX XX XX : lea r10, [rip + XX]"},
1028     { 7, {0x81, 0x78, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 78 YY XX XX XX XX : cmp DWORD PTR [rax+YY], XX XX XX XX"},
1029     { 7, {0x81, 0x79, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 79 YY XX XX XX XX : cmp dword ptr [rcx+YY], XX XX XX XX"},
1030     { 7, {0x81, 0x7A, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 7A YY XX XX XX XX : cmp DWORD PTR [rdx+YY], XX XX XX XX"},
1031     { 7, {0x81, 0x7B, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 7B YY XX XX XX XX : cmp DWORD PTR [rbx+YY], XX XX XX XX"},
1032     { 7, {0x81, 0x7D, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 7D YY XX XX XX XX : cmp DWORD PTR [rbp+YY], XX XX XX XX"},
1033     { 7, {0x81, 0x7E, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 7E YY XX XX XX XX : cmp DWORD PTR [rsi+YY], XX XX XX XX"},
1034     { 8, {0x41, 0x81, 0x78, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 78 XX YY YY YY YY : cmp DWORD PTR [r8+YY], XX XX XX XX"},
1035     { 8, {0x41, 0x81, 0x79, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 79 XX YY YY YY YY : cmp DWORD PTR [r9+YY], XX XX XX XX"},
1036     { 8, {0x41, 0x81, 0x7a, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7a XX YY YY YY YY : cmp DWORD PTR [r10+YY], XX XX XX XX"},
1037     { 8, {0x41, 0x81, 0x7b, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7b XX YY YY YY YY : cmp DWORD PTR [r11+YY], XX XX XX XX"},
1038     { 8, {0x41, 0x81, 0x7d, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7d XX YY YY YY YY : cmp DWORD PTR [r13+YY], XX XX XX XX"},
1039     { 8, {0x41, 0x81, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7e XX YY YY YY YY : cmp DWORD PTR [r14+YY], XX XX XX XX"},
1040     { 8, {0x41, 0x81, 0x7f, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7f YY XX XX XX XX : cmp DWORD PTR [r15+YY], XX XX XX XX"},
1041     { 8, {0x48, 0x8D, 0xA4, 0x24, 0x74, 0x75, 0x76, 0x77}, 0, "48 8D A4 24 XX XX XX XX : lea rsp, [rsp + XX XX XX XX]"},
1042     { 8, {0x81, 0x7c, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "81 7c 24 YY XX XX XX XX : cmp DWORD PTR [rsp+YY], XX XX XX XX"},
1043     { 8, {0xc7, 0x44, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "C7 44 24 XX YY YY YY YY : mov dword ptr [rsp + XX], YYYYYYYY"},
1044     { 9, {0x41, 0x81, 0x7c, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78}, 0, "41 81 7c ZZ YY XX XX XX XX : cmp DWORD PTR [reg+reg*n+YY], XX XX XX XX"},
1045     { 9, {0xA1, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78}, 0, "A1 XX XX XX XX XX XX XX XX : movabs eax, dword ptr ds:[XXXXXXXX]"},
1046 #else
1047     // sorted list
1048     { 3, {0x8B, 0x45, 0x72}, 0, "8B 45 XX : mov eax, dword ptr [ebp + XX]"},
1049     { 3, {0x8B, 0x5D, 0x72}, 0, "8B 5D XX : mov ebx, dword ptr [ebp + XX]"},
1050     { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov esi, dword ptr [ebp + XX]"},
1051     { 3, {0x8B, 0x7D, 0x72}, 0, "8B 7D XX : mov edi, dword ptr [ebp + XX]"},
1052     { 3, {0xFF, 0x75, 0x72}, 0, "FF 75 XX : push dword ptr [ebp + XX]"},
1053     { 4, {0x83, 0x7D, 0x72, 0x73}, 0, "83 7D XX YY : cmp dword ptr [ebp + XX], YY"},
1054     { 4, {0x8A, 0x44, 0x24, 0x73}, 0, "8A 44 24 XX : mov eal, dword ptr [esp + XX]"},
1055     { 4, {0x8B, 0x44, 0x24, 0x73}, 0, "8B 44 24 XX : mov eax, dword ptr [esp + XX]"},
1056     { 4, {0x8B, 0x4C, 0x24, 0x73}, 0, "8B 4C 24 XX : mov ecx, dword ptr [esp + XX]"},
1057     { 4, {0x8B, 0x54, 0x24, 0x73}, 0, "8B 54 24 XX : mov edx, dword ptr [esp + XX]"},
1058     { 4, {0x8B, 0x5C, 0x24, 0x73}, 0, "8B 5C 24 XX : mov ebx, dword ptr [esp + XX]"},
1059     { 4, {0x8B, 0x6C, 0x24, 0x73}, 0, "8B 6C 24 XX : mov ebp, dword ptr [esp + XX]"},
1060     { 4, {0x8B, 0x74, 0x24, 0x73}, 0, "8B 74 24 XX : mov esi, dword ptr [esp + XX]"},
1061     { 4, {0x8B, 0x7C, 0x24, 0x73}, 0, "8B 7C 24 XX : mov edi, dword ptr [esp + XX]"},
1062     { 5, {0x0F, 0xB6, 0x44, 0x24, 0x74}, 0, "0F B6 44 24 XX : movzx eax, byte ptr [esp + XX]"},
1063     { 5, {0xA1, 0x71, 0x72, 0x73, 0x74}, 0, "A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX]"},
1064     { 6, {0xF7, 0xC1, 0x72, 0x73, 0x74, 0x75}, 0, "F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX"},
1065     { 7, {0x83, 0x3D, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "83 3D XX YY ZZ WW TT : cmp TT, WWZZYYXX"},
1066 #endif
1067     // clang-format on
1068 };
1069 
1070 std::string dumpInstruction(unsigned arrayIndex,
1071                             const InstructionSizeData &data) {
1072   std::stringstream ret;
1073   ret << "  with arrayIndex=" << arrayIndex << " {";
1074   for (size_t i = 0; i < data.size; i++) {
1075     if (i > 0)
1076       ret << ", ";
1077     ret << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex
1078         << (int)data.instr[i];
1079   }
1080   ret << "} " << data.comment;
1081   return ret.str();
1082 }
1083 
1084 TEST(Interception, GetInstructionSize) {
1085   for (unsigned i = 0; i < sizeof(data) / sizeof(*data); i++) {
1086     size_t rel_offset = ~0L;
1087     size_t size = __interception::TestOnlyGetInstructionSize(
1088         (uptr)data[i].instr, &rel_offset);
1089     EXPECT_EQ(data[i].size, size) << dumpInstruction(i, data[i]);
1090     EXPECT_EQ(data[i].rel_offset, rel_offset) << dumpInstruction(i, data[i]);
1091   }
1092 }
1093 
1094 }  // namespace __interception
1095 
1096 #    endif  // !SANITIZER_WINDOWS_ARM64
1097 #endif  // SANITIZER_WINDOWS
1098 #endif  // #if !SANITIZER_DEBUG
1099