diff options
Diffstat (limited to '')
| -rw-r--r-- | src/hooks.cpp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/hooks.cpp b/src/hooks.cpp new file mode 100644 index 0000000..215ecfd --- /dev/null +++ b/src/hooks.cpp | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // hooks.cpp — vtable hook installation and teardown bookkeeping. | ||
| 2 | #include "hl2h.h" | ||
| 3 | |||
| 4 | #include <mutex> | ||
| 5 | #include <vector> | ||
| 6 | |||
| 7 | namespace { | ||
| 8 | |||
| 9 | struct Installed { | ||
| 10 | void *iface; | ||
| 11 | void **old_vt; | ||
| 12 | }; | ||
| 13 | |||
| 14 | std::mutex g_hook_mu; | ||
| 15 | std::vector<Installed> g_installed; | ||
| 16 | |||
| 17 | } // namespace | ||
| 18 | |||
| 19 | bool hooks_install_vtable(void *iface, size_t slots, const VtablePatch *patches, | ||
| 20 | int count) { | ||
| 21 | if (!iface || !patches || count <= 0) | ||
| 22 | return false; | ||
| 23 | void **old = *(void ***)iface; | ||
| 24 | if (!old) | ||
| 25 | return false; | ||
| 26 | for (int i = 0; i < count; i++) { | ||
| 27 | if (patches[i].slot < 0 || (size_t)patches[i].slot >= slots) { | ||
| 28 | logf("hooks: slot %d out of range (table has %u)", patches[i].slot, | ||
| 29 | (unsigned)slots); | ||
| 30 | return false; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | void **clone = vtable_clone(iface, slots); | ||
| 35 | if (!clone) | ||
| 36 | return false; | ||
| 37 | for (int i = 0; i < count; i++) { | ||
| 38 | if (patches[i].original) | ||
| 39 | *patches[i].original = old[patches[i].slot]; | ||
| 40 | clone[patches[i].slot] = patches[i].replacement; | ||
| 41 | } | ||
| 42 | |||
| 43 | std::lock_guard<std::mutex> lock(g_hook_mu); | ||
| 44 | *(void ***)iface = clone; | ||
| 45 | g_installed.push_back({iface, old}); | ||
| 46 | return true; | ||
| 47 | } | ||
| 48 | |||
| 49 | void hooks_restore_all() { | ||
| 50 | std::lock_guard<std::mutex> lock(g_hook_mu); | ||
| 51 | for (auto it = g_installed.rbegin(); it != g_installed.rend(); ++it) | ||
| 52 | *(void ***)it->iface = it->old_vt; | ||
| 53 | g_installed.clear(); | ||
| 54 | } | ||
| 55 | |||
| 56 | int hooks_installed_count() { | ||
| 57 | std::lock_guard<std::mutex> lock(g_hook_mu); | ||
| 58 | return (int)g_installed.size(); | ||
| 59 | } | ||
