Reintroduce hook_del(Hook), since it seems useful.

This also improves backwards compatibility a bit.
This commit is contained in:
Robert Xiao 2023-05-12 22:43:46 -07:00
parent e787f49d21
commit 48870c4cc3
2 changed files with 85 additions and 21 deletions

View File

@ -1,15 +1,18 @@
package tests; package tests;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import org.junit.Test; import org.junit.Test;
import unicorn.CodeHook;
import unicorn.MemRegion; import unicorn.MemRegion;
import unicorn.TlbFillHook; import unicorn.TlbFillHook;
import unicorn.Unicorn; import unicorn.Unicorn;
import unicorn.UnicornException;
import unicorn.X86_Float80; import unicorn.X86_Float80;
public class FunctionalityTests { public class FunctionalityTests {
@ -181,4 +184,44 @@ public class FunctionalityTests {
assertEquals(Math.sin(-1.1), reg.toDouble(), 1e-12); assertEquals(Math.sin(-1.1), reg.toDouble(), 1e-12);
u.close(); u.close();
} }
@Test
public void testRemoveHook() {
byte[] X86_CODE = { 0x40, 0x40, 0x40, 0x40 }; // (inc eax) x 4
int ADDRESS = 0x10000;
final int[] hook_accum = { 0 };
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
u.mem_write(ADDRESS, X86_CODE);
CodeHook hook =
(uc, address, size, user) -> hook_accum[0] += (int) user;
long h1 = u.hook_add(hook, ADDRESS, ADDRESS, 1);
long h2 = u.hook_add(hook, ADDRESS + 1, ADDRESS + 1, 2);
long h3 = u.hook_add(hook, ADDRESS + 2, ADDRESS + 2, 4);
long h4 = u.hook_add(hook, ADDRESS + 3, ADDRESS + 3, 8);
hook_accum[0] = 0;
u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0);
assertEquals(15, hook_accum[0]);
u.hook_del(h2);
hook_accum[0] = 0;
u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0);
assertEquals(13, hook_accum[0]);
u.hook_del(hook);
hook_accum[0] = 0;
u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0);
assertEquals(0, hook_accum[0]);
assertThrows(UnicornException.class, () -> u.hook_del(h1));
assertThrows(UnicornException.class, () -> u.hook_del(h3));
assertThrows(UnicornException.class, () -> u.hook_del(h4));
u.close();
}
} }

View File

