Update Java samples to match C samples.
Also add all of the samples as Java tests, referencing the output of the C samples.
This commit is contained in:
159
bindings/java/samples/Sample_ctl.java
Normal file
159
bindings/java/samples/Sample_ctl.java
Normal file
@@ -0,0 +1,159 @@
|
||||
package samples;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import unicorn.*;
|
||||
|
||||
public class Sample_ctl implements UnicornConst, X86Const {
|
||||
/** Code to be emulated
|
||||
* <pre>
|
||||
* cmp eax, 0;
|
||||
* jg lb;
|
||||
* inc eax;
|
||||
* nop;
|
||||
* lb:
|
||||
* inc ebx;
|
||||
* nop;
|
||||
* </pre>
|
||||
*/
|
||||
private static final byte[] X86_JUMP_CODE =
|
||||
Utils.hexToBytes("83f8007f0240904390");
|
||||
|
||||
/** memory address where emulation starts */
|
||||
private static final long ADDRESS = 0x10000;
|
||||
|
||||
public static void test_uc_ctl_read() {
|
||||
System.out.println("Reading some properties by uc_ctl.");
|
||||
|
||||
// Initialize emulator in X86-32bit mode
|
||||
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
|
||||
|
||||
// Let's query some properties by uc_ctl.
|
||||
int mode = uc.ctl_get_mode();
|
||||
int arch = uc.ctl_get_arch();
|
||||
long timeout = uc.ctl_get_timeout();
|
||||
int pagesize = uc.ctl_get_page_size();
|
||||
|
||||
System.out.format(">>> mode = %d, arch = %d, timeout=%d, pagesize=%d\n",
|
||||
mode, arch, timeout, pagesize);
|
||||
}
|
||||
|
||||
private static final EdgeGeneratedHook trace_new_edge =
|
||||
(uc, cur, prev, data) -> {
|
||||
System.out.format(">>> Getting a new edge from 0x%x to 0x%x.\n",
|
||||
prev.pc + prev.size - 1, cur.pc);
|
||||
};
|
||||
|
||||
public static void test_uc_ctl_exits() {
|
||||
long r_eax, r_ebx;
|
||||
long exits[] = { ADDRESS + 6, ADDRESS + 8 };
|
||||
|
||||
System.out.println("Using multiple exits by uc_ctl.");
|
||||
|
||||
// Initialize emulator in X86-32bit mode
|
||||
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
|
||||
|
||||
uc.mem_map(ADDRESS, 0x1000, UC_PROT_ALL);
|
||||
|
||||
// Write our code to the memory.
|
||||
uc.mem_write(ADDRESS, X86_JUMP_CODE);
|
||||
|
||||
// We trace if any new edge is generated.
|
||||
uc.hook_add(trace_new_edge, 1, 0, null);
|
||||
|
||||
// Enable multiple exits.
|
||||
uc.ctl_exits_enabled(true);
|
||||
uc.ctl_set_exits(exits);
|
||||
|
||||
// This should stop at ADDRESS + 6 and increase eax, even thouhg we don't
|
||||
// provide an exit.
|
||||
uc.emu_start(ADDRESS, 0, 0, 0);
|
||||
|
||||
r_eax = uc.reg_read(UC_X86_REG_EAX);
|
||||
r_ebx = uc.reg_read(UC_X86_REG_EBX);
|
||||
System.out.format(
|
||||
">>> eax = %d and ebx = %d after the first emulation\n",
|
||||
r_eax, r_ebx);
|
||||
|
||||
// This should stop at ADDRESS + 8, even though we don't provide an exit.
|
||||
uc.emu_start(ADDRESS, 0, 0, 0);
|
||||
|
||||
r_eax = uc.reg_read(UC_X86_REG_EAX);
|
||||
r_ebx = uc.reg_read(UC_X86_REG_EBX);
|
||||
System.out.format(
|
||||
">>> eax = %d and ebx = %d after the second emulation\n",
|
||||
r_eax, r_ebx);
|
||||
}
|
||||
|
||||
private static final int TB_COUNT = 8;
|
||||
private static final int TCG_MAX_INSNS = 512; // from tcg.h
|
||||
private static final int CODE_LEN = TB_COUNT * TCG_MAX_INSNS;
|
||||
|
||||
private static double time_emulation(Unicorn uc, long start, long end) {
|
||||
long t1 = System.nanoTime();
|
||||
uc.emu_start(start, end, 0, 0);
|
||||
long t2 = System.nanoTime();
|
||||
return (t2 - t1) / 1000000.0;
|
||||
}
|
||||
|
||||
public static void test_uc_ctl_tb_cache() {
|
||||
byte[] code = new byte[CODE_LEN];
|
||||
double standard, cached, evicted;
|
||||
|
||||
System.out.println(
|
||||
"Controlling the TB cache in a finer granularity by uc_ctl.");
|
||||
|
||||
// Fill the code buffer with NOP.
|
||||
Arrays.fill(code, (byte) 0x90);
|
||||
|
||||
// Initialize emulator in X86-32bit mode
|
||||
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
|
||||
|
||||
uc.mem_map(ADDRESS, 0x10000, UC_PROT_ALL);
|
||||
|
||||
// Write our code to the memory.
|
||||
uc.mem_write(ADDRESS, code);
|
||||
|
||||
// We trace if any new edge is generated.
|
||||
// Note: In this sample, there is only **one** basic block while muliple
|
||||
// translation blocks is generated due to QEMU tcg buffer limit. In this
|
||||
// case, we don't consider it as a new edge.
|
||||
uc.hook_add(trace_new_edge, 1, 0, null);
|
||||
|
||||
// Do emulation without any cache.
|
||||
standard = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN);
|
||||
|
||||
// Now we request cache for all TBs.
|
||||
for (int i = 0; i < TB_COUNT; i++) {
|
||||
TranslationBlock tb =
|
||||
uc.ctl_request_cache(ADDRESS + i * TCG_MAX_INSNS);
|
||||
System.out.format(
|
||||
">>> TB is cached at 0x%x which has %d instructions with %d bytes.\n",
|
||||
tb.pc, tb.icount, tb.size);
|
||||
}
|
||||
|
||||
// Do emulation with all TB cached.
|
||||
cached = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN);
|
||||
|
||||
// Now we clear cache for all TBs.
|
||||
for (int i = 0; i < TB_COUNT; i++) {
|
||||
uc.ctl_remove_cache(ADDRESS + i * TCG_MAX_INSNS,
|
||||
ADDRESS + i * TCG_MAX_INSNS + 1);
|
||||
}
|
||||
|
||||
// Do emulation with all TB cache evicted.
|
||||
evicted = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN);
|
||||
|
||||
System.out.format(
|
||||
">>> Run time: First time: %fms, Cached: %fms, Cache evicted: %fms\n",
|
||||
standard, cached, evicted);
|
||||
}
|
||||
|
||||
public static final void main(String[] args) {
|
||||
test_uc_ctl_read();
|
||||
System.out.println("====================");
|
||||
test_uc_ctl_exits();
|
||||
System.out.println("====================");
|
||||
test_uc_ctl_tb_cache();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user