summaryrefslogtreecommitdiffhomepage
path: root/src/hook.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hook.c')
-rw-r--r--src/hook.c45
1 files changed, 20 insertions, 25 deletions
diff --git a/src/hook.c b/src/hook.c
index 3d6c14d..ba02461 100644
--- a/src/hook.c
+++ b/src/hook.c
@@ -27,8 +27,6 @@
// Almost certainly breaks in some weird cases. Oh well! Most of the time,
// vtable hooking is more reliable, this is only for, uh, emergencies.
-#if defined(_WIN32) && !defined(_WIN64)
-
#if defined(__GNUC__) || defined(__clang__)
__attribute__((aligned(4096)))
#elif defined(_MSC_VER)
@@ -45,6 +43,18 @@ bool hook_init(void) {
return os_mprot(trampolines, sizeof(trampolines), PAGE_EXECUTE_READWRITE);
}
+static inline void iflush(void *p, int len) {
+#if defined(_WIN32)
+ // -1 is the current process, and it's a constant in the WDK, so it's
+ // assumed we can safely avoid the useless GetCurrentProcess call
+ FlushInstructionCache((void *)-1, p, len);
+#elif defined(__GNUC__)
+ __builtin___clear_cache((char *)p, (char *)p + len);
+#else
+#error no way to flush instruction cache
+#endif
+}
+
void *hook_inline(void *func_, void *target) {
uchar *func = func_;
// dumb hack: if we hit some thunk that immediately jumps elsewhere (which
@@ -74,30 +84,21 @@ void *hook_inline(void *func_, void *target) {
}
}
// for simplicity, just bump alloc the trampoline. no need to free anyway
- if (nexttrampoline - trampolines > sizeof(trampolines) - len - 6) goto nosp;
- // TODO(opt): stop pretending to be thread-safe, it's just slowing us down
- uchar *trampoline = (uchar *)InterlockedExchangeAdd(
- (volatile long *)&nexttrampoline, len + 6);
- // avoid TOCTOU
- if (trampoline - trampolines > sizeof(trampolines) - len - 6) {
-nosp: con_warn("hook_inline: out of trampoline space\n");
+ if (nexttrampoline - trampolines > sizeof(trampolines) - len - 6) {
+ con_warn("hook_inline: out of trampoline space\n");
return 0;
}
+ uchar *trampoline = nexttrampoline;
+ nexttrampoline += len + 6; // NOT thread-safe. we don't need that anyway!
*trampoline++ = len; // stick length in front for quicker unhooking
memcpy(trampoline, func, len);
trampoline[len] = X86_JMPIW;
uint diff = func - (trampoline + 5); // goto the continuation
memcpy(trampoline + len + 1, &diff, 4);
- uchar jmp[8];
- jmp[0] = X86_JMPIW;
diff = (uchar *)target - (func + 5); // goto the hook target
- memcpy(jmp + 1, &diff, 4);
- // pad with original bytes so we can do an 8-byte atomic write
- memcpy(jmp + 5, func + 5, 3);
- *(volatile uvlong *)func = *(uvlong *)jmp; // (assuming function is aligned)
- // -1 is the current process, and it's a constant in the WDK, so it's
- // assumed we can safely avoid the useless GetCurrentProcess call
- FlushInstructionCache((void *)-1, func, len);
+ func[0] = X86_JMPIW;
+ memcpy(func + 1, &diff, 4);
+ iflush(func, 5);
return trampoline;
}
@@ -107,13 +108,7 @@ void unhook_inline(void *orig) {
int off = mem_load32(p + len + 1);
uchar *q = p + off + 5;
memcpy(q, p, 5); // XXX: not atomic atm! (does any of it even need to be?)
- FlushInstructionCache((void *)-1, q, 5);
+ iflush(q, 5);
}
-#else
-
-// TODO(linux): Implement for Linux and/or x86_64 when needed...
-
-#endif
-
// vi: sw=4 ts=4 noet tw=80 cc=80