Fix typo in 9b54bd30006c008b4a951331b273613d5bac3abf
[pm.git] / xpcom / build / nsWindowsDllInterceptor.h
blobb4cda713a6dd28a763824b17c471264718cb3e9c
1 /* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef NS_WINDOWS_DLL_INTERCEPTOR_H_
7 #define NS_WINDOWS_DLL_INTERCEPTOR_H_
8 #include <windows.h>
9 #include <winternl.h>
12 * Simple function interception.
14 * We have two separate mechanisms for intercepting a function: We can use the
15 * built-in nop space, if it exists, or we can create a detour.
17 * Using the built-in nop space works as follows: On x86-32, DLL functions
18 * begin with a two-byte nop (mov edi, edi) and are preceeded by five bytes of
19 * NOP instructions.
21 * When we detect a function with this prelude, we do the following:
23 * 1. Write a long jump to our interceptor function into the five bytes of NOPs
24 * before the function.
26 * 2. Write a short jump -5 into the two-byte nop at the beginning of the function.
28 * This mechanism is nice because it's thread-safe. It's even safe to do if
29 * another thread is currently running the function we're modifying!
31 * When the WindowsDllNopSpacePatcher is destroyed, we overwrite the short jump
32 * but not the long jump, so re-intercepting the same function won't work,
33 * because its prelude won't match.
36 * Unfortunately nop space patching doesn't work on functions which don't have
37 * this magic prelude (and in particular, x86-64 never has the prelude). So
38 * when we can't use the built-in nop space, we fall back to using a detour,
39 * which works as follows:
41 * 1. Save first N bytes of OrigFunction to trampoline, where N is a
42 * number of bytes >= 5 that are instruction aligned.
44 * 2. Replace first 5 bytes of OrigFunction with a jump to the Hook
45 * function.
47 * 3. After N bytes of the trampoline, add a jump to OrigFunction+N to
48 * continue original program flow.
50 * 4. Hook function needs to call the trampoline during its execution,
51 * to invoke the original function (so address of trampoline is
52 * returned).
54 * When the WindowsDllDetourPatcher object is destructed, OrigFunction is
55 * patched again to jump directly to the trampoline instead of going through
56 * the hook function. As such, re-intercepting the same function won't work, as
57 * jump instructions are not supported.
59 * Note that this is not thread-safe. Sad day.
63 #include <stdint.h>
65 namespace mozilla {
66 namespace internal {
68 class WindowsDllNopSpacePatcher
70 typedef unsigned char* byteptr_t;
71 HMODULE mModule;
73 // Dumb array for remembering the addresses of functions we've patched.
74 // (This should be nsTArray, but non-XPCOM code uses this class.)
75 static const size_t maxPatchedFns = 128;
76 byteptr_t mPatchedFns[maxPatchedFns];
77 int mPatchedFnsLen;
79 public:
80 WindowsDllNopSpacePatcher()
81 : mModule(0)
82 , mPatchedFnsLen(0)
85 ~WindowsDllNopSpacePatcher()
87 // Restore the mov edi, edi to the beginning of each function we patched.
89 for (int i = 0; i < mPatchedFnsLen; i++) {
90 byteptr_t fn = mPatchedFns[i];
92 // Ensure we can write to the code.
93 DWORD op;
94 if (!VirtualProtectEx(GetCurrentProcess(), fn, 2, PAGE_EXECUTE_READWRITE, &op)) {
95 // printf("VirtualProtectEx failed! %d\n", GetLastError());
96 continue;
99 // mov edi, edi
100 *((uint16_t*)fn) = 0xff8b;
102 // Restore the old protection.
103 VirtualProtectEx(GetCurrentProcess(), fn, 2, op, &op);
105 // I don't think this is actually necessary, but it can't hurt.
106 FlushInstructionCache(GetCurrentProcess(),
107 /* ignored */ nullptr,
108 /* ignored */ 0);
112 void Init(const char* aModuleName)
114 mModule = LoadLibraryExA(aModuleName, nullptr, 0);
115 if (!mModule) {
116 //printf("LoadLibraryEx for '%s' failed\n", aModuleName);
117 return;
121 #if defined(_M_IX86)
122 bool AddHook(const char* aName, intptr_t aHookDest, void** aOrigFunc)
124 if (!mModule) {
125 return false;
128 if (mPatchedFnsLen == maxPatchedFns) {
129 // printf ("No space for hook in mPatchedFns.\n");
130 return false;
133 byteptr_t fn = reinterpret_cast<byteptr_t>(GetProcAddress(mModule, aName));
134 if (!fn) {
135 //printf ("GetProcAddress failed\n");
136 return false;
139 fn = ResolveRedirectedAddress(fn);
141 // Ensure we can read and write starting at fn - 5 (for the long jmp we're
142 // going to write) and ending at fn + 2 (for the short jmp up to the long
143 // jmp).
144 DWORD op;
145 if (!VirtualProtectEx(GetCurrentProcess(), fn - 5, 7,
146 PAGE_EXECUTE_READWRITE, &op)) {
147 //printf ("VirtualProtectEx failed! %d\n", GetLastError());
148 return false;
151 bool rv = WriteHook(fn, aHookDest, aOrigFunc);
153 // Re-protect, and we're done.
154 VirtualProtectEx(GetCurrentProcess(), fn - 5, 7, op, &op);
156 if (rv) {
157 mPatchedFns[mPatchedFnsLen] = fn;
158 mPatchedFnsLen++;
161 return rv;
164 bool WriteHook(byteptr_t aFn, intptr_t aHookDest, void** aOrigFunc)
166 // Check that the 5 bytes before aFn are NOP's or INT 3's,
167 // and that the 2 bytes after aFn are mov(edi, edi).
169 // It's safe to read aFn[-5] because we set it to PAGE_EXECUTE_READWRITE
170 // before calling WriteHook.
172 for (int i = -5; i <= -1; i++) {
173 if (aFn[i] != 0x90 && aFn[i] != 0xcc) { // nop or int 3
174 return false;
178 // mov edi, edi. Yes, there are two ways to encode the same thing:
180 // 0x89ff == mov r/m, r
181 // 0x8bff == mov r, r/m
183 // where "r" is register and "r/m" is register or memory. Windows seems to
184 // use 8bff; I include 89ff out of paranoia.
185 if ((aFn[0] != 0x8b && aFn[0] != 0x89) || aFn[1] != 0xff) {
186 return false;
189 // Write a long jump into the space above the function.
190 aFn[-5] = 0xe9; // jmp
191 *((intptr_t*)(aFn - 4)) = aHookDest - (uintptr_t)(aFn); // target displacement
193 // Set aOrigFunc here, because after this point, aHookDest might be called,
194 // and aHookDest might use the aOrigFunc pointer.
195 *aOrigFunc = aFn + 2;
197 // Short jump up into our long jump.
198 *((uint16_t*)(aFn)) = 0xf9eb; // jmp $-5
200 // I think this routine is safe without this, but it can't hurt.
201 FlushInstructionCache(GetCurrentProcess(),
202 /* ignored */ nullptr,
203 /* ignored */ 0);
205 return true;
208 private:
209 static byteptr_t ResolveRedirectedAddress(const byteptr_t aOriginalFunction)
211 // If function entry is jmp [disp32] such as used by kernel32,
212 // we resolve redirected address from import table.
213 if (aOriginalFunction[0] == 0xff && aOriginalFunction[1] == 0x25) {
214 return (byteptr_t)(**((uint32_t**) (aOriginalFunction + 2)));
217 return aOriginalFunction;
219 #else
220 bool AddHook(const char* aName, intptr_t aHookDest, void** aOrigFunc)
222 // Not implemented except on x86-32.
223 return false;
225 #endif
228 class WindowsDllDetourPatcher
230 typedef unsigned char* byteptr_t;
231 public:
232 WindowsDllDetourPatcher()
233 : mModule(0), mHookPage(0), mMaxHooks(0), mCurHooks(0)
237 ~WindowsDllDetourPatcher()
239 int i;
240 byteptr_t p;
241 for (i = 0, p = mHookPage; i < mCurHooks; i++, p += kHookSize) {
242 #if defined(_M_IX86)
243 size_t nBytes = 1 + sizeof(intptr_t);
244 #elif defined(_M_X64)
245 size_t nBytes = 2 + sizeof(intptr_t);
246 #else
247 #error "Unknown processor type"
248 #endif
249 byteptr_t origBytes = (byteptr_t)DecodePointer(*((byteptr_t*)p));
250 // ensure we can modify the original code
251 DWORD op;
252 if (!VirtualProtectEx(GetCurrentProcess(), origBytes, nBytes,
253 PAGE_EXECUTE_READWRITE, &op)) {
254 continue;
256 // Remove the hook by making the original function jump directly
257 // in the trampoline.
258 intptr_t dest = (intptr_t)(p + sizeof(void*));
259 #if defined(_M_IX86)
260 // Ensure the JMP from CreateTrampoline is where we expect it to be.
261 if (origBytes[0] != 0xE9)
262 continue;
263 *((intptr_t*)(origBytes + 1)) =
264 dest - (intptr_t)(origBytes + 5); // target displacement
265 #elif defined(_M_X64)
266 // Ensure the MOV R11 from CreateTrampoline is where we expect it to be.
267 if (origBytes[0] != 0x49 || origBytes[1] != 0xBB)
268 continue;
269 *((intptr_t*)(origBytes + 2)) = dest;
270 #else
271 #error "Unknown processor type"
272 #endif
273 // restore protection; if this fails we can't really do anything about it
274 VirtualProtectEx(GetCurrentProcess(), origBytes, nBytes, op, &op);
278 void Init(const char* aModuleName, int aNumHooks = 0)
280 if (mModule) {
281 return;
284 mModule = LoadLibraryExA(aModuleName, nullptr, 0);
285 if (!mModule) {
286 //printf("LoadLibraryEx for '%s' failed\n", aModuleName);
287 return;
290 int hooksPerPage = 4096 / kHookSize;
291 if (aNumHooks == 0) {
292 aNumHooks = hooksPerPage;
295 mMaxHooks = aNumHooks + (hooksPerPage % aNumHooks);
297 mHookPage = (byteptr_t)VirtualAllocEx(GetCurrentProcess(), nullptr,
298 mMaxHooks * kHookSize,
299 MEM_COMMIT | MEM_RESERVE,
300 PAGE_EXECUTE_READWRITE);
301 if (!mHookPage) {
302 mModule = 0;
303 return;
307 bool Initialized() { return !!mModule; }
309 void LockHooks()
311 if (!mModule) {
312 return;
315 DWORD op;
316 VirtualProtectEx(GetCurrentProcess(), mHookPage, mMaxHooks * kHookSize,
317 PAGE_EXECUTE_READ, &op);
319 mModule = 0;
322 bool AddHook(const char* aName, intptr_t aHookDest, void** aOrigFunc)
324 if (!mModule) {
325 return false;
328 void* pAddr = (void*)GetProcAddress(mModule, aName);
329 if (!pAddr) {
330 //printf ("GetProcAddress failed\n");
331 return false;
334 pAddr = ResolveRedirectedAddress((byteptr_t)pAddr);
336 CreateTrampoline(pAddr, aHookDest, aOrigFunc);
337 if (!*aOrigFunc) {
338 //printf ("CreateTrampoline failed\n");
339 return false;
342 return true;
345 protected:
346 const static int kPageSize = 4096;
347 const static int kHookSize = 128;
349 HMODULE mModule;
350 byteptr_t mHookPage;
351 int mMaxHooks;
352 int mCurHooks;
354 void CreateTrampoline(void* aOrigFunction, intptr_t aDest, void** aOutTramp)
356 *aOutTramp = nullptr;
358 byteptr_t tramp = FindTrampolineSpace();
359 if (!tramp) {
360 return;
363 byteptr_t origBytes = (byteptr_t)aOrigFunction;
365 int nBytes = 0;
366 int pJmp32 = -1;
368 #if defined(_M_IX86)
369 while (nBytes < 5) {
370 // Understand some simple instructions that might be found in a
371 // prologue; we might need to extend this as necessary.
373 // Note! If we ever need to understand jump instructions, we'll
374 // need to rewrite the displacement argument.
375 if (origBytes[nBytes] >= 0x88 && origBytes[nBytes] <= 0x8B) {
376 // various MOVs
377 unsigned char b = origBytes[nBytes + 1];
378 if (((b & 0xc0) == 0xc0) ||
379 (((b & 0xc0) == 0x00) &&
380 ((b & 0x07) != 0x04) && ((b & 0x07) != 0x05))) {
381 // REG=r, R/M=r or REG=r, R/M=[r]
382 nBytes += 2;
383 } else if ((b & 0xc0) == 0x40) {
384 if ((b & 0x07) == 0x04) {
385 // REG=r, R/M=[SIB + disp8]
386 nBytes += 4;
387 } else {
388 // REG=r, R/M=[r + disp8]
389 nBytes += 3;
391 } else {
392 // complex MOV, bail
393 return;
395 } else if (origBytes[nBytes] == 0xB8) {
396 // MOV 0xB8: http://ref.x86asm.net/coder32.html#xB8
397 nBytes += 5;
398 } else if (origBytes[nBytes] == 0x83) {
399 // ADD|ODR|ADC|SBB|AND|SUB|XOR|CMP r/m, imm8
400 unsigned char b = origBytes[nBytes + 1];
401 if ((b & 0xc0) == 0xc0) {
402 // ADD|ODR|ADC|SBB|AND|SUB|XOR|CMP r, imm8
403 nBytes += 3;
404 } else {
405 // bail
406 return;
408 } else if (origBytes[nBytes] == 0x68) {
409 // PUSH with 4-byte operand
410 nBytes += 5;
411 } else if ((origBytes[nBytes] & 0xf0) == 0x50) {
412 // 1-byte PUSH/POP
413 nBytes++;
414 } else if (origBytes[nBytes] == 0x6A) {
415 // PUSH imm8
416 nBytes += 2;
417 } else if (origBytes[nBytes] == 0xe9) {
418 pJmp32 = nBytes;
419 // jmp 32bit offset
420 nBytes += 5;
421 } else if (origBytes[nBytes] == 0xff && origBytes[nBytes + 1] == 0x25) {
422 // jmp [disp32]
423 nBytes += 6;
424 } else {
425 //printf ("Unknown x86 instruction byte 0x%02x, aborting trampoline\n", origBytes[nBytes]);
426 return;
429 #elif defined(_M_X64)
430 byteptr_t directJmpAddr;
432 while (nBytes < 13) {
434 // if found JMP 32bit offset, next bytes must be NOP
435 if (pJmp32 >= 0) {
436 if (origBytes[nBytes++] != 0x90) {
437 return;
440 continue;
442 if (origBytes[nBytes] == 0x0f) {
443 nBytes++;
444 if (origBytes[nBytes] == 0x1f) {
445 // nop (multibyte)
446 nBytes++;
447 if ((origBytes[nBytes] & 0xc0) == 0x40 &&
448 (origBytes[nBytes] & 0x7) == 0x04) {
449 nBytes += 3;
450 } else {
451 return;
453 } else if (origBytes[nBytes] == 0x05) {
454 // syscall
455 nBytes++;
456 } else {
457 return;
459 } else if (origBytes[nBytes] == 0x40 ||
460 origBytes[nBytes] == 0x41) {
461 // Plain REX or REX.B
462 nBytes++;
464 if ((origBytes[nBytes] & 0xf0) == 0x50) {
465 // push/pop with Rx register
466 nBytes++;
467 } else if (origBytes[nBytes] >= 0xb8 && origBytes[nBytes] <= 0xbf) {
468 // mov r32, imm32
469 nBytes += 5;
470 } else {
471 return;
473 } else if (origBytes[nBytes] == 0x45) {
474 // REX.R & REX.B
475 nBytes++;
477 if (origBytes[nBytes] == 0x33) {
478 // xor r32, r32
479 nBytes += 2;
480 } else {
481 return;
483 } else if ((origBytes[nBytes] & 0xfb) == 0x48) {
484 // REX.W | REX.WR
485 nBytes++;
487 if (origBytes[nBytes] == 0x81 &&
488 (origBytes[nBytes + 1] & 0xf8) == 0xe8) {
489 // sub r, dword
490 nBytes += 6;
491 } else if (origBytes[nBytes] == 0x83 &&
492 (origBytes[nBytes + 1] & 0xf8) == 0xe8) {
493 // sub r, byte
494 nBytes += 3;
495 } else if (origBytes[nBytes] == 0x83 &&
496 (origBytes[nBytes + 1] & 0xf8) == 0x60) {
497 // and [r+d], imm8
498 nBytes += 5;
499 } else if ((origBytes[nBytes] & 0xfd) == 0x89) {
500 // MOV r/m64, r64 | MOV r64, r/m64
501 if ((origBytes[nBytes + 1] & 0xc0) == 0x40) {
502 if ((origBytes[nBytes + 1] & 0x7) == 0x04) {
503 // R/M=[SIB+disp8], REG=r64
504 nBytes += 4;
505 } else {
506 // R/M=[r64+disp8], REG=r64
507 nBytes += 3;
509 } else if (((origBytes[nBytes + 1] & 0xc0) == 0xc0) ||
510 (((origBytes[nBytes + 1] & 0xc0) == 0x00) &&
511 ((origBytes[nBytes + 1] & 0x07) != 0x04) &&
512 ((origBytes[nBytes + 1] & 0x07) != 0x05))) {
513 // REG=r64, R/M=r64 or REG=r64, R/M=[r64]
514 nBytes += 2;
515 } else {
516 // complex MOV
517 return;
519 } else if (origBytes[nBytes] == 0xc7) {
520 // MOV r/m64, imm32
521 if (origBytes[nBytes + 1] == 0x44) {
522 // MOV [r64+disp8], imm32
523 // ModR/W + SIB + disp8 + imm32
524 nBytes += 8;
525 } else {
526 return;
528 } else if (origBytes[nBytes] == 0xff) {
529 pJmp32 = nBytes - 1;
530 // JMP /4
531 if ((origBytes[nBytes + 1] & 0xc0) == 0x0 &&
532 (origBytes[nBytes + 1] & 0x07) == 0x5) {
533 // [rip+disp32]
534 // convert JMP 32bit offset to JMP 64bit direct
535 directJmpAddr =
536 (byteptr_t)*((uint64_t*)(origBytes + nBytes + 6 +
537 (*((int32_t*)(origBytes + nBytes + 2)))));
538 nBytes += 6;
539 } else {
540 // not support yet!
541 return;
543 } else {
544 // not support yet!
545 return;
547 } else if ((origBytes[nBytes] & 0xf0) == 0x50) {
548 // 1-byte push/pop
549 nBytes++;
550 } else if (origBytes[nBytes] == 0x90) {
551 // nop
552 nBytes++;
553 } else if (origBytes[nBytes] == 0xb8) {
554 // MOV 0xB8: http://ref.x86asm.net/coder32.html#xB8
555 nBytes += 5;
556 } else if (origBytes[nBytes] == 0xc3) {
557 // ret
558 nBytes++;
559 } else if (origBytes[nBytes] == 0xe9) {
560 pJmp32 = nBytes;
561 // convert JMP 32bit offset to JMP 64bit direct
562 directJmpAddr = origBytes + pJmp32 + 5 + (*((int32_t*)(origBytes + pJmp32 + 1)));
563 // jmp 32bit offset
564 nBytes += 5;
565 } else if (origBytes[nBytes] == 0xff) {
566 nBytes++;
567 if ((origBytes[nBytes] & 0xf8) == 0xf0) {
568 // push r64
569 nBytes++;
570 } else {
571 return;
573 } else {
574 return;
577 #else
578 #error "Unknown processor type"
579 #endif
581 if (nBytes > 100) {
582 //printf ("Too big!");
583 return;
586 // We keep the address of the original function in the first bytes of
587 // the trampoline buffer
588 *((void**)tramp) = EncodePointer(aOrigFunction);
589 tramp += sizeof(void*);
591 memcpy(tramp, aOrigFunction, nBytes);
593 // OrigFunction+N, the target of the trampoline
594 byteptr_t trampDest = origBytes + nBytes;
596 #if defined(_M_IX86)
597 if (pJmp32 >= 0) {
598 // Jump directly to the original target of the jump instead of jumping to the
599 // original function.
600 // Adjust jump target displacement to jump location in the trampoline.
601 *((intptr_t*)(tramp + pJmp32 + 1)) += origBytes - tramp;
602 } else {
603 tramp[nBytes] = 0xE9; // jmp
604 *((intptr_t*)(tramp + nBytes + 1)) =
605 (intptr_t)trampDest - (intptr_t)(tramp + nBytes + 5); // target displacement
607 #elif defined(_M_X64)
608 // If JMP32 opcode found, we don't insert to trampoline jump
609 if (pJmp32 >= 0) {
610 // mov r11, address
611 tramp[pJmp32] = 0x49;
612 tramp[pJmp32 + 1] = 0xbb;
613 *((intptr_t*)(tramp + pJmp32 + 2)) = (intptr_t)directJmpAddr;
615 // jmp r11
616 tramp[pJmp32 + 10] = 0x41;
617 tramp[pJmp32 + 11] = 0xff;
618 tramp[pJmp32 + 12] = 0xe3;
619 } else {
620 // mov r11, address
621 tramp[nBytes] = 0x49;
622 tramp[nBytes + 1] = 0xbb;
623 *((intptr_t*)(tramp + nBytes + 2)) = (intptr_t)trampDest;
625 // jmp r11
626 tramp[nBytes + 10] = 0x41;
627 tramp[nBytes + 11] = 0xff;
628 tramp[nBytes + 12] = 0xe3;
630 #endif
632 // The trampoline is now valid.
633 *aOutTramp = tramp;
635 // ensure we can modify the original code
636 DWORD op;
637 if (!VirtualProtectEx(GetCurrentProcess(), aOrigFunction, nBytes,
638 PAGE_EXECUTE_READWRITE, &op)) {
639 //printf ("VirtualProtectEx failed! %d\n", GetLastError());
640 return;
643 #if defined(_M_IX86)
644 // now modify the original bytes
645 origBytes[0] = 0xE9; // jmp
646 *((intptr_t*)(origBytes + 1)) =
647 aDest - (intptr_t)(origBytes + 5); // target displacement
648 #elif defined(_M_X64)
649 // mov r11, address
650 origBytes[0] = 0x49;
651 origBytes[1] = 0xbb;
653 *((intptr_t*)(origBytes + 2)) = aDest;
655 // jmp r11
656 origBytes[10] = 0x41;
657 origBytes[11] = 0xff;
658 origBytes[12] = 0xe3;
659 #endif
661 // restore protection; if this fails we can't really do anything about it
662 VirtualProtectEx(GetCurrentProcess(), aOrigFunction, nBytes, op, &op);
665 byteptr_t FindTrampolineSpace()
667 if (mCurHooks >= mMaxHooks) {
668 return 0;
671 byteptr_t p = mHookPage + mCurHooks * kHookSize;
673 mCurHooks++;
675 return p;
678 static void* ResolveRedirectedAddress(const byteptr_t aOriginalFunction)
680 #if defined(_M_IX86)
681 // If function entry is jmp [disp32] such as used by kernel32,
682 // we resolve redirected address from import table.
683 if (aOriginalFunction[0] == 0xff && aOriginalFunction[1] == 0x25) {
684 return (void*)(**((uint32_t**) (aOriginalFunction + 2)));
686 #elif defined(_M_X64)
687 if (aOriginalFunction[0] == 0xe9) {
688 // require for TestDllInterceptor with --disable-optimize
689 int32_t offset = *((int32_t*)(aOriginalFunction + 1));
690 return aOriginalFunction + 5 + offset;
692 #endif
694 return aOriginalFunction;
698 } // namespace internal
700 class WindowsDllInterceptor
702 internal::WindowsDllNopSpacePatcher mNopSpacePatcher;
703 internal::WindowsDllDetourPatcher mDetourPatcher;
705 const char* mModuleName;
706 int mNHooks;
708 public:
709 WindowsDllInterceptor()
710 : mModuleName(nullptr)
711 , mNHooks(0)
714 void Init(const char* aModuleName, int aNumHooks = 0)
716 if (mModuleName) {
717 return;
720 mModuleName = aModuleName;
721 mNHooks = aNumHooks;
722 mNopSpacePatcher.Init(aModuleName);
724 // Lazily initialize mDetourPatcher, since it allocates memory and we might
725 // not need it.
728 void LockHooks()
730 if (mDetourPatcher.Initialized()) {
731 mDetourPatcher.LockHooks();
735 bool AddHook(const char* aName, intptr_t aHookDest, void** aOrigFunc)
737 // Use a nop space patch if possible, otherwise fall back to a detour.
738 // This should be the preferred method for adding hooks.
740 if (!mModuleName) {
741 return false;
744 if (mNopSpacePatcher.AddHook(aName, aHookDest, aOrigFunc)) {
745 return true;
748 return AddDetour(aName, aHookDest, aOrigFunc);
751 bool AddDetour(const char* aName, intptr_t aHookDest, void** aOrigFunc)
753 // Generally, code should not call this method directly. Use AddHook unless
754 // there is a specific need to avoid nop space patches.
756 if (!mModuleName) {
757 return false;
760 if (!mDetourPatcher.Initialized()) {
761 mDetourPatcher.Init(mModuleName, mNHooks);
764 return mDetourPatcher.AddHook(aName, aHookDest, aOrigFunc);
768 } // namespace mozilla
770 #endif /* NS_WINDOWS_DLL_INTERCEPTOR_H_ */