xref: /llvm-project/compiler-rt/lib/interception/tests/interception_win_test.cpp (revision bbf377060adc8607e1187952388c7eeea7cf4933)
19642e337SNico Weber //===-- interception_win_test.cpp -----------------------------------------===//
29642e337SNico Weber //
39642e337SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49642e337SNico Weber // See https://llvm.org/LICENSE.txt for license information.
59642e337SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69642e337SNico Weber //
79642e337SNico Weber //===----------------------------------------------------------------------===//
89642e337SNico Weber //
99642e337SNico Weber // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
109642e337SNico Weber // Tests for interception_win.h.
119642e337SNico Weber //
129642e337SNico Weber //===----------------------------------------------------------------------===//
139642e337SNico Weber #include "interception/interception.h"
149642e337SNico Weber 
159642e337SNico Weber #include "gtest/gtest.h"
169642e337SNico Weber 
179642e337SNico Weber // Too slow for debug build
18d79aee9fSFarzon Lotfi // Disabling for ARM64 since testcases are x86/x64 assembly.
199642e337SNico Weber #if !SANITIZER_DEBUG
209642e337SNico Weber #if SANITIZER_WINDOWS
21d79aee9fSFarzon Lotfi #    if !SANITIZER_WINDOWS_ARM64
229642e337SNico Weber 
230716888dSAlvin Wong #      include <stdarg.h>
240716888dSAlvin Wong 
259642e337SNico Weber #      define WIN32_LEAN_AND_MEAN
269642e337SNico Weber #      include <windows.h>
279642e337SNico Weber 
289642e337SNico Weber namespace __interception {
299642e337SNico Weber namespace {
309642e337SNico Weber 
319642e337SNico Weber enum FunctionPrefixKind {
329642e337SNico Weber   FunctionPrefixNone,
339642e337SNico Weber   FunctionPrefixPadding,
349642e337SNico Weber   FunctionPrefixHotPatch,
359642e337SNico Weber   FunctionPrefixDetour,
369642e337SNico Weber };
379642e337SNico Weber 
389642e337SNico Weber typedef bool (*TestOverrideFunction)(uptr, uptr, uptr*);
399642e337SNico Weber typedef int (*IdentityFunction)(int);
409642e337SNico Weber 
419642e337SNico Weber #if SANITIZER_WINDOWS64
429642e337SNico Weber 
439642e337SNico Weber const u8 kIdentityCodeWithPrologue[] = {
449642e337SNico Weber     0x55,                   // push        rbp
459642e337SNico Weber     0x48, 0x89, 0xE5,       // mov         rbp,rsp
469642e337SNico Weber     0x8B, 0xC1,             // mov         eax,ecx
479642e337SNico Weber     0x5D,                   // pop         rbp
489642e337SNico Weber     0xC3,                   // ret
499642e337SNico Weber };
509642e337SNico Weber 
519642e337SNico Weber const u8 kIdentityCodeWithPushPop[] = {
529642e337SNico Weber     0x55,                   // push        rbp
539642e337SNico Weber     0x48, 0x89, 0xE5,       // mov         rbp,rsp
549642e337SNico Weber     0x53,                   // push        rbx
559642e337SNico Weber     0x50,                   // push        rax
569642e337SNico Weber     0x58,                   // pop         rax
579642e337SNico Weber     0x8B, 0xC1,             // mov         rax,rcx
589642e337SNico Weber     0x5B,                   // pop         rbx
599642e337SNico Weber     0x5D,                   // pop         rbp
609642e337SNico Weber     0xC3,                   // ret
619642e337SNico Weber };
629642e337SNico Weber 
639642e337SNico Weber const u8 kIdentityTwiceOffset = 16;
649642e337SNico Weber const u8 kIdentityTwice[] = {
659642e337SNico Weber     0x55,                   // push        rbp
669642e337SNico Weber     0x48, 0x89, 0xE5,       // mov         rbp,rsp
679642e337SNico Weber     0x8B, 0xC1,             // mov         eax,ecx
689642e337SNico Weber     0x5D,                   // pop         rbp
699642e337SNico Weber     0xC3,                   // ret
709642e337SNico Weber     0x90, 0x90, 0x90, 0x90,
719642e337SNico Weber     0x90, 0x90, 0x90, 0x90,
729642e337SNico Weber     0x55,                   // push        rbp
739642e337SNico Weber     0x48, 0x89, 0xE5,       // mov         rbp,rsp
749642e337SNico Weber     0x8B, 0xC1,             // mov         eax,ecx
759642e337SNico Weber     0x5D,                   // pop         rbp
769642e337SNico Weber     0xC3,                   // ret
779642e337SNico Weber };
789642e337SNico Weber 
799642e337SNico Weber const u8 kIdentityCodeWithMov[] = {
809642e337SNico Weber     0x89, 0xC8,             // mov         eax, ecx
819642e337SNico Weber     0xC3,                   // ret
829642e337SNico Weber };
839642e337SNico Weber 
849642e337SNico Weber const u8 kIdentityCodeWithJump[] = {
859642e337SNico Weber     0xE9, 0x04, 0x00, 0x00,
869642e337SNico Weber     0x00,                   // jmp + 4
879642e337SNico Weber     0xCC, 0xCC, 0xCC, 0xCC,
889642e337SNico Weber     0x89, 0xC8,             // mov         eax, ecx
899642e337SNico Weber     0xC3,                   // ret
909642e337SNico Weber };
919642e337SNico Weber 
9278c033b5SMarkus Böck const u8 kIdentityCodeWithJumpBackwards[] = {
9378c033b5SMarkus Böck     0x89, 0xC8,  // mov         eax, ecx
9478c033b5SMarkus Böck     0xC3,        // ret
9578c033b5SMarkus Böck     0xE9, 0xF8, 0xFF, 0xFF,
9678c033b5SMarkus Böck     0xFF,  // jmp - 8
9778c033b5SMarkus Böck     0xCC, 0xCC, 0xCC, 0xCC,
9878c033b5SMarkus Böck };
9978c033b5SMarkus Böck const u8 kIdentityCodeWithJumpBackwardsOffset = 3;
10078c033b5SMarkus Böck 
1019642e337SNico Weber #    else
1029642e337SNico Weber 
1039642e337SNico Weber const u8 kIdentityCodeWithPrologue[] = {
1049642e337SNico Weber     0x55,                   // push        ebp
1059642e337SNico Weber     0x8B, 0xEC,             // mov         ebp,esp
1069642e337SNico Weber     0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]
1079642e337SNico Weber     0x5D,                   // pop         ebp
1089642e337SNico Weber     0xC3,                   // ret
1099642e337SNico Weber };
1109642e337SNico Weber 
1119642e337SNico Weber const u8 kIdentityCodeWithPushPop[] = {
1129642e337SNico Weber     0x55,                   // push        ebp
1139642e337SNico Weber     0x8B, 0xEC,             // mov         ebp,esp
1149642e337SNico Weber     0x53,                   // push        ebx
1159642e337SNico Weber     0x50,                   // push        eax
1169642e337SNico Weber     0x58,                   // pop         eax
1179642e337SNico Weber     0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]
1189642e337SNico Weber     0x5B,                   // pop         ebx
1199642e337SNico Weber     0x5D,                   // pop         ebp
1209642e337SNico Weber     0xC3,                   // ret
1219642e337SNico Weber };
1229642e337SNico Weber 
1239642e337SNico Weber const u8 kIdentityTwiceOffset = 8;
1249642e337SNico Weber const u8 kIdentityTwice[] = {
1259642e337SNico Weber     0x55,                   // push        ebp
1269642e337SNico Weber     0x8B, 0xEC,             // mov         ebp,esp
1279642e337SNico Weber     0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]
1289642e337SNico Weber     0x5D,                   // pop         ebp
1299642e337SNico Weber     0xC3,                   // ret
1309642e337SNico Weber     0x55,                   // push        ebp
1319642e337SNico Weber     0x8B, 0xEC,             // mov         ebp,esp
1329642e337SNico Weber     0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]
1339642e337SNico Weber     0x5D,                   // pop         ebp
1349642e337SNico Weber     0xC3,                   // ret
1359642e337SNico Weber };
1369642e337SNico Weber 
1379642e337SNico Weber const u8 kIdentityCodeWithMov[] = {
1389642e337SNico Weber     0x8B, 0x44, 0x24, 0x04, // mov         eax,dword ptr [esp + 4]
1399642e337SNico Weber     0xC3,                   // ret
1409642e337SNico Weber };
1419642e337SNico Weber 
1429642e337SNico Weber const u8 kIdentityCodeWithJump[] = {
1439642e337SNico Weber     0xE9, 0x04, 0x00, 0x00,
1449642e337SNico Weber     0x00,                   // jmp + 4
1459642e337SNico Weber     0xCC, 0xCC, 0xCC, 0xCC,
1469642e337SNico Weber     0x8B, 0x44, 0x24, 0x04, // mov         eax,dword ptr [esp + 4]
1479642e337SNico Weber     0xC3,                   // ret
1489642e337SNico Weber };
1499642e337SNico Weber 
15078c033b5SMarkus Böck const u8 kIdentityCodeWithJumpBackwards[] = {
15178c033b5SMarkus Böck     0x8B, 0x44, 0x24, 0x04,  // mov         eax,dword ptr [esp + 4]
15278c033b5SMarkus Böck     0xC3,                    // ret
15378c033b5SMarkus Böck     0xE9, 0xF6, 0xFF, 0xFF,
15478c033b5SMarkus Böck     0xFF,  // jmp - 10
15578c033b5SMarkus Böck     0xCC, 0xCC, 0xCC, 0xCC,
15678c033b5SMarkus Böck };
15778c033b5SMarkus Böck const u8 kIdentityCodeWithJumpBackwardsOffset = 5;
15878c033b5SMarkus Böck 
1599642e337SNico Weber #    endif
1609642e337SNico Weber 
1619642e337SNico Weber const u8 kPatchableCode1[] = {
1629642e337SNico Weber     0xB8, 0x4B, 0x00, 0x00, 0x00,   // mov eax,4B
1639642e337SNico Weber     0x33, 0xC9,                     // xor ecx,ecx
1649642e337SNico Weber     0xC3,                           // ret
1659642e337SNico Weber };
1669642e337SNico Weber 
1679642e337SNico Weber const u8 kPatchableCode2[] = {
1689642e337SNico Weber     0x55,                           // push ebp
1699642e337SNico Weber     0x8B, 0xEC,                     // mov ebp,esp
1709642e337SNico Weber     0x33, 0xC0,                     // xor eax,eax
1719642e337SNico Weber     0x5D,                           // pop ebp
1729642e337SNico Weber     0xC3,                           // ret
1739642e337SNico Weber };
1749642e337SNico Weber 
1759642e337SNico Weber const u8 kPatchableCode3[] = {
1769642e337SNico Weber     0x55,                           // push ebp
1779642e337SNico Weber     0x8B, 0xEC,                     // mov ebp,esp
1789642e337SNico Weber     0x6A, 0x00,                     // push 0
1799642e337SNico Weber     0xE8, 0x3D, 0xFF, 0xFF, 0xFF,   // call <func>
1809642e337SNico Weber };
1819642e337SNico Weber 
1829642e337SNico Weber const u8 kPatchableCode4[] = {
1839642e337SNico Weber     0xE9, 0xCC, 0xCC, 0xCC, 0xCC,   // jmp <label>
1849642e337SNico Weber     0x90, 0x90, 0x90, 0x90,
1859642e337SNico Weber };
1869642e337SNico Weber 
1879642e337SNico Weber const u8 kPatchableCode5[] = {
1889642e337SNico Weber     0x55,                                      // push    ebp
1899642e337SNico Weber     0x8b, 0xec,                                // mov     ebp,esp
1909642e337SNico Weber     0x8d, 0xa4, 0x24, 0x30, 0xfd, 0xff, 0xff,  // lea     esp,[esp-2D0h]
1919642e337SNico Weber     0x54,                                      // push    esp
1929642e337SNico Weber };
1939642e337SNico Weber 
1949642e337SNico Weber #if SANITIZER_WINDOWS64
1959642e337SNico Weber u8 kLoadGlobalCode[] = {
1969642e337SNico Weber   0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov    eax [rip + global]
1979642e337SNico Weber   0xC3,                               // ret
1989642e337SNico Weber };
1999642e337SNico Weber #endif
2009642e337SNico Weber 
2019642e337SNico Weber const u8 kUnpatchableCode1[] = {
2029642e337SNico Weber     0xC3,                           // ret
2039642e337SNico Weber };
2049642e337SNico Weber 
2059642e337SNico Weber const u8 kUnpatchableCode2[] = {
2069642e337SNico Weber     0x33, 0xC9,                     // xor ecx,ecx
2079642e337SNico Weber     0xC3,                           // ret
2089642e337SNico Weber };
2099642e337SNico Weber 
2109642e337SNico Weber const u8 kUnpatchableCode3[] = {
2119642e337SNico Weber     0x75, 0xCC,                     // jne <label>
2129642e337SNico Weber     0x33, 0xC9,                     // xor ecx,ecx
2139642e337SNico Weber     0xC3,                           // ret
2149642e337SNico Weber };
2159642e337SNico Weber 
2169642e337SNico Weber const u8 kUnpatchableCode4[] = {
2179642e337SNico Weber     0x74, 0xCC,                     // jne <label>
2189642e337SNico Weber     0x33, 0xC9,                     // xor ecx,ecx
2199642e337SNico Weber     0xC3,                           // ret
2209642e337SNico Weber };
2219642e337SNico Weber 
2229642e337SNico Weber const u8 kUnpatchableCode5[] = {
2239642e337SNico Weber     0xEB, 0x02,                     // jmp <label>
2249642e337SNico Weber     0x33, 0xC9,                     // xor ecx,ecx
2259642e337SNico Weber     0xC3,                           // ret
2269642e337SNico Weber };
2279642e337SNico Weber 
2289642e337SNico Weber const u8 kUnpatchableCode6[] = {
2299642e337SNico Weber     0xE8, 0xCC, 0xCC, 0xCC, 0xCC,   // call <func>
2309642e337SNico Weber     0x90, 0x90, 0x90, 0x90,
2319642e337SNico Weber };
2329642e337SNico Weber 
233b89e7746Sbernhardu #      if SANITIZER_WINDOWS64
23422ea0ceaSToshihito Kikuchi const u8 kUnpatchableCode7[] = {
23522ea0ceaSToshihito Kikuchi     0x33, 0xc0,                     // xor     eax,eax
23622ea0ceaSToshihito Kikuchi     0x48, 0x85, 0xd2,               // test    rdx,rdx
23722ea0ceaSToshihito Kikuchi     0x74, 0x10,                     // je      +16  (unpatchable)
23822ea0ceaSToshihito Kikuchi };
23922ea0ceaSToshihito Kikuchi 
24022ea0ceaSToshihito Kikuchi const u8 kUnpatchableCode8[] = {
24122ea0ceaSToshihito Kikuchi     0x48, 0x8b, 0xc1,               // mov     rax,rcx
24222ea0ceaSToshihito Kikuchi     0x0f, 0xb7, 0x10,               // movzx   edx,word ptr [rax]
24322ea0ceaSToshihito Kikuchi     0x48, 0x83, 0xc0, 0x02,         // add     rax,2
24422ea0ceaSToshihito Kikuchi     0x66, 0x85, 0xd2,               // test    dx,dx
24522ea0ceaSToshihito Kikuchi     0x75, 0xf4,                     // jne     -12  (unpatchable)
24622ea0ceaSToshihito Kikuchi };
24722ea0ceaSToshihito Kikuchi 
24822ea0ceaSToshihito Kikuchi const u8 kUnpatchableCode9[] = {
24922ea0ceaSToshihito Kikuchi     0x4c, 0x8b, 0xc1,               // mov     r8,rcx
25022ea0ceaSToshihito Kikuchi     0x8a, 0x01,                     // mov     al,byte ptr [rcx]
25122ea0ceaSToshihito Kikuchi     0x48, 0xff, 0xc1,               // inc     rcx
25222ea0ceaSToshihito Kikuchi     0x84, 0xc0,                     // test    al,al
25322ea0ceaSToshihito Kikuchi     0x75, 0xf7,                     // jne     -9  (unpatchable)
25422ea0ceaSToshihito Kikuchi };
25522ea0ceaSToshihito Kikuchi 
2569642e337SNico Weber const u8 kPatchableCode6[] = {
2579642e337SNico Weber     0x48, 0x89, 0x54, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], rdx
2589642e337SNico Weber     0x33, 0xC9,                   // xor ecx,ecx
2599642e337SNico Weber     0xC3,                         // ret
2609642e337SNico Weber };
2619642e337SNico Weber 
2629642e337SNico Weber const u8 kPatchableCode7[] = {
2639642e337SNico Weber     0x4c, 0x89, 0x4c, 0x24, 0xBB,  // mov QWORD PTR [rsp + 0xBB], r9
2649642e337SNico Weber     0x33, 0xC9,                   // xor ecx,ecx
2659642e337SNico Weber     0xC3,                         // ret
2669642e337SNico Weber };
2679642e337SNico Weber 
2689642e337SNico Weber const u8 kPatchableCode8[] = {
2699642e337SNico Weber     0x4c, 0x89, 0x44, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r8
2709642e337SNico Weber     0x33, 0xC9,                   // xor ecx,ecx
2719642e337SNico Weber     0xC3,                         // ret
2729642e337SNico Weber };
2739642e337SNico Weber 
27422ea0ceaSToshihito Kikuchi const u8 kPatchableCode9[] = {
27522ea0ceaSToshihito Kikuchi     0x8a, 0x01,                     // al,byte ptr [rcx]
27622ea0ceaSToshihito Kikuchi     0x45, 0x33, 0xc0,               // xor     r8d,r8d
27722ea0ceaSToshihito Kikuchi     0x84, 0xc0,                     // test    al,al
27822ea0ceaSToshihito Kikuchi };
27922ea0ceaSToshihito Kikuchi 
28022ea0ceaSToshihito Kikuchi const u8 kPatchableCode10[] = {
28122ea0ceaSToshihito Kikuchi     0x45, 0x33, 0xc0,               // xor     r8d,r8d
28222ea0ceaSToshihito Kikuchi     0x41, 0x8b, 0xc0,               // mov     eax,r8d
28322ea0ceaSToshihito Kikuchi     0x48, 0x85, 0xd2,               // test    rdx,rdx
28422ea0ceaSToshihito Kikuchi };
28522ea0ceaSToshihito Kikuchi 
28622ea0ceaSToshihito Kikuchi const u8 kPatchableCode11[] = {
28722ea0ceaSToshihito Kikuchi     0x48, 0x83, 0xec, 0x38,         // sub     rsp,38h
28822ea0ceaSToshihito Kikuchi     0x83, 0x64, 0x24, 0x28, 0x00,   // and     dword ptr [rsp+28h],0
28922ea0ceaSToshihito Kikuchi };
290b89e7746Sbernhardu #      endif
29122ea0ceaSToshihito Kikuchi 
292b89e7746Sbernhardu #      if !SANITIZER_WINDOWS64
293ca40985eSAlvin Wong const u8 kPatchableCode12[] = {
294ca40985eSAlvin Wong     0x55,                           // push    ebp
295ca40985eSAlvin Wong     0x53,                           // push    ebx
296ca40985eSAlvin Wong     0x57,                           // push    edi
297ca40985eSAlvin Wong     0x56,                           // push    esi
298ca40985eSAlvin Wong     0x8b, 0x6c, 0x24, 0x18,         // mov     ebp,dword ptr[esp+18h]
299ca40985eSAlvin Wong };
300ca40985eSAlvin Wong 
301ca40985eSAlvin Wong const u8 kPatchableCode13[] = {
302ca40985eSAlvin Wong     0x55,                           // push    ebp
303ca40985eSAlvin Wong     0x53,                           // push    ebx
304ca40985eSAlvin Wong     0x57,                           // push    edi
305ca40985eSAlvin Wong     0x56,                           // push    esi
306ca40985eSAlvin Wong     0x8b, 0x5c, 0x24, 0x14,         // mov     ebx,dword ptr[esp+14h]
307ca40985eSAlvin Wong };
308b89e7746Sbernhardu #      endif
309ca40985eSAlvin Wong 
310ca40985eSAlvin Wong const u8 kPatchableCode14[] = {
311ca40985eSAlvin Wong     0x55,                           // push    ebp
312ca40985eSAlvin Wong     0x89, 0xe5,                     // mov     ebp,esp
313ca40985eSAlvin Wong     0x53,                           // push    ebx
314ca40985eSAlvin Wong     0x57,                           // push    edi
315ca40985eSAlvin Wong     0x56,                           // push    esi
316ca40985eSAlvin Wong };
317ca40985eSAlvin Wong 
3187b5571f3SAlvin Wong const u8 kUnsupportedCode1[] = {
3197b5571f3SAlvin Wong     0x0f, 0x0b,                     // ud2
3207b5571f3SAlvin Wong     0x0f, 0x0b,                     // ud2
3217b5571f3SAlvin Wong     0x0f, 0x0b,                     // ud2
3227b5571f3SAlvin Wong     0x0f, 0x0b,                     // ud2
3237b5571f3SAlvin Wong };
3247b5571f3SAlvin Wong 
3259642e337SNico Weber // A buffer holding the dynamically generated code under test.
3269642e337SNico Weber u8* ActiveCode;
3279642e337SNico Weber const size_t ActiveCodeLength = 4096;
3289642e337SNico Weber 
3299642e337SNico Weber int InterceptorFunction(int x);
3309642e337SNico Weber 
3319642e337SNico Weber /// Allocate code memory more than 2GB away from Base.
3329642e337SNico Weber u8 *AllocateCode2GBAway(u8 *Base) {
3339642e337SNico Weber   // Find a 64K aligned location after Base plus 2GB.
3349642e337SNico Weber   size_t TwoGB = 0x80000000;
3359642e337SNico Weber   size_t AllocGranularity = 0x10000;
3369642e337SNico Weber   Base = (u8 *)((((uptr)Base + TwoGB + AllocGranularity)) & ~(AllocGranularity - 1));
3379642e337SNico Weber 
3389642e337SNico Weber   // Check if that location is free, and if not, loop over regions until we find
3399642e337SNico Weber   // one that is.
3409642e337SNico Weber   MEMORY_BASIC_INFORMATION mbi = {};
3419642e337SNico Weber   while (sizeof(mbi) == VirtualQuery(Base, &mbi, sizeof(mbi))) {
3429642e337SNico Weber     if (mbi.State & MEM_FREE) break;
3439642e337SNico Weber     Base += mbi.RegionSize;
3449642e337SNico Weber   }
3459642e337SNico Weber 
3469642e337SNico Weber   // Allocate one RWX page at the free location.
3479642e337SNico Weber   return (u8 *)::VirtualAlloc(Base, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE,
3489642e337SNico Weber                               PAGE_EXECUTE_READWRITE);
3499642e337SNico Weber }
3509642e337SNico Weber 
3519642e337SNico Weber template<class T>
3529642e337SNico Weber static void LoadActiveCode(
3539642e337SNico Weber     const T &code,
3549642e337SNico Weber     uptr *entry_point,
3559642e337SNico Weber     FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
3569642e337SNico Weber   if (ActiveCode == nullptr) {
3579642e337SNico Weber     ActiveCode = AllocateCode2GBAway((u8*)&InterceptorFunction);
3589642e337SNico Weber     ASSERT_NE(ActiveCode, nullptr) << "failed to allocate RWX memory 2GB away";
3599642e337SNico Weber   }
3609642e337SNico Weber 
3619642e337SNico Weber   size_t position = 0;
3629642e337SNico Weber 
3639642e337SNico Weber   // Add padding to avoid memory violation when scanning the prefix.
3649642e337SNico Weber   for (int i = 0; i < 16; ++i)
3659642e337SNico Weber     ActiveCode[position++] = 0xC3;  // Instruction 'ret'.
3669642e337SNico Weber 
3679642e337SNico Weber   // Add function padding.
3689642e337SNico Weber   size_t padding = 0;
3699642e337SNico Weber   if (prefix_kind == FunctionPrefixPadding)
3709642e337SNico Weber     padding = 16;
3719642e337SNico Weber   else if (prefix_kind == FunctionPrefixDetour ||
3729642e337SNico Weber            prefix_kind == FunctionPrefixHotPatch)
3739642e337SNico Weber     padding = FIRST_32_SECOND_64(5, 6);
3749642e337SNico Weber   // Insert |padding| instructions 'nop'.
3759642e337SNico Weber   for (size_t i = 0; i < padding; ++i)
3769642e337SNico Weber     ActiveCode[position++] = 0x90;
3779642e337SNico Weber 
3789642e337SNico Weber   // Keep track of the entry point.
3799642e337SNico Weber   *entry_point = (uptr)&ActiveCode[position];
3809642e337SNico Weber 
3819642e337SNico Weber   // Add the detour instruction (i.e. mov edi, edi)
3829642e337SNico Weber   if (prefix_kind == FunctionPrefixDetour) {
3839642e337SNico Weber #if SANITIZER_WINDOWS64
3849642e337SNico Weber     // Note that "mov edi,edi" is NOP in 32-bit only, in 64-bit it clears
3859642e337SNico Weber     // higher bits of RDI.
3869642e337SNico Weber     // Use 66,90H as NOP for Windows64.
3879642e337SNico Weber     ActiveCode[position++] = 0x66;
3889642e337SNico Weber     ActiveCode[position++] = 0x90;
3899642e337SNico Weber #else
3909642e337SNico Weber     // mov edi,edi.
3919642e337SNico Weber     ActiveCode[position++] = 0x8B;
3929642e337SNico Weber     ActiveCode[position++] = 0xFF;
3939642e337SNico Weber #endif
3949642e337SNico Weber 
3959642e337SNico Weber   }
3969642e337SNico Weber 
3979642e337SNico Weber   // Copy the function body.
3989642e337SNico Weber   for (size_t i = 0; i < sizeof(T); ++i)
3999642e337SNico Weber     ActiveCode[position++] = code[i];
4009642e337SNico Weber }
4019642e337SNico Weber 
4029642e337SNico Weber int InterceptorFunctionCalled;
4039642e337SNico Weber IdentityFunction InterceptedRealFunction;
4049642e337SNico Weber 
4059642e337SNico Weber int InterceptorFunction(int x) {
4069642e337SNico Weber   ++InterceptorFunctionCalled;
4079642e337SNico Weber   return InterceptedRealFunction(x);
4089642e337SNico Weber }
4099642e337SNico Weber 
4109642e337SNico Weber }  // namespace
4119642e337SNico Weber 
4129642e337SNico Weber // Tests for interception_win.h
4139642e337SNico Weber TEST(Interception, InternalGetProcAddress) {
4149642e337SNico Weber   HMODULE ntdll_handle = ::GetModuleHandle("ntdll");
4159642e337SNico Weber   ASSERT_NE(nullptr, ntdll_handle);
4169642e337SNico Weber   uptr DbgPrint_expected = (uptr)::GetProcAddress(ntdll_handle, "DbgPrint");
4179642e337SNico Weber   uptr isdigit_expected = (uptr)::GetProcAddress(ntdll_handle, "isdigit");
4189642e337SNico Weber   uptr DbgPrint_adddress = InternalGetProcAddress(ntdll_handle, "DbgPrint");
4199642e337SNico Weber   uptr isdigit_address = InternalGetProcAddress(ntdll_handle, "isdigit");
4209642e337SNico Weber 
4219642e337SNico Weber   EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress);
4229642e337SNico Weber   EXPECT_EQ(isdigit_expected, isdigit_address);
4239642e337SNico Weber   EXPECT_NE(DbgPrint_adddress, isdigit_address);
4249642e337SNico Weber }
4259642e337SNico Weber 
4269642e337SNico Weber template <class T>
4279642e337SNico Weber static void TestIdentityFunctionPatching(
42878c033b5SMarkus Böck     const T &code, TestOverrideFunction override,
42978c033b5SMarkus Böck     FunctionPrefixKind prefix_kind = FunctionPrefixNone,
43078c033b5SMarkus Böck     int function_start_offset = 0) {
4319642e337SNico Weber   uptr identity_address;
4329642e337SNico Weber   LoadActiveCode(code, &identity_address, prefix_kind);
43378c033b5SMarkus Böck   identity_address += function_start_offset;
4349642e337SNico Weber   IdentityFunction identity = (IdentityFunction)identity_address;
4359642e337SNico Weber 
4369642e337SNico Weber   // Validate behavior before dynamic patching.
4379642e337SNico Weber   InterceptorFunctionCalled = 0;
4389642e337SNico Weber   EXPECT_EQ(0, identity(0));
4399642e337SNico Weber   EXPECT_EQ(42, identity(42));
4409642e337SNico Weber   EXPECT_EQ(0, InterceptorFunctionCalled);
4419642e337SNico Weber 
4429642e337SNico Weber   // Patch the function.
4439642e337SNico Weber   uptr real_identity_address = 0;
4449642e337SNico Weber   bool success = override(identity_address,
4459642e337SNico Weber                          (uptr)&InterceptorFunction,
4469642e337SNico Weber                          &real_identity_address);
4479642e337SNico Weber   EXPECT_TRUE(success);
4489642e337SNico Weber   EXPECT_NE(0U, real_identity_address);
4499642e337SNico Weber   IdentityFunction real_identity = (IdentityFunction)real_identity_address;
4509642e337SNico Weber   InterceptedRealFunction = real_identity;
4519642e337SNico Weber 
4529642e337SNico Weber   // Don't run tests if hooking failed or the real function is not valid.
4539642e337SNico Weber   if (!success || !real_identity_address)
4549642e337SNico Weber     return;
4559642e337SNico Weber 
4569642e337SNico Weber   // Calling the redirected function.
4579642e337SNico Weber   InterceptorFunctionCalled = 0;
4589642e337SNico Weber   EXPECT_EQ(0, identity(0));
4599642e337SNico Weber   EXPECT_EQ(42, identity(42));
4609642e337SNico Weber   EXPECT_EQ(2, InterceptorFunctionCalled);
4619642e337SNico Weber 
4629642e337SNico Weber   // Calling the real function.
4639642e337SNico Weber   InterceptorFunctionCalled = 0;
4649642e337SNico Weber   EXPECT_EQ(0, real_identity(0));
4659642e337SNico Weber   EXPECT_EQ(42, real_identity(42));
4669642e337SNico Weber   EXPECT_EQ(0, InterceptorFunctionCalled);
4679642e337SNico Weber 
4689642e337SNico Weber   TestOnlyReleaseTrampolineRegions();
4699642e337SNico Weber }
4709642e337SNico Weber 
4719642e337SNico Weber #    if !SANITIZER_WINDOWS64
4729642e337SNico Weber TEST(Interception, OverrideFunctionWithDetour) {
4739642e337SNico Weber   TestOverrideFunction override = OverrideFunctionWithDetour;
4749642e337SNico Weber   FunctionPrefixKind prefix = FunctionPrefixDetour;
4759642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
4769642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
4779642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
4789642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
4799642e337SNico Weber }
4809642e337SNico Weber #endif  // !SANITIZER_WINDOWS64
4819642e337SNico Weber 
4829642e337SNico Weber TEST(Interception, OverrideFunctionWithRedirectJump) {
4839642e337SNico Weber   TestOverrideFunction override = OverrideFunctionWithRedirectJump;
4849642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithJump, override);
48578c033b5SMarkus Böck   TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards, override,
48678c033b5SMarkus Böck                                FunctionPrefixNone,
48778c033b5SMarkus Böck                                kIdentityCodeWithJumpBackwardsOffset);
4889642e337SNico Weber }
4899642e337SNico Weber 
4909642e337SNico Weber TEST(Interception, OverrideFunctionWithHotPatch) {
4919642e337SNico Weber   TestOverrideFunction override = OverrideFunctionWithHotPatch;
4929642e337SNico Weber   FunctionPrefixKind prefix = FunctionPrefixHotPatch;
4939642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
4949642e337SNico Weber }
4959642e337SNico Weber 
4969642e337SNico Weber TEST(Interception, OverrideFunctionWithTrampoline) {
4979642e337SNico Weber   TestOverrideFunction override = OverrideFunctionWithTrampoline;
4989642e337SNico Weber   FunctionPrefixKind prefix = FunctionPrefixNone;
4999642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
5009642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
5019642e337SNico Weber 
5029642e337SNico Weber   prefix = FunctionPrefixPadding;
5039642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
5049642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
5059642e337SNico Weber }
5069642e337SNico Weber 
5079642e337SNico Weber TEST(Interception, OverrideFunction) {
5089642e337SNico Weber   TestOverrideFunction override = OverrideFunction;
5099642e337SNico Weber   FunctionPrefixKind prefix = FunctionPrefixNone;
5109642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
5119642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
5129642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
5139642e337SNico Weber 
5149642e337SNico Weber   prefix = FunctionPrefixPadding;
5159642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
5169642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
5179642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
5189642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
5199642e337SNico Weber 
5209642e337SNico Weber   prefix = FunctionPrefixHotPatch;
5219642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
5229642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
5239642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
5249642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
5259642e337SNico Weber 
5269642e337SNico Weber   prefix = FunctionPrefixDetour;
5279642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
5289642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
5299642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
5309642e337SNico Weber   TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
5319642e337SNico Weber }
5329642e337SNico Weber 
5339642e337SNico Weber template<class T>
5349642e337SNico Weber static void TestIdentityFunctionMultiplePatching(
5359642e337SNico Weber     const T &code,
5369642e337SNico Weber     TestOverrideFunction override,
5379642e337SNico Weber     FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
5389642e337SNico Weber   uptr identity_address;
5399642e337SNico Weber   LoadActiveCode(code, &identity_address, prefix_kind);
5409642e337SNico Weber 
5419642e337SNico Weber   // Patch the function.
5429642e337SNico Weber   uptr real_identity_address = 0;
5439642e337SNico Weber   bool success = override(identity_address,
5449642e337SNico Weber                           (uptr)&InterceptorFunction,
5459642e337SNico Weber                           &real_identity_address);
5469642e337SNico Weber   EXPECT_TRUE(success);
5479642e337SNico Weber   EXPECT_NE(0U, real_identity_address);
5489642e337SNico Weber 
5499642e337SNico Weber   // Re-patching the function should not work.
5509642e337SNico Weber   success = override(identity_address,
5519642e337SNico Weber                      (uptr)&InterceptorFunction,
5529642e337SNico Weber                      &real_identity_address);
5539642e337SNico Weber   EXPECT_FALSE(success);
5549642e337SNico Weber 
5559642e337SNico Weber   TestOnlyReleaseTrampolineRegions();
5569642e337SNico Weber }
5579642e337SNico Weber 
5589642e337SNico Weber TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) {
5599642e337SNico Weber #if !SANITIZER_WINDOWS64
5609642e337SNico Weber   TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue,
5619642e337SNico Weber                                        OverrideFunctionWithDetour,
5629642e337SNico Weber                                        FunctionPrefixDetour);
5639642e337SNico Weber #endif
5649642e337SNico Weber 
5659642e337SNico Weber   TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov,
5669642e337SNico Weber                                        OverrideFunctionWithHotPatch,
5679642e337SNico Weber                                        FunctionPrefixHotPatch);
5689642e337SNico Weber 
5699642e337SNico Weber   TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop,
5709642e337SNico Weber                                        OverrideFunctionWithTrampoline,
5719642e337SNico Weber                                        FunctionPrefixPadding);
5729642e337SNico Weber }
5739642e337SNico Weber 
5749642e337SNico Weber TEST(Interception, OverrideFunctionTwice) {
5759642e337SNico Weber   uptr identity_address1;
5769642e337SNico Weber   LoadActiveCode(kIdentityTwice, &identity_address1);
5779642e337SNico Weber   uptr identity_address2 = identity_address1 + kIdentityTwiceOffset;
5789642e337SNico Weber   IdentityFunction identity1 = (IdentityFunction)identity_address1;
5799642e337SNico Weber   IdentityFunction identity2 = (IdentityFunction)identity_address2;
5809642e337SNico Weber 
5819642e337SNico Weber   // Patch the two functions.
5829642e337SNico Weber   uptr real_identity_address = 0;
5839642e337SNico Weber   EXPECT_TRUE(OverrideFunction(identity_address1,
5849642e337SNico Weber                                (uptr)&InterceptorFunction,
5859642e337SNico Weber                                &real_identity_address));
5869642e337SNico Weber   EXPECT_TRUE(OverrideFunction(identity_address2,
5879642e337SNico Weber                                (uptr)&InterceptorFunction,
5889642e337SNico Weber                                &real_identity_address));
5899642e337SNico Weber   IdentityFunction real_identity = (IdentityFunction)real_identity_address;
5909642e337SNico Weber   InterceptedRealFunction = real_identity;
5919642e337SNico Weber 
5929642e337SNico Weber   // Calling the redirected function.
5939642e337SNico Weber   InterceptorFunctionCalled = 0;
5949642e337SNico Weber   EXPECT_EQ(42, identity1(42));
5959642e337SNico Weber   EXPECT_EQ(42, identity2(42));
5969642e337SNico Weber   EXPECT_EQ(2, InterceptorFunctionCalled);
5979642e337SNico Weber 
5989642e337SNico Weber   TestOnlyReleaseTrampolineRegions();
5999642e337SNico Weber }
6009642e337SNico Weber 
6019642e337SNico Weber template<class T>
6029642e337SNico Weber static bool TestFunctionPatching(
6039642e337SNico Weber     const T &code,
6049642e337SNico Weber     TestOverrideFunction override,
6059642e337SNico Weber     FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
6069642e337SNico Weber   uptr address;
6079642e337SNico Weber   LoadActiveCode(code, &address, prefix_kind);
6089642e337SNico Weber   uptr unused_real_address = 0;
6099642e337SNico Weber   bool result = override(
6109642e337SNico Weber       address, (uptr)&InterceptorFunction, &unused_real_address);
6119642e337SNico Weber 
6129642e337SNico Weber   TestOnlyReleaseTrampolineRegions();
6139642e337SNico Weber   return result;
6149642e337SNico Weber }
6159642e337SNico Weber 
6169642e337SNico Weber TEST(Interception, PatchableFunction) {
6179642e337SNico Weber   TestOverrideFunction override = OverrideFunction;
6189642e337SNico Weber   // Test without function padding.
6199642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override));
6209642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override));
6219642e337SNico Weber #if SANITIZER_WINDOWS64
6229642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
6239642e337SNico Weber #else
6249642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override));
6259642e337SNico Weber #endif
6269642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
6279642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override));
6289642e337SNico Weber #if SANITIZER_WINDOWS64
6299642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override));
6309642e337SNico Weber #endif
6319642e337SNico Weber 
6329642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
6339642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
6349642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
6359642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
6369642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
6379642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
6389642e337SNico Weber }
6399642e337SNico Weber 
6409642e337SNico Weber #if !SANITIZER_WINDOWS64
6419642e337SNico Weber TEST(Interception, PatchableFunctionWithDetour) {
6429642e337SNico Weber   TestOverrideFunction override = OverrideFunctionWithDetour;
6439642e337SNico Weber   // Without the prefix, no function can be detoured.
6449642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
6459642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
6469642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
6479642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override));
6489642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
6499642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
6509642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
6519642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
6529642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
6539642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
6549642e337SNico Weber 
6559642e337SNico Weber   // With the prefix, all functions can be detoured.
6569642e337SNico Weber   FunctionPrefixKind prefix = FunctionPrefixDetour;
6579642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
6589642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
6599642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
6609642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
6619642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
6629642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
6639642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
6649642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
6659642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
6669642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
6679642e337SNico Weber }
6689642e337SNico Weber #endif  // !SANITIZER_WINDOWS64
6699642e337SNico Weber 
6709642e337SNico Weber TEST(Interception, PatchableFunctionWithRedirectJump) {
6719642e337SNico Weber   TestOverrideFunction override = OverrideFunctionWithRedirectJump;
6729642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
6739642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
6749642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
6759642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
6769642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
6779642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
6789642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
6799642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
6809642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
6819642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
6829642e337SNico Weber }
6839642e337SNico Weber 
6849642e337SNico Weber TEST(Interception, PatchableFunctionWithHotPatch) {
6859642e337SNico Weber   TestOverrideFunction override = OverrideFunctionWithHotPatch;
6869642e337SNico Weber   FunctionPrefixKind prefix = FunctionPrefixHotPatch;
6879642e337SNico Weber 
6889642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
6899642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override, prefix));
6909642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
6919642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
6929642e337SNico Weber #if SANITIZER_WINDOWS64
6939642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode6, override, prefix));
6949642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode7, override, prefix));
6959642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode8, override, prefix));
6969642e337SNico Weber #endif
6979642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
6989642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
6999642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
7009642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
7019642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
7029642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
7039642e337SNico Weber }
7049642e337SNico Weber 
7059642e337SNico Weber TEST(Interception, PatchableFunctionWithTrampoline) {
7069642e337SNico Weber   TestOverrideFunction override = OverrideFunctionWithTrampoline;
7079642e337SNico Weber   FunctionPrefixKind prefix = FunctionPrefixPadding;
7089642e337SNico Weber 
7099642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
7109642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
7119642e337SNico Weber #if SANITIZER_WINDOWS64
7129642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
71322ea0ceaSToshihito Kikuchi   EXPECT_TRUE(TestFunctionPatching(kPatchableCode9, override, prefix));
71422ea0ceaSToshihito Kikuchi   EXPECT_TRUE(TestFunctionPatching(kPatchableCode10, override, prefix));
71522ea0ceaSToshihito Kikuchi   EXPECT_TRUE(TestFunctionPatching(kPatchableCode11, override, prefix));
71622ea0ceaSToshihito Kikuchi   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode7, override, prefix));
71722ea0ceaSToshihito Kikuchi   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode8, override, prefix));
71822ea0ceaSToshihito Kikuchi   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode9, override, prefix));
7199642e337SNico Weber #else
7209642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
721ca40985eSAlvin Wong   EXPECT_TRUE(TestFunctionPatching(kPatchableCode12, override, prefix));
722ca40985eSAlvin Wong   EXPECT_TRUE(TestFunctionPatching(kPatchableCode13, override, prefix));
7239642e337SNico Weber #endif
7249642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
725ca40985eSAlvin Wong   EXPECT_TRUE(TestFunctionPatching(kPatchableCode14, override, prefix));
7269642e337SNico Weber 
7279642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
7289642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
7299642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
7309642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
7319642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
7329642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
7339642e337SNico Weber }
7349642e337SNico Weber 
7357b5571f3SAlvin Wong TEST(Interception, UnsupportedInstructionWithTrampoline) {
7367b5571f3SAlvin Wong   TestOverrideFunction override = OverrideFunctionWithTrampoline;
7377b5571f3SAlvin Wong   FunctionPrefixKind prefix = FunctionPrefixPadding;
7387b5571f3SAlvin Wong 
7390716888dSAlvin Wong   static bool reportCalled;
7400716888dSAlvin Wong   reportCalled = false;
7410716888dSAlvin Wong 
7420716888dSAlvin Wong   struct Local {
7430716888dSAlvin Wong     static void Report(const char *format, ...) {
7440716888dSAlvin Wong       if (reportCalled)
7450716888dSAlvin Wong         FAIL() << "Report called more times than expected";
7460716888dSAlvin Wong       reportCalled = true;
7470716888dSAlvin Wong       ASSERT_STREQ(
7480716888dSAlvin Wong           "interception_win: unhandled instruction at %p: %02x %02x %02x %02x "
7490716888dSAlvin Wong           "%02x %02x %02x %02x\n",
7500716888dSAlvin Wong           format);
7510716888dSAlvin Wong       va_list args;
7520716888dSAlvin Wong       va_start(args, format);
7530716888dSAlvin Wong       u8 *ptr = va_arg(args, u8 *);
7540716888dSAlvin Wong       for (int i = 0; i < 8; i++) EXPECT_EQ(kUnsupportedCode1[i], ptr[i]);
7550716888dSAlvin Wong       int bytes[8];
7560716888dSAlvin Wong       for (int i = 0; i < 8; i++) {
7570716888dSAlvin Wong         bytes[i] = va_arg(args, int);
7580716888dSAlvin Wong         EXPECT_EQ(kUnsupportedCode1[i], bytes[i]);
7590716888dSAlvin Wong       }
7600716888dSAlvin Wong       va_end(args);
7610716888dSAlvin Wong     }
7620716888dSAlvin Wong   };
7630716888dSAlvin Wong 
7640716888dSAlvin Wong   SetErrorReportCallback(Local::Report);
7657b5571f3SAlvin Wong   EXPECT_FALSE(TestFunctionPatching(kUnsupportedCode1, override, prefix));
7660716888dSAlvin Wong   SetErrorReportCallback(nullptr);
7670716888dSAlvin Wong 
7680716888dSAlvin Wong   if (!reportCalled)
7690716888dSAlvin Wong     ADD_FAILURE() << "Report not called";
7707b5571f3SAlvin Wong }
7717b5571f3SAlvin Wong 
7729642e337SNico Weber TEST(Interception, PatchableFunctionPadding) {
7739642e337SNico Weber   TestOverrideFunction override = OverrideFunction;
7749642e337SNico Weber   FunctionPrefixKind prefix = FunctionPrefixPadding;
7759642e337SNico Weber 
7769642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
7779642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
7789642e337SNico Weber #if SANITIZER_WINDOWS64
7799642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
7809642e337SNico Weber #else
7819642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
7829642e337SNico Weber #endif
7839642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
7849642e337SNico Weber 
7859642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
7869642e337SNico Weber   EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
7879642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
7889642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
7899642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
7909642e337SNico Weber   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
7919642e337SNico Weber }
7929642e337SNico Weber 
7939642e337SNico Weber TEST(Interception, EmptyExportTable) {
7949642e337SNico Weber   // We try to get a pointer to a function from an executable that doesn't
7959642e337SNico Weber   // export any symbol (empty export table).
7969642e337SNico Weber   uptr FunPtr = InternalGetProcAddress((void *)GetModuleHandleA(0), "example");
7979642e337SNico Weber   EXPECT_EQ(0U, FunPtr);
7989642e337SNico Weber }
7999642e337SNico Weber 
80036b1811dSbernhardu const struct InstructionSizeData {
80136b1811dSbernhardu   size_t size;  // hold instruction size or 0 for failure,
80236b1811dSbernhardu                 // e.g. on control instructions
80336b1811dSbernhardu   u8 instr[16];
8049a9e41caSbernhardu   size_t rel_offset;  // adjustment for RIP-relative addresses when copying
8059a9e41caSbernhardu                       // instructions during hooking via hotpatch or trampoline.
80636b1811dSbernhardu   const char *comment;
80736b1811dSbernhardu } data[] = {
808b8d857efSbernhardu     // clang-format off
809b8d857efSbernhardu     // sorted list
810b8d857efSbernhardu     { 0, {0x70, 0x71}, 0, "70 XX : jo XX (short conditional jump)"},
811b8d857efSbernhardu     { 0, {0x71, 0x71}, 0, "71 XX : jno XX (short conditional jump)"},
812b8d857efSbernhardu     { 0, {0x72, 0x71}, 0, "72 XX : jb XX (short conditional jump)"},
813b8d857efSbernhardu     { 0, {0x73, 0x71}, 0, "73 XX : jae XX (short conditional jump)"},
814b8d857efSbernhardu     { 0, {0x74, 0x71}, 0, "74 XX : je XX (short conditional jump)"},
815b8d857efSbernhardu     { 0, {0x75, 0x71}, 0, "75 XX : jne XX (short conditional jump)"},
816b8d857efSbernhardu     { 0, {0x76, 0x71}, 0, "76 XX : jbe XX (short conditional jump)"},
817b8d857efSbernhardu     { 0, {0x77, 0x71}, 0, "77 XX : ja XX (short conditional jump)"},
818b8d857efSbernhardu     { 0, {0x78, 0x71}, 0, "78 XX : js XX (short conditional jump)"},
819b8d857efSbernhardu     { 0, {0x79, 0x71}, 0, "79 XX : jns XX (short conditional jump)"},
820b8d857efSbernhardu     { 0, {0x7A, 0x71}, 0, "7A XX : jp XX (short conditional jump)"},
821b8d857efSbernhardu     { 0, {0x7B, 0x71}, 0, "7B XX : jnp XX (short conditional jump)"},
822b8d857efSbernhardu     { 0, {0x7C, 0x71}, 0, "7C XX : jl XX (short conditional jump)"},
823b8d857efSbernhardu     { 0, {0x7D, 0x71}, 0, "7D XX : jge XX (short conditional jump)"},
824b8d857efSbernhardu     { 0, {0x7E, 0x71}, 0, "7E XX : jle XX (short conditional jump)"},
825b8d857efSbernhardu     { 0, {0x7F, 0x71}, 0, "7F XX : jg XX (short conditional jump)"},
826b8d857efSbernhardu     { 0, {0xE8, 0x71, 0x72, 0x73, 0x74}, 0, "E8 XX XX XX XX : call <func>"},
827b8d857efSbernhardu     { 0, {0xE9, 0x71, 0x72, 0x73, 0x74}, 0, "E9 XX XX XX XX : jmp <label>"},
828b8d857efSbernhardu     { 0, {0xEB, 0x71}, 0, "EB XX : jmp XX (short jump)"},
829b8d857efSbernhardu     { 0, {0xFF, 0x25, 0x72, 0x73, 0x74, 0x75}, 0, "FF 25 XX YY ZZ WW : jmp dword ptr ds:[WWZZYYXX]"},
83036b1811dSbernhardu     { 1, {0x50}, 0, "50 : push eax / rax"},
831b8d857efSbernhardu     { 1, {0x51}, 0, "51 : push ecx / rcx"},
832b8d857efSbernhardu     { 1, {0x52}, 0, "52 : push edx / rdx"},
833b8d857efSbernhardu     { 1, {0x53}, 0, "53 : push ebx / rbx"},
834b8d857efSbernhardu     { 1, {0x54}, 0, "54 : push esp / rsp"},
835b8d857efSbernhardu     { 1, {0x55}, 0, "55 : push ebp / rbp"},
836b8d857efSbernhardu     { 1, {0x56}, 0, "56 : push esi / rsi"},
837b8d857efSbernhardu     { 1, {0x57}, 0, "57 : push edi / rdi"},
838b8d857efSbernhardu     { 1, {0x5D}, 0, "5D : pop ebp / rbp"},
839b8d857efSbernhardu     { 1, {0x90}, 0, "90 : nop"},
840b8d857efSbernhardu     { 1, {0xC3}, 0, "C3 : ret   (for small/empty function interception"},
841b8d857efSbernhardu     { 1, {0xCC}, 0, "CC : int 3  i.e. registering weak functions)"},
84299612a3aSbernhardu     { 2, {0x31, 0xC0}, 0, "31 C0 : xor eax, eax"},
84399612a3aSbernhardu     { 2, {0x31, 0xC9}, 0, "31 C9 : xor ecx, ecx"},
84499612a3aSbernhardu     { 2, {0x31, 0xD2}, 0, "31 D2 : xor edx, edx"},
845b8d857efSbernhardu     { 2, {0x33, 0xC0}, 0, "33 C0 : xor eax, eax"},
846b8d857efSbernhardu     { 2, {0x33, 0xC9}, 0, "33 C9 : xor ecx, ecx"},
847b8d857efSbernhardu     { 2, {0x33, 0xD2}, 0, "33 D2 : xor edx, edx"},
848b8d857efSbernhardu     { 2, {0x6A, 0x71}, 0, "6A XX : push XX"},
84999612a3aSbernhardu     { 2, {0x84, 0xC0}, 0, "84 C0 : test al,al"},
850b8d857efSbernhardu     { 2, {0x84, 0xC9}, 0, "84 C9 : test cl,cl"},
851b8d857efSbernhardu     { 2, {0x84, 0xD2}, 0, "84 D2 : test dl,dl"},
852b8d857efSbernhardu     { 2, {0x84, 0xDB}, 0, "84 DB : test bl,bl"},
853b8d857efSbernhardu     { 2, {0x89, 0xc8}, 0, "89 C8 : mov eax, ecx"},
85499612a3aSbernhardu     { 2, {0x89, 0xD1}, 0, "89 D1 : mov ecx, edx"},
855b8d857efSbernhardu     { 2, {0x89, 0xE5}, 0, "89 E5 : mov ebp, esp"},
856b8d857efSbernhardu     { 2, {0x8A, 0x01}, 0, "8A 01 : mov al, byte ptr [ecx]"},
857b8d857efSbernhardu     { 2, {0x8B, 0xC1}, 0, "8B C1 : mov eax, ecx"},
858b8d857efSbernhardu     { 2, {0x8B, 0xEC}, 0, "8B EC : mov ebp, esp"},
859b8d857efSbernhardu     { 2, {0x8B, 0xFF}, 0, "8B FF : mov edi, edi"},
86057466db7Sbernhardu     { 3, {0x80, 0x39, 0x72}, 0, "80 39 XX : cmp BYTE PTR [rcx], XX"},
861f85579fbSbernhardu     { 3, {0x83, 0xE4, 0x72}, 0, "83 E4 XX : and esp, XX"},
862854ea0cfSbernhardu     { 3, {0x83, 0xEC, 0x72}, 0, "83 EC XX : sub esp, XX"},
86357466db7Sbernhardu     { 3, {0x8B, 0x4D, 0x72}, 0, "8B 4D XX : mov XX(%ebp), ecx"},
86457466db7Sbernhardu     { 3, {0x8B, 0x55, 0x72}, 0, "8B 55 XX : mov XX(%ebp), edx"},
86557466db7Sbernhardu     { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov XX(%ebp), esp"},
866b8d857efSbernhardu     { 3, {0xc2, 0x71, 0x72}, 0, "C2 XX XX : ret XX (needed for registering weak functions)"},
86756592a81Sbernhardu     { 4, {0x8D, 0x4C, 0x24, 0x73}, 0, "8D 4C 24 XX : lea ecx, [esp + XX]"},
86856592a81Sbernhardu     { 4, {0xFF, 0x74, 0x24, 0x73}, 0, "FF 74 24 XX : push qword ptr [rsp + XX]"},
869b8d857efSbernhardu     { 5, {0x68, 0x71, 0x72, 0x73, 0x74}, 0, "68 XX XX XX XX : push imm32"},
870b8d857efSbernhardu     { 5, {0xb8, 0x71, 0x72, 0x73, 0x74}, 0, "b8 XX XX XX XX : mov eax, XX XX XX XX"},
871b8d857efSbernhardu     { 5, {0xB9, 0x71, 0x72, 0x73, 0x74}, 0, "b9 XX XX XX XX : mov ecx, XX XX XX XX"},
8725f405707Sbernhardu     { 5, {0xBA, 0x71, 0x72, 0x73, 0x74}, 0, "ba XX XX XX XX : mov edx, XX XX XX XX"},
873351ee305Sbernhardu     { 6, {0x81, 0xEC, 0x72, 0x73, 0x74, 0x75}, 0, "81 EC XX XX XX XX : sub esp, XX XX XX XX"},
874351ee305Sbernhardu     { 6, {0xFF, 0x89, 0x72, 0x73, 0x74, 0x75}, 0, "FF 89 XX XX XX XX : dec dword ptr [ecx + XX XX XX XX]"},
8759a9e41caSbernhardu     { 7, {0x8D, 0xA4, 0x24, 0x73, 0x74, 0x75, 0x76}, 0, "8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX]"},
876b8d857efSbernhardu #if SANITIZER_WINDOWS_x64
877b8d857efSbernhardu     // sorted list
878b8d857efSbernhardu     { 2, {0x40, 0x50}, 0, "40 50 : push rax"},
879b8d857efSbernhardu     { 2, {0x40, 0x51}, 0, "40 51 : push rcx"},
880b8d857efSbernhardu     { 2, {0x40, 0x52}, 0, "40 52 : push rdx"},
881b8d857efSbernhardu     { 2, {0x40, 0x53}, 0, "40 53 : push rbx"},
882b8d857efSbernhardu     { 2, {0x40, 0x54}, 0, "40 54 : push rsp"},
883b8d857efSbernhardu     { 2, {0x40, 0x55}, 0, "40 55 : push rbp"},
884b8d857efSbernhardu     { 2, {0x40, 0x56}, 0, "40 56 : push rsi"},
885b8d857efSbernhardu     { 2, {0x40, 0x57}, 0, "40 57 : push rdi"},
886b8d857efSbernhardu     { 2, {0x41, 0x54}, 0, "41 54 : push r12"},
887b8d857efSbernhardu     { 2, {0x41, 0x55}, 0, "41 55 : push r13"},
888b8d857efSbernhardu     { 2, {0x41, 0x56}, 0, "41 56 : push r14"},
889b8d857efSbernhardu     { 2, {0x41, 0x57}, 0, "41 57 : push r15"},
890b8d857efSbernhardu     { 2, {0x66, 0x90}, 0, "66 90 : Two-byte NOP"},
891b8d857efSbernhardu     { 2, {0x84, 0xc0}, 0, "84 c0 : test al, al"},
892b8d857efSbernhardu     { 2, {0x8a, 0x01}, 0, "8a 01 : mov al, byte ptr [rcx]"},
89357466db7Sbernhardu     { 3, {0x0f, 0xb6, 0x01}, 0, "0f b6 01 : movzx eax, BYTE PTR [rcx]"},
89457466db7Sbernhardu     { 3, {0x0f, 0xb6, 0x09}, 0, "0f b6 09 : movzx ecx, BYTE PTR [rcx]"},
89557466db7Sbernhardu     { 3, {0x0f, 0xb6, 0x11}, 0, "0f b6 11 : movzx edx, BYTE PTR [rcx]"},
896b8d857efSbernhardu     { 3, {0x0f, 0xb6, 0xc2}, 0, "0f b6 c2 : movzx eax, dl"},
897b8d857efSbernhardu     { 3, {0x0f, 0xb6, 0xd2}, 0, "0f b6 d2 : movzx edx, dl"},
898b8d857efSbernhardu     { 3, {0x0f, 0xb7, 0x10}, 0, "0f b7 10 : movzx edx, WORD PTR [rax]"},
89957466db7Sbernhardu     { 3, {0x0f, 0xbe, 0xd2}, 0, "0f be d2 : movsx edx, dl"},
900b8d857efSbernhardu     { 3, {0x41, 0x8b, 0xc0}, 0, "41 8b c0 : mov eax, r8d"},
901b8d857efSbernhardu     { 3, {0x41, 0x8b, 0xc1}, 0, "41 8b c1 : mov eax, r9d"},
902b8d857efSbernhardu     { 3, {0x41, 0x8b, 0xc2}, 0, "41 8b c2 : mov eax, r10d"},
903b8d857efSbernhardu     { 3, {0x41, 0x8b, 0xc3}, 0, "41 8b c3 : mov eax, r11d"},
904b8d857efSbernhardu     { 3, {0x41, 0x8b, 0xc4}, 0, "41 8b c4 : mov eax, r12d"},
90557466db7Sbernhardu     { 3, {0x45, 0x31, 0xc0}, 0, "45 31 c0 : xor r8d,r8d"},
90657466db7Sbernhardu     { 3, {0x45, 0x31, 0xc9}, 0, "45 31 c9 : xor r9d,r9d"},
907b8d857efSbernhardu     { 3, {0x45, 0x33, 0xc0}, 0, "45 33 c0 : xor r8d, r8d"},
908b8d857efSbernhardu     { 3, {0x45, 0x33, 0xc9}, 0, "45 33 c9 : xor r9d, r9d"},
909b8d857efSbernhardu     { 3, {0x45, 0x33, 0xdb}, 0, "45 33 db : xor r11d, r11d"},
91057466db7Sbernhardu     { 3, {0x45, 0x84, 0xc0}, 0, "45 84 c0 : test r8b,r8b"},
91157466db7Sbernhardu     { 3, {0x45, 0x84, 0xd2}, 0, "45 84 d2 : test r10b,r10b"},
91257466db7Sbernhardu     { 3, {0x48, 0x29, 0xd1}, 0, "48 29 d1 : sub rcx, rdx"},
913b8d857efSbernhardu     { 3, {0x48, 0x2b, 0xca}, 0, "48 2b ca : sub rcx, rdx"},
914b8d857efSbernhardu     { 3, {0x48, 0x2b, 0xd1}, 0, "48 2b d1 : sub rdx, rcx"},
915b8d857efSbernhardu     { 3, {0x48, 0x3b, 0xca}, 0, "48 3b ca : cmp rcx, rdx"},
916b8d857efSbernhardu     { 3, {0x48, 0x85, 0xc0}, 0, "48 85 c0 : test rax, rax"},
917b8d857efSbernhardu     { 3, {0x48, 0x85, 0xc9}, 0, "48 85 c9 : test rcx, rcx"},
918b8d857efSbernhardu     { 3, {0x48, 0x85, 0xd2}, 0, "48 85 d2 : test rdx, rdx"},
919b8d857efSbernhardu     { 3, {0x48, 0x85, 0xdb}, 0, "48 85 db : test rbx, rbx"},
920b8d857efSbernhardu     { 3, {0x48, 0x85, 0xe4}, 0, "48 85 e4 : test rsp, rsp"},
921b8d857efSbernhardu     { 3, {0x48, 0x85, 0xed}, 0, "48 85 ed : test rbp, rbp"},
92257466db7Sbernhardu     { 3, {0x48, 0x89, 0xc8}, 0, "48 89 c8 : mov rax,rcx"},
92357466db7Sbernhardu     { 3, {0x48, 0x89, 0xcb}, 0, "48 89 cb : mov rbx,rcx"},
92457466db7Sbernhardu     { 3, {0x48, 0x89, 0xd0}, 0, "48 89 d0 : mov rax,rdx"},
92557466db7Sbernhardu     { 3, {0x48, 0x89, 0xd1}, 0, "48 89 d1 : mov rcx,rdx"},
92657466db7Sbernhardu     { 3, {0x48, 0x89, 0xd3}, 0, "48 89 d3 : mov rbx,rdx"},
927b8d857efSbernhardu     { 3, {0x48, 0x89, 0xe5}, 0, "48 89 e5 : mov rbp, rsp"},
928b8d857efSbernhardu     { 3, {0x48, 0x8b, 0xc1}, 0, "48 8b c1 : mov rax, rcx"},
929b8d857efSbernhardu     { 3, {0x48, 0x8b, 0xc4}, 0, "48 8b c4 : mov rax, rsp"},
930b8d857efSbernhardu     { 3, {0x48, 0x8b, 0xd1}, 0, "48 8b d1 : mov rdx, rcx"},
931b8d857efSbernhardu     { 3, {0x48, 0xf7, 0xd9}, 0, "48 f7 d9 : neg rcx"},
932b8d857efSbernhardu     { 3, {0x48, 0xff, 0xc0}, 0, "48 ff c0 : inc rax"},
933b8d857efSbernhardu     { 3, {0x48, 0xff, 0xc1}, 0, "48 ff c1 : inc rcx"},
934b8d857efSbernhardu     { 3, {0x48, 0xff, 0xc2}, 0, "48 ff c2 : inc rdx"},
935b8d857efSbernhardu     { 3, {0x48, 0xff, 0xc3}, 0, "48 ff c3 : inc rbx"},
936b8d857efSbernhardu     { 3, {0x48, 0xff, 0xc6}, 0, "48 ff c6 : inc rsi"},
937b8d857efSbernhardu     { 3, {0x48, 0xff, 0xc7}, 0, "48 ff c7 : inc rdi"},
93857466db7Sbernhardu     { 3, {0x49, 0x89, 0xc8}, 0, "49 89 c8 : mov r8, rcx"},
93957466db7Sbernhardu     { 3, {0x49, 0x89, 0xc9}, 0, "49 89 c9 : mov r9, rcx"},
94057466db7Sbernhardu     { 3, {0x49, 0x89, 0xca}, 0, "49 89 ca : mov r10,rcx"},
94157466db7Sbernhardu     { 3, {0x49, 0x89, 0xd0}, 0, "49 89 d0 : mov r8, rdx"},
94257466db7Sbernhardu     { 3, {0x49, 0x89, 0xd1}, 0, "49 89 d1 : mov r9, rdx"},
94357466db7Sbernhardu     { 3, {0x49, 0x89, 0xd2}, 0, "49 89 d2 : mov r10, rdx"},
94457466db7Sbernhardu     { 3, {0x49, 0x89, 0xd3}, 0, "49 89 d3 : mov r11, rdx"},
945b8d857efSbernhardu     { 3, {0x49, 0xff, 0xc0}, 0, "49 ff c0 : inc r8"},
946b8d857efSbernhardu     { 3, {0x49, 0xff, 0xc1}, 0, "49 ff c1 : inc r9"},
947b8d857efSbernhardu     { 3, {0x49, 0xff, 0xc2}, 0, "49 ff c2 : inc r10"},
948b8d857efSbernhardu     { 3, {0x49, 0xff, 0xc3}, 0, "49 ff c3 : inc r11"},
949b8d857efSbernhardu     { 3, {0x49, 0xff, 0xc4}, 0, "49 ff c4 : inc r12"},
950b8d857efSbernhardu     { 3, {0x49, 0xff, 0xc5}, 0, "49 ff c5 : inc r13"},
951b8d857efSbernhardu     { 3, {0x49, 0xff, 0xc6}, 0, "49 ff c6 : inc r14"},
952b8d857efSbernhardu     { 3, {0x49, 0xff, 0xc7}, 0, "49 ff c7 : inc r15"},
953b8d857efSbernhardu     { 3, {0x4c, 0x8b, 0xc1}, 0, "4c 8b c1 : mov r8, rcx"},
954b8d857efSbernhardu     { 3, {0x4c, 0x8b, 0xc9}, 0, "4c 8b c9 : mov r9, rcx"},
955b8d857efSbernhardu     { 3, {0x4c, 0x8b, 0xd1}, 0, "4c 8b d1 : mov r10, rcx"},
956b8d857efSbernhardu     { 3, {0x4c, 0x8b, 0xd2}, 0, "4c 8b d2 : mov r10, rdx"},
957b8d857efSbernhardu     { 3, {0x4c, 0x8b, 0xd9}, 0, "4c 8b d9 : mov r11, rcx"},
958b8d857efSbernhardu     { 3, {0x4c, 0x8b, 0xdc}, 0, "4c 8b dc : mov r11, rsp"},
959b8d857efSbernhardu     { 3, {0x4d, 0x0b, 0xc0}, 0, "4d 0b c0 : or r8, r8"},
960b8d857efSbernhardu     { 3, {0x4d, 0x85, 0xc0}, 0, "4d 85 c0 : test r8, r8"},
961b8d857efSbernhardu     { 3, {0x4d, 0x85, 0xc9}, 0, "4d 85 c9 : test r9, r9"},
962b8d857efSbernhardu     { 3, {0x4d, 0x85, 0xd2}, 0, "4d 85 d2 : test r10, r10"},
963b8d857efSbernhardu     { 3, {0x4d, 0x85, 0xdb}, 0, "4d 85 db : test r11, r11"},
964b8d857efSbernhardu     { 3, {0x4d, 0x85, 0xe4}, 0, "4d 85 e4 : test r12, r12"},
965b8d857efSbernhardu     { 3, {0x4d, 0x85, 0xed}, 0, "4d 85 ed : test r13, r13"},
966b8d857efSbernhardu     { 3, {0x4d, 0x85, 0xf6}, 0, "4d 85 f6 : test r14, r14"},
967b8d857efSbernhardu     { 3, {0x4d, 0x85, 0xff}, 0, "4d 85 ff : test r15, r15"},
968bf6f1ca2Sbernhardu     { 3, {0xf6, 0xc1, 0x72}, 0, "f6 c1 XX : test cl, XX"},
96956592a81Sbernhardu     { 4, {0x44, 0x0f, 0xb6, 0x01}, 0, "44 0f b6 01 : movzx r8d, BYTE PTR [rcx]"},
97056592a81Sbernhardu     { 4, {0x44, 0x0f, 0xb6, 0x09}, 0, "44 0f b6 09 : movzx r9d, BYTE PTR [rcx]"},
97156592a81Sbernhardu     { 4, {0x44, 0x0f, 0xb6, 0x0a}, 0, "44 0f b6 0a : movzx r8d, BYTE PTR [rdx]"},
97256592a81Sbernhardu     { 4, {0x44, 0x0f, 0xb6, 0x11}, 0, "44 0f b6 11 : movzx r10d, BYTE PTR [rcx]"},
973b8d857efSbernhardu     { 4, {0x44, 0x0f, 0xb6, 0x1a}, 0, "44 0f b6 1a : movzx r11d, BYTE PTR [rdx]"},
974b8d857efSbernhardu     { 4, {0x44, 0x8d, 0x42, 0x73}, 0, "44 8d 42 XX : lea r8d , [rdx + XX]"},
975b8d857efSbernhardu     { 4, {0x48, 0x83, 0xec, 0x73}, 0, "48 83 ec XX : sub rsp, XX"},
976b8d857efSbernhardu     { 4, {0x48, 0x89, 0x58, 0x73}, 0, "48 89 58 XX : mov QWORD PTR[rax + XX], rbx"},
977b8d857efSbernhardu     { 4, {0x49, 0x83, 0xf8, 0x73}, 0, "49 83 f8 XX : cmp r8, XX"},
97856592a81Sbernhardu     { 4, {0x49, 0x8d, 0x48, 0x73}, 0, "49 8d 48 XX : lea rcx, [...]"},
97956592a81Sbernhardu     { 4, {0x4c, 0x8d, 0x04, 0x73}, 0, "4c 8d 04 XX : lea r8, [...]"},
98056592a81Sbernhardu     { 4, {0x4e, 0x8d, 0x14, 0x73}, 0, "4e 8d 14 XX : lea r10, [...]"},
98156592a81Sbernhardu     { 4, {0x66, 0x83, 0x39, 0x73}, 0, "66 83 39 XX : cmp WORD PTR [rcx], XX"},
982b8d857efSbernhardu     { 4, {0x80, 0x78, 0x72, 0x73}, 0, "80 78 YY XX : cmp BYTE PTR [rax+YY], XX"},
983b8d857efSbernhardu     { 4, {0x80, 0x79, 0x72, 0x73}, 0, "80 79 YY XX : cmp BYTE ptr [rcx+YY], XX"},
984b8d857efSbernhardu     { 4, {0x80, 0x7A, 0x72, 0x73}, 0, "80 7A YY XX : cmp BYTE PTR [rdx+YY], XX"},
985b8d857efSbernhardu     { 4, {0x80, 0x7B, 0x72, 0x73}, 0, "80 7B YY XX : cmp BYTE PTR [rbx+YY], XX"},
986b8d857efSbernhardu     { 4, {0x80, 0x7D, 0x72, 0x73}, 0, "80 7D YY XX : cmp BYTE PTR [rbp+YY], XX"},
987b8d857efSbernhardu     { 4, {0x80, 0x7E, 0x72, 0x73}, 0, "80 7E YY XX : cmp BYTE PTR [rsi+YY], XX"},
988b8d857efSbernhardu     { 4, {0x89, 0x54, 0x24, 0x73}, 0, "89 54 24 XX : mov DWORD PTR[rsp + XX], edx"},
9895f405707Sbernhardu     { 5, {0x0F, 0x1F, 0x44, 0x73, 0x74}, 0, "0F 1F 44 XX XX : nop DWORD PTR [...]"},
990b8d857efSbernhardu     { 5, {0x44, 0x89, 0x44, 0x24, 0x74}, 0, "44 89 44 24 XX : mov DWORD PTR [rsp + XX], r8d"},
991b8d857efSbernhardu     { 5, {0x44, 0x89, 0x4c, 0x24, 0x74}, 0, "44 89 4c 24 XX : mov DWORD PTR [rsp + XX], r9d"},
992b8d857efSbernhardu     { 5, {0x48, 0x89, 0x4C, 0x24, 0x74}, 0, "48 89 4C 24 XX : mov QWORD PTR [rsp + XX], rcx"},
993b8d857efSbernhardu     { 5, {0x48, 0x89, 0x54, 0x24, 0x74}, 0, "48 89 54 24 XX : mov QWORD PTR [rsp + XX], rdx"},
994b8d857efSbernhardu     { 5, {0x48, 0x89, 0x5c, 0x24, 0x74}, 0, "48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx"},
995b8d857efSbernhardu     { 5, {0x48, 0x89, 0x6c, 0x24, 0x74}, 0, "48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp"},
996b8d857efSbernhardu     { 5, {0x48, 0x89, 0x74, 0x24, 0x74}, 0, "48 89 74 24 XX : mov QWORD PTR [rsp + XX], rsi"},
997b8d857efSbernhardu     { 5, {0x48, 0x89, 0x7c, 0x24, 0x74}, 0, "48 89 7c 24 XX : mov QWORD PTR [rsp + XX], rdi"},
998b8d857efSbernhardu     { 5, {0x48, 0x8b, 0x44, 0x24, 0x74}, 0, "48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX]"},
999b8d857efSbernhardu     { 5, {0x48, 0x8d, 0x6c, 0x24, 0x74}, 0, "48 8d 6c 24 XX : lea rbp, [rsp + XX]"},
1000b8d857efSbernhardu     { 5, {0x4c, 0x89, 0x44, 0x24, 0x74}, 0, "4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8"},
1001b8d857efSbernhardu     { 5, {0x4c, 0x89, 0x4c, 0x24, 0x74}, 0, "4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9"},
10025f405707Sbernhardu     { 5, {0x66, 0x48, 0x0F, 0x7E, 0xC0}, 0, "66 48 0F 7E C0 : movq rax, xmm0"},
1003b8d857efSbernhardu     { 5, {0x83, 0x44, 0x72, 0x73, 0x74}, 0, "83 44 72 XX YY : add DWORD PTR [rdx+rsi*2+XX],YY"},
1004b8d857efSbernhardu     { 5, {0x83, 0x64, 0x24, 0x73, 0x74}, 0, "83 64 24 XX YY : and DWORD PTR [rsp+XX], YY"},
1005351ee305Sbernhardu     { 6, {0x41, 0xB8, 0x72, 0x73, 0x74, 0x75}, 0, "41 B8 XX XX XX XX : mov r8d, XX XX XX XX"},
1006b8d857efSbernhardu     { 6, {0x48, 0x83, 0x64, 0x24, 0x74, 0x75}, 0, "48 83 64 24 XX YY : and QWORD PTR [rsp + XX], YY"},
1007b8d857efSbernhardu     { 6, {0x66, 0x81, 0x78, 0x73, 0x74, 0x75}, 0, "66 81 78 XX YY YY : cmp WORD PTR [rax+XX], YY YY"},
1008b8d857efSbernhardu     { 6, {0x66, 0x81, 0x79, 0x73, 0x74, 0x75}, 0, "66 81 79 XX YY YY : cmp WORD PTR [rcx+XX], YY YY"},
1009b8d857efSbernhardu     { 6, {0x66, 0x81, 0x7a, 0x73, 0x74, 0x75}, 0, "66 81 7a XX YY YY : cmp WORD PTR [rdx+XX], YY YY"},
1010b8d857efSbernhardu     { 6, {0x66, 0x81, 0x7b, 0x73, 0x74, 0x75}, 0, "66 81 7b XX YY YY : cmp WORD PTR [rbx+XX], YY YY"},
1011b8d857efSbernhardu     { 6, {0x66, 0x81, 0x7e, 0x73, 0x74, 0x75}, 0, "66 81 7e XX YY YY : cmp WORD PTR [rsi+XX], YY YY"},
1012b8d857efSbernhardu     { 6, {0x66, 0x81, 0x7f, 0x73, 0x74, 0x75}, 0, "66 81 7f XX YY YY : cmp WORD PTR [rdi+XX], YY YY"},
1013b8d857efSbernhardu     { 6, {0x8A, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8A 05 XX XX XX XX : mov al, byte ptr [XX XX XX XX]"},
1014b8d857efSbernhardu     { 6, {0x8B, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]"},
1015b8d857efSbernhardu     { 6, {0xF2, 0x0f, 0x11, 0x44, 0x24, 0x75}, 0, "f2 0f 11 44 24 XX : movsd QWORD PTR [rsp + XX], xmm0"},
1016b8d857efSbernhardu     { 6, {0xF2, 0x0f, 0x11, 0x4c, 0x24, 0x75}, 0, "f2 0f 11 4c 24 XX : movsd QWORD PTR [rsp + XX], xmm1"},
1017b8d857efSbernhardu     { 6, {0xF2, 0x0f, 0x11, 0x54, 0x24, 0x75}, 0, "f2 0f 11 54 24 XX : movsd QWORD PTR [rsp + XX], xmm2"},
1018b8d857efSbernhardu     { 6, {0xF2, 0x0f, 0x11, 0x5c, 0x24, 0x75}, 0, "f2 0f 11 5c 24 XX : movsd QWORD PTR [rsp + XX], xmm3"},
1019b8d857efSbernhardu     { 6, {0xF2, 0x0f, 0x11, 0x64, 0x24, 0x75}, 0, "f2 0f 11 64 24 XX : movsd QWORD PTR [rsp + XX], xmm4"},
1020b8d857efSbernhardu     { 7, {0x48, 0x81, 0xec, 0x73, 0x74, 0x75, 0x76}, 0, "48 81 EC XX XX XX XX : sub rsp, XXXXXXXX"},
1021b8d857efSbernhardu     { 7, {0x48, 0x89, 0x0d, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 0d XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rcx"},
1022b8d857efSbernhardu     { 7, {0x48, 0x89, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 15 XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rdx"},
1023b8d857efSbernhardu     { 7, {0x48, 0x8b, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8b 05 XX XX XX XX : mov rax, QWORD PTR [rip + XXXXXXXX]"},
1024b8d857efSbernhardu     { 7, {0x48, 0x8d, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8d 05 XX XX XX XX : lea rax, QWORD PTR [rip + XXXXXXXX]"},
1025*bbf37706Sbernhardu     { 7, {0x48, 0xc7, 0xc0, 0x73, 0x74, 0x75, 0x76}, 0, "48 C7 C0 XX XX XX XX : mov rax, XX XX XX XX"},
1026b8d857efSbernhardu     { 7, {0x48, 0xff, 0x25, 0x73, 0x74, 0x75, 0x76}, 3, "48 ff 25 XX XX XX XX : rex.W jmp QWORD PTR [rip + XXXXXXXX]"},
1027b8d857efSbernhardu     { 7, {0x4C, 0x8D, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "4c 8d 15 XX XX XX XX : lea r10, [rip + XX]"},
1028b8d857efSbernhardu     { 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"},
1029b8d857efSbernhardu     { 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"},
1030b8d857efSbernhardu     { 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"},
1031b8d857efSbernhardu     { 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"},
1032b8d857efSbernhardu     { 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"},
1033b8d857efSbernhardu     { 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"},
1034b8d857efSbernhardu     { 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"},
1035b8d857efSbernhardu     { 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"},
1036b8d857efSbernhardu     { 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"},
1037b8d857efSbernhardu     { 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"},
1038b8d857efSbernhardu     { 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"},
1039b8d857efSbernhardu     { 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"},
1040b8d857efSbernhardu     { 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*bbf37706Sbernhardu     { 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]"},
1042b8d857efSbernhardu     { 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"},
1043b8d857efSbernhardu     { 8, {0xc7, 0x44, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "C7 44 24 XX YY YY YY YY : mov dword ptr [rsp + XX], YYYYYYYY"},
1044213c90d3Sbernhardu     { 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"},
1045b8d857efSbernhardu     { 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]"},
1046b8d857efSbernhardu #else
1047b8d857efSbernhardu     // sorted list
1048b8d857efSbernhardu     { 3, {0x8B, 0x45, 0x72}, 0, "8B 45 XX : mov eax, dword ptr [ebp + XX]"},
1049b8d857efSbernhardu     { 3, {0x8B, 0x5D, 0x72}, 0, "8B 5D XX : mov ebx, dword ptr [ebp + XX]"},
1050b8d857efSbernhardu     { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov esi, dword ptr [ebp + XX]"},
1051b8d857efSbernhardu     { 3, {0x8B, 0x7D, 0x72}, 0, "8B 7D XX : mov edi, dword ptr [ebp + XX]"},
1052b8d857efSbernhardu     { 3, {0xFF, 0x75, 0x72}, 0, "FF 75 XX : push dword ptr [ebp + XX]"},
1053b8d857efSbernhardu     { 4, {0x83, 0x7D, 0x72, 0x73}, 0, "83 7D XX YY : cmp dword ptr [ebp + XX], YY"},
1054b8d857efSbernhardu     { 4, {0x8A, 0x44, 0x24, 0x73}, 0, "8A 44 24 XX : mov eal, dword ptr [esp + XX]"},
1055b8d857efSbernhardu     { 4, {0x8B, 0x44, 0x24, 0x73}, 0, "8B 44 24 XX : mov eax, dword ptr [esp + XX]"},
1056b8d857efSbernhardu     { 4, {0x8B, 0x4C, 0x24, 0x73}, 0, "8B 4C 24 XX : mov ecx, dword ptr [esp + XX]"},
1057b8d857efSbernhardu     { 4, {0x8B, 0x54, 0x24, 0x73}, 0, "8B 54 24 XX : mov edx, dword ptr [esp + XX]"},
1058b8d857efSbernhardu     { 4, {0x8B, 0x5C, 0x24, 0x73}, 0, "8B 5C 24 XX : mov ebx, dword ptr [esp + XX]"},
1059b8d857efSbernhardu     { 4, {0x8B, 0x6C, 0x24, 0x73}, 0, "8B 6C 24 XX : mov ebp, dword ptr [esp + XX]"},
1060b8d857efSbernhardu     { 4, {0x8B, 0x74, 0x24, 0x73}, 0, "8B 74 24 XX : mov esi, dword ptr [esp + XX]"},
1061b8d857efSbernhardu     { 4, {0x8B, 0x7C, 0x24, 0x73}, 0, "8B 7C 24 XX : mov edi, dword ptr [esp + XX]"},
1062b8d857efSbernhardu     { 5, {0x0F, 0xB6, 0x44, 0x24, 0x74}, 0, "0F B6 44 24 XX : movzx eax, byte ptr [esp + XX]"},
1063b8d857efSbernhardu     { 5, {0xA1, 0x71, 0x72, 0x73, 0x74}, 0, "A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX]"},
1064b8d857efSbernhardu     { 6, {0xF7, 0xC1, 0x72, 0x73, 0x74, 0x75}, 0, "F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX"},
1065b8d857efSbernhardu     { 7, {0x83, 0x3D, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "83 3D XX YY ZZ WW TT : cmp TT, WWZZYYXX"},
1066b8d857efSbernhardu #endif
1067b8d857efSbernhardu     // clang-format on
106836b1811dSbernhardu };
106936b1811dSbernhardu 
107036b1811dSbernhardu std::string dumpInstruction(unsigned arrayIndex,
107136b1811dSbernhardu                             const InstructionSizeData &data) {
107236b1811dSbernhardu   std::stringstream ret;
107336b1811dSbernhardu   ret << "  with arrayIndex=" << arrayIndex << " {";
107436b1811dSbernhardu   for (size_t i = 0; i < data.size; i++) {
107536b1811dSbernhardu     if (i > 0)
107636b1811dSbernhardu       ret << ", ";
107736b1811dSbernhardu     ret << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex
107836b1811dSbernhardu         << (int)data.instr[i];
107936b1811dSbernhardu   }
108036b1811dSbernhardu   ret << "} " << data.comment;
108136b1811dSbernhardu   return ret.str();
108236b1811dSbernhardu }
108336b1811dSbernhardu 
108436b1811dSbernhardu TEST(Interception, GetInstructionSize) {
108536b1811dSbernhardu   for (unsigned i = 0; i < sizeof(data) / sizeof(*data); i++) {
108636b1811dSbernhardu     size_t rel_offset = ~0L;
108736b1811dSbernhardu     size_t size = __interception::TestOnlyGetInstructionSize(
108836b1811dSbernhardu         (uptr)data[i].instr, &rel_offset);
108936b1811dSbernhardu     EXPECT_EQ(data[i].size, size) << dumpInstruction(i, data[i]);
109036b1811dSbernhardu     EXPECT_EQ(data[i].rel_offset, rel_offset) << dumpInstruction(i, data[i]);
109136b1811dSbernhardu   }
109236b1811dSbernhardu }
109336b1811dSbernhardu 
10949642e337SNico Weber }  // namespace __interception
10959642e337SNico Weber 
1096d79aee9fSFarzon Lotfi #    endif  // !SANITIZER_WINDOWS_ARM64
10979642e337SNico Weber #endif  // SANITIZER_WINDOWS
10989642e337SNico Weber #endif  // #if !SANITIZER_DEBUG
1099