@ -52,7 +52,8 @@ public class Unicorn
/** Wrapper around a registered hook */ /** Wrapper around a registered hook */
private static class HookWrapper { private static class HookWrapper {
private long nativePtr; Hook hook;
long nativePtr;
@Override @Override
protected void finalize() { protected void finalize() {
@ -685,8 +686,9 @@ public class Unicorn
_ctl_tlb_mode(nativePtr, mode); _ctl_tlb_mode(nativePtr, mode);
} }
private long registerHook(long val) { private long registerHook(Hook hook, long val) {
HookWrapper wrapper = new HookWrapper(); HookWrapper wrapper = new HookWrapper();
wrapper.hook = hook;
wrapper.nativePtr = val; wrapper.nativePtr = val;
long index = nextAllocCounter(); long index = nextAllocCounter();
hooks.put(index, wrapper); hooks.put(index, wrapper);
@ -705,7 +707,7 @@ public class Unicorn
*/ */
public long hook_add(InterruptHook callback, Object user_data) public long hook_add(InterruptHook callback, Object user_data)
throws UnicornException { throws UnicornException {
return registerHook( return registerHook(callback,
_hook_add(nativePtr, UC_HOOK_INTR, callback, user_data, 1, 0)); _hook_add(nativePtr, UC_HOOK_INTR, callback, user_data, 1, 0));
} }
@ -728,8 +730,8 @@ public class Unicorn
long end, long end,
Object user_data) Object user_data)
throws UnicornException { throws UnicornException {
return registerHook(_hook_add(nativePtr, UC_HOOK_INSN, callback, return registerHook(callback, _hook_add(nativePtr, UC_HOOK_INSN,
user_data, begin, end, insn)); callback, user_data, begin, end, insn));
} }
/** /**
@ -811,8 +813,8 @@ public class Unicorn
public long hook_add(CodeHook callback, long begin, long end, public long hook_add(CodeHook callback, long begin, long end,
Object user_data) Object user_data)
throws UnicornException { throws UnicornException {
return registerHook(_hook_add(nativePtr, UC_HOOK_CODE, callback, return registerHook(callback, _hook_add(nativePtr, UC_HOOK_CODE,
user_data, begin, end)); callback, user_data, begin, end));
} }
/** /**
@ -833,8 +835,8 @@ public class Unicorn
public long hook_add(BlockHook callback, long begin, long end, public long hook_add(BlockHook callback, long begin, long end,
Object user_data) Object user_data)
throws UnicornException { throws UnicornException {
return registerHook(_hook_add(nativePtr, UC_HOOK_BLOCK, callback, return registerHook(callback, _hook_add(nativePtr, UC_HOOK_BLOCK,
user_data, begin, end)); callback, user_data, begin, end));
} }
/** /**
@ -859,7 +861,7 @@ public class Unicorn
public long hook_add(MemHook callback, int type, long begin, long end, public long hook_add(MemHook callback, int type, long begin, long end,
Object user_data) Object user_data)
throws UnicornException { throws UnicornException {
return registerHook( return registerHook(callback,
_hook_add(nativePtr, type, callback, user_data, begin, end)); _hook_add(nativePtr, type, callback, user_data, begin, end));
} }
@ -884,7 +886,7 @@ public class Unicorn
public long hook_add(EventMemHook callback, int type, long begin, long end, public long hook_add(EventMemHook callback, int type, long begin, long end,
Object user_data) Object user_data)
throws UnicornException { throws UnicornException {
return registerHook( return registerHook(callback,
_hook_add(nativePtr, type, callback, user_data, begin, end)); _hook_add(nativePtr, type, callback, user_data, begin, end));
} }
@ -902,7 +904,7 @@ public class Unicorn
*/ */
public long hook_add(EventMemHook callback, int type, Object user_data) public long hook_add(EventMemHook callback, int type, Object user_data)
throws UnicornException { throws UnicornException {
return registerHook( return registerHook(callback,
_hook_add(nativePtr, type, callback, user_data, 1, 0)); _hook_add(nativePtr, type, callback, user_data, 1, 0));
} }
@ -919,8 +921,8 @@ public class Unicorn
*/ */
public long hook_add(InvalidInstructionHook callback, public long hook_add(InvalidInstructionHook callback,
Object user_data) { Object user_data) {
return registerHook(_hook_add(nativePtr, UC_HOOK_INSN_INVALID, callback, return registerHook(callback, _hook_add(nativePtr, UC_HOOK_INSN_INVALID,
user_data, 1, 0)); callback, user_data, 1, 0));
} }
/** /**
@ -941,8 +943,8 @@ public class Unicorn
public long hook_add(EdgeGeneratedHook callback, long begin, long end, public long hook_add(EdgeGeneratedHook callback, long begin, long end,
Object user_data) Object user_data)
throws UnicornException { throws UnicornException {
return registerHook(_hook_add(nativePtr, UC_HOOK_EDGE_GENERATED, return registerHook(callback, _hook_add(nativePtr,
callback, user_data, begin, end)); UC_HOOK_EDGE_GENERATED, callback, user_data, begin, end));
} }
/** /**
@ -966,8 +968,8 @@ public class Unicorn
int opcode, int flags, int opcode, int flags,
Object user_data) Object user_data)
throws UnicornException { throws UnicornException {
return registerHook(_hook_add(nativePtr, UC_HOOK_TCG_OPCODE, callback, return registerHook(callback, _hook_add(nativePtr, UC_HOOK_TCG_OPCODE,
user_data, begin, end, opcode, flags)); callback, user_data, begin, end, opcode, flags));
} }
/** /**
@ -986,8 +988,8 @@ public class Unicorn
*/ */
public long hook_add(TlbFillHook callback, long begin, long end, public long hook_add(TlbFillHook callback, long begin, long end,
Object user_data) throws UnicornException { Object user_data) throws UnicornException {
return registerHook(_hook_add(nativePtr, UC_HOOK_TLB_FILL, callback, return registerHook(callback, _hook_add(nativePtr, UC_HOOK_TLB_FILL,
user_data, begin, end)); callback, user_data, begin, end));
} }
/** Remove a hook that was previously registered. /** Remove a hook that was previously registered.
@ -1003,6 +1005,25 @@ public class Unicorn
} }
} }
/** Remove all registrations for a given {@link Hook} object.
*
* @param hook A {@link Hook} object to unregister.
*/
public void hook_del(Hook hook) throws UnicornException {
if (hook == null) {
// we use null for "special" hooks that can't be _hook_del'd
throw new NullPointerException("hook must not be null");
}
Iterator<Map.Entry<Long, HookWrapper>> it = hooks.entrySet().iterator();
while (it.hasNext()) {
HookWrapper wrapper = it.next().getValue();
if (wrapper.hook == hook) {
it.remove();
_hook_del(nativePtr, wrapper.nativePtr);
}
}
}
/** /**
* Create a memory-mapped I/O range. * Create a memory-mapped I/O range.
* *
@ -1026,7 +1047,7 @@ public class Unicorn
long[] hooks = _mmio_map(nativePtr, address, size, read_cb, long[] hooks = _mmio_map(nativePtr, address, size, read_cb,
user_data_read, write_cb, user_data_write); user_data_read, write_cb, user_data_write);
for (long hook : hooks) { for (long hook : hooks) {
registerHook(hook); registerHook(null, hook);
} }
} }