mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-22 09:15:40 +00:00
Start moving examples in S files (#851)
* Move assembly to S files * more assembly files * osx compilation change * makefile mistake * add objcopy from crosstool * use gobjcopy on osx * start cmocka install cleanup * move wget to directory option * move back to cd * fix copy * First cut * free allocated memory * bad idea too much switching between python and c * add debug * cleanup bad size
This commit is contained in:
parent
7f116846c0
commit
da21bd0589
|
@ -1,8 +1,7 @@
|
|||
language: c
|
||||
sudo: false
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install cmocka; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install cmocka crosstool-ng; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./install-cmocka-linux.sh; fi
|
||||
script:
|
||||
- make && make -C bindings/go && make -C bindings/go test && make test
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#!/bin/sh
|
||||
set -ex
|
||||
#!/bin/sh -ex
|
||||
mkdir -p cmocka
|
||||
#wget https://cmocka.org/files/1.1/cmocka-1.1.0.tar.xz -O /tmp/cmocka-1.1.0.tar.xz
|
||||
wget --no-check-certificate http://cmocka.org/files/1.1/cmocka-1.1.0.tar.xz -O /tmp/cmocka-1.1.0.tar.xz
|
||||
tar -xf /tmp/cmocka-1.1.0.tar.xz -C /tmp
|
||||
cd cmocka && cmake -DUNIT_TESTING=On /tmp/cmocka-1.1.0 && make && make test
|
||||
wget --no-check-certificate https://cmocka.org/files/1.1/cmocka-1.1.1.tar.xz -P /tmp/
|
||||
tar -xf /tmp/cmocka-1.1.1.tar.xz -C /tmp
|
||||
cd cmocka && cmake -DUNIT_TESTING=On /tmp/cmocka-1.1.1 && make && make test
|
||||
# cmake builds an so instead of a dll in mingw/msys
|
||||
if [[ ! -z $MSYSTEM ]]; then
|
||||
cp src/cmocka.so src/cmocka.dll
|
||||
fi
|
||||
# cmocka does not include headers in build
|
||||
cp -R /tmp/cmocka-1.1.0/include/ .
|
||||
cp -R /tmp/cmocka-1.1.1/include/ .
|
||||
|
|
1
tests/unit/.gitignore
vendored
1
tests/unit/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
!*.c
|
||||
test_*
|
||||
*.bin
|
||||
|
|
|
@ -2,10 +2,15 @@ CFLAGS += -Wall -Werror -Wno-unused-function -g
|
|||
CFLAGS += -D__USE_MINGW_ANSI_STDIO=1
|
||||
CFLAGS += -L ../../ -I ../../include
|
||||
CFLAGS += -L ../../cmocka/src -I ../../cmocka/include
|
||||
ASFLAGS += --32
|
||||
OBJCOPY = objcopy
|
||||
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S), Linux)
|
||||
LDLIBS += -lrt -pthread
|
||||
else ifeq ($(UNAME_S), Darwin)
|
||||
OBJCOPY = gobjcopy
|
||||
ASFLAGS = -arch i386
|
||||
endif
|
||||
|
||||
LDLIBS += -lcmocka -lunicorn
|
||||
|
@ -20,17 +25,24 @@ LDFLAGS := -fsanitize=address ${LDFLAGS}
|
|||
endif
|
||||
|
||||
ALL_TESTS_SOURCES = $(wildcard *.c)
|
||||
TEST_ASSEMBLY = $(wildcard *.s)
|
||||
TEST_PROGS = $(TEST_ASSEMBLY:%.s=%.o)
|
||||
TEST_BINS = $(TEST_PROGS:%.o=%.bin)
|
||||
ALL_TESTS = $(ALL_TESTS_SOURCES:%.c=%)
|
||||
|
||||
.PHONY: all
|
||||
all: ${ALL_TESTS}
|
||||
all: ${TEST_BINS} ${ALL_TESTS}
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf ${ALL_TESTS}
|
||||
rm -rf ${TEST_BINS} ${ALL_TESTS}
|
||||
|
||||
%.bin: %.o
|
||||
${OBJCOPY} -O binary $^ $@
|
||||
hexdump -C $@
|
||||
|
||||
.PHONY: test
|
||||
test: ${ALL_TESTS}
|
||||
test: all
|
||||
${EXECUTE_VARS} ./test_sanity
|
||||
${EXECUTE_VARS} ./test_x86
|
||||
${EXECUTE_VARS} ./test_mem_map
|
||||
|
|
3
tests/unit/gdt_idx.s
Normal file
3
tests/unit/gdt_idx.s
Normal file
|
@ -0,0 +1,3 @@
|
|||
.text
|
||||
sidt (esp)
|
||||
sgdt (esp+6)
|
6
tests/unit/high_address.s
Normal file
6
tests/unit/high_address.s
Normal file
|
@ -0,0 +1,6 @@
|
|||
dec %eax
|
||||
mov (%eax), %eax
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
9
tests/unit/pc_change.s
Normal file
9
tests/unit/pc_change.s
Normal file
|
@ -0,0 +1,9 @@
|
|||
.text
|
||||
inc %ecx
|
||||
inc %ecx
|
||||
inc %ecx
|
||||
inc %ecx
|
||||
inc %ecx
|
||||
inc %ecx
|
||||
inc %edx
|
||||
inc %edx
|
90
tests/unit/tb_x86.s
Normal file
90
tests/unit/tb_x86.s
Normal file
|
@ -0,0 +1,90 @@
|
|||
mov %esp,%ecx
|
||||
fxch %st(5)
|
||||
fnstenv -0xc(%ecx)
|
||||
pop %ebp
|
||||
push %ebp
|
||||
pop %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
dec %ecx
|
||||
inc %ebx
|
||||
inc %ebx
|
||||
inc %ebx
|
||||
inc %ebx
|
||||
inc %ebx
|
||||
inc %ebx
|
||||
aaa
|
||||
push %ecx
|
||||
pop %edx
|
||||
push $0x41
|
||||
pop %eax
|
||||
push %eax
|
||||
xor %al,0x30(%ecx)
|
||||
inc %ecx
|
||||
imul $0x51,0x41(%ecx),%eax
|
||||
xor 0x42(%ecx),%al
|
||||
xor 0x42(%edx),%al
|
||||
xor %al,0x42(%edx)
|
||||
inc %ecx
|
||||
inc %edx
|
||||
pop %eax
|
||||
push %eax
|
||||
cmp %al,0x42(%ecx)
|
||||
jne .+0x4c
|
||||
dec %ecx
|
||||
push %ecx
|
||||
push %ecx
|
||||
push %ecx
|
||||
push %edx
|
||||
inc %edi
|
||||
xor 0x34(%edi),%eax
|
||||
push %ecx
|
||||
push %ebp
|
||||
push %ecx
|
||||
push %esi
|
||||
push %eax
|
||||
inc %edi
|
||||
inc %edi
|
||||
cmp %al,0x39(%edi)
|
||||
push %eax
|
||||
dec %edx
|
||||
push %eax
|
||||
dec %ebx
|
||||
push %eax
|
||||
dec %esp
|
||||
push %eax
|
||||
dec %ebp
|
||||
push %eax
|
||||
dec %esi
|
||||
push %eax
|
||||
dec %edi
|
||||
push %eax
|
||||
push %eax
|
||||
push %eax
|
||||
xor %eax, 0x42(%edi)
|
||||
inc %edi
|
||||
inc %edx
|
||||
push %eax
|
||||
xor $0x50,%al
|
||||
pop %edx
|
||||
push %eax
|
||||
inc %ebp
|
||||
push %ecx
|
||||
push %edx
|
||||
inc %esi
|
||||
xor 0x31(%edi),%al
|
||||
push %eax
|
||||
dec %ebp
|
||||
push %ecx
|
||||
push %ecx
|
||||
push %eax
|
||||
dec %esi
|
||||
inc %ecx
|
||||
inc %ecx
|
|
@ -1,45 +1,9 @@
|
|||
#include "unicorn_test.h"
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Assert that err matches expect
|
||||
*/
|
||||
#define uc_assert_err(expect, err) \
|
||||
do { \
|
||||
uc_err __err = err; \
|
||||
if (__err != expect) { \
|
||||
fprintf(stderr, "%s", uc_strerror(__err)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Assert that err is UC_ERR_OK
|
||||
*/
|
||||
#define uc_assert_success(err) uc_assert_err(UC_ERR_OK, err)
|
||||
|
||||
/**
|
||||
* Assert that err is anything but UC_ERR_OK
|
||||
*
|
||||
* Note: Better to use uc_assert_err(<specific error>, err),
|
||||
* as this serves to document which errors a function will return
|
||||
* in various scenarios.
|
||||
*/
|
||||
#define uc_assert_fail(err) \
|
||||
do { \
|
||||
uc_err __err = err; \
|
||||
if (__err == UC_ERR_OK) { \
|
||||
fprintf(stderr, "%s", uc_strerror(__err)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define OK(x) uc_assert_success(x)
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void test_idt_gdt_i386(/*void **state*/)
|
||||
{
|
||||
uc_engine *uc;
|
||||
|
@ -50,7 +14,9 @@ static void test_idt_gdt_i386(/*void **state*/)
|
|||
uc_x86_mmr ldt;
|
||||
uc_x86_mmr tr;
|
||||
|
||||
const uint8_t code[] = "\x0f\x01\x0c\x24\x0f\x01\x44\x24\x06"; // sidt [esp]; sgdt [esp+6]
|
||||
struct stat info;
|
||||
char * code = read_file("gdt_idx.bin", &info);
|
||||
|
||||
const uint64_t address = 0x1000000;
|
||||
|
||||
int r_esp = address + 0x1000 - 0x100; // initial esp
|
||||
|
@ -79,7 +45,7 @@ static void test_idt_gdt_i386(/*void **state*/)
|
|||
uc_assert_success(err);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
err = uc_mem_write(uc, address, code, sizeof(code)-1);
|
||||
err = uc_mem_write(uc, address, code, info.st_size);
|
||||
uc_assert_success(err);
|
||||
|
||||
// initialize machine registers
|
||||
|
@ -141,7 +107,7 @@ static void test_idt_gdt_i386(/*void **state*/)
|
|||
assert(memcmp(buf, "\xba\xdc\x21\x43\x65\x87", 6) == 0);
|
||||
|
||||
uc_close(uc);
|
||||
|
||||
free(code);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -90,6 +90,8 @@ static void test_high_address_reads(void **state)
|
|||
static void test_high_address_read_values(void **state)
|
||||
{
|
||||
uc_engine *uc = *state;
|
||||
struct stat info;
|
||||
char * code = read_file("high_address.bin", &info);
|
||||
|
||||
uint64_t addr = 0x0010000000000001;
|
||||
//addr = 0x000ffffffffffff8; // uncomment to fix wrong behaviour
|
||||
|
@ -100,15 +102,16 @@ static void test_high_address_read_values(void **state)
|
|||
uc_assert_success(uc_mem_write(uc, addr, content, 8));
|
||||
uc_assert_success(uc_reg_write(uc, UC_X86_REG_RAX, &addr));
|
||||
const uint64_t base_addr = 0x40000;
|
||||
uint8_t code[] = {0x48,0x8b,0x00,0x90,0x90,0x90,0x90}; // mov rax, [rax], nops
|
||||
uc_assert_success(uc_mem_map(uc, base_addr, 4096, UC_PROT_ALL));
|
||||
uc_assert_success(uc_mem_write(uc, base_addr, code, 7));
|
||||
uc_assert_success(uc_mem_write(uc, base_addr, code, info.st_size));
|
||||
uc_assert_success(uc_emu_start(uc, base_addr, base_addr + 3, 0, 0));
|
||||
uint64_t rax = 0;
|
||||
uc_assert_success(uc_reg_read(uc, UC_X86_REG_RAX, &rax));
|
||||
if(rax != 0x4242424242424242) {
|
||||
fail_msg("wrong memory read from code %"PRIx64, rax);
|
||||
}
|
||||
|
||||
free(code);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Test PC change during the callback. by Nguyen Anh Quynh, 2016
|
||||
#include "unicorn_test.h"
|
||||
#include "unicorn/unicorn.h"
|
||||
#include "sys/stat.h"
|
||||
|
||||
#define OK(x) uc_assert_success(x)
|
||||
|
||||
|
@ -54,21 +55,12 @@ static void test_pc_change(void **state)
|
|||
uc_engine *uc = *state;
|
||||
uc_hook trace1;
|
||||
int32_t r_ecx = 3, r_edx = 15;
|
||||
struct stat info;
|
||||
char *code = read_file("pc_change.bin", &info);
|
||||
|
||||
#define BASEADDR 0x1000000
|
||||
|
||||
uint64_t address = BASEADDR;
|
||||
const uint8_t code[] = {
|
||||
0x41, // inc ECX @0x1000000
|
||||
0x41, // inc ECX
|
||||
0x41, // inc ECX
|
||||
0x41, // inc ECX @0x1000003
|
||||
0x41, // inc ECX
|
||||
0x41, // inc ECX
|
||||
|
||||
0x42, // inc EDX @0x1000006
|
||||
0x42, // inc EDX
|
||||
};
|
||||
|
||||
#undef BASEADDR
|
||||
|
||||
|
@ -76,7 +68,7 @@ static void test_pc_change(void **state)
|
|||
OK(uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL));
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
OK(uc_mem_write(uc, address, code, sizeof(code)));
|
||||
OK(uc_mem_write(uc, address, code, info.st_size));
|
||||
|
||||
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
||||
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
@ -85,7 +77,7 @@ static void test_pc_change(void **state)
|
|||
// trace all instructions
|
||||
OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, 1, 0));
|
||||
|
||||
OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0));
|
||||
OK(uc_emu_start(uc, address, address+info.st_size, 0, 0));
|
||||
|
||||
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
||||
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
@ -93,6 +85,7 @@ static void test_pc_change(void **state)
|
|||
printf("ECX = %u, EDX = %u\n", r_ecx, r_edx);
|
||||
assert_int_equal(r_ecx, 6);
|
||||
assert_int_equal(r_edx, 17);
|
||||
free(code);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "unicorn/unicorn.h"
|
||||
|
||||
#define RIP_NEXT_TO_THE_SELFMODIFY_OPCODE (1)
|
||||
|
@ -21,17 +22,6 @@
|
|||
#define CODE_SPACE (2 * 1024 * 1024)
|
||||
#define PHY_STACK_REGION (0x60000000)
|
||||
|
||||
#define X86_CODE32_ALPHA_MIXED \
|
||||
"\x89\xe1\xd9\xcd\xd9\x71\xf4\x5d\x55\x59\x49\x49\x49\x49\x49\x49" \
|
||||
"\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a\x41\x58" \
|
||||
"\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30" \
|
||||
"\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x51\x51\x51\x52" \
|
||||
"\x47\x33\x47\x34\x51\x55\x51\x56\x50\x47\x47\x38\x47\x39\x50\x4a" \
|
||||
"\x50\x4b\x50\x4c\x50\x4d\x50\x4e\x50\x4f\x50\x50\x50\x31\x47\x42" \
|
||||
"\x47\x42\x50\x34\x50\x5a\x50\x45\x51\x52\x46\x32\x47\x31\x50\x4d" \
|
||||
"\x51\x51\x50\x4e\x41\x41"
|
||||
|
||||
|
||||
/* Called before every test to set up a new instance */
|
||||
static int setup(void **state)
|
||||
{
|
||||
|
@ -57,12 +47,12 @@ static int teardown(void **state)
|
|||
|
||||
|
||||
|
||||
static void dump_stack_mem(uc_engine *uc)
|
||||
static void dump_stack_mem(uc_engine *uc, const struct stat info)
|
||||
{
|
||||
uint8_t tmp[256];
|
||||
uint32_t size;
|
||||
|
||||
size = sizeof(X86_CODE32_ALPHA_MIXED);
|
||||
size = sizeof(info.st_size);
|
||||
if (size > 255) size = 255;
|
||||
if (!uc_mem_read(uc, PHY_STACK_REGION, tmp, size))
|
||||
{
|
||||
|
@ -106,7 +96,8 @@ static void print_registers(uc_engine *uc)
|
|||
static void hook_code32(uc_engine *uc,
|
||||
uint64_t address,
|
||||
uint32_t size,
|
||||
void *user_data)
|
||||
void *user_data,
|
||||
const struct stat info)
|
||||
{
|
||||
//uint8_t opcode[256];
|
||||
uint8_t tmp[16];
|
||||
|
@ -126,7 +117,7 @@ static void hook_code32(uc_engine *uc,
|
|||
}
|
||||
printf("\n");
|
||||
}
|
||||
dump_stack_mem(uc);
|
||||
dump_stack_mem(uc, info);
|
||||
|
||||
|
||||
if (address == 0x60000025)
|
||||
|
@ -222,6 +213,8 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state)
|
|||
{
|
||||
uc_engine *uc = *state;
|
||||
uc_hook trace1, trace2;
|
||||
struct stat info;
|
||||
char * code = read_file("tb_x86.bin", &info);
|
||||
//void *mem;
|
||||
#ifdef RIP_NEXT_TO_THE_SELFMODIFY_OPCODE
|
||||
// These values assumes just before PC = 0x60000021
|
||||
|
@ -258,8 +251,8 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state)
|
|||
UC_PROT_ALL));
|
||||
uc_assert_success(uc_mem_write(uc,
|
||||
PHY_STACK_REGION,
|
||||
X86_CODE32_ALPHA_MIXED,
|
||||
sizeof(X86_CODE32_ALPHA_MIXED) - 1));
|
||||
code,
|
||||
info.st_size));
|
||||
uc_assert_success(uc_reg_write(uc, UC_X86_REG_EAX, &eax));
|
||||
uc_assert_success(uc_reg_write(uc, UC_X86_REG_ECX, &ecx));
|
||||
uc_assert_success(uc_reg_write(uc, UC_X86_REG_EDX, &edx));
|
||||
|
@ -275,7 +268,8 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state)
|
|||
hook_code32,
|
||||
NULL,
|
||||
1,
|
||||
0));
|
||||
0,
|
||||
info));
|
||||
|
||||
uc_assert_success(uc_hook_add(uc,
|
||||
&trace2,
|
||||
|
@ -294,7 +288,7 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state)
|
|||
#else
|
||||
PHY_STACK_REGION+0x0000,
|
||||
#endif
|
||||
PHY_STACK_REGION+sizeof(X86_CODE32_ALPHA_MIXED) - 1,
|
||||
PHY_STACK_REGION+info.st_size,
|
||||
0, 0));
|
||||
|
||||
uc_assert_success(uc_close(uc));
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/**
|
||||
* Assert that err matches expect
|
||||
|
@ -38,5 +39,12 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
char * read_file(const char *filename, struct stat *info) {
|
||||
stat(filename, info);
|
||||
char *code = malloc(info->st_size);
|
||||
FILE *fp = fopen(filename, "r");
|
||||
fread(code, info->st_size, 1, fp);
|
||||
return code;
|
||||
}
|
||||
|
||||
#endif /* UNICORN_TEST_H */
|
||||
|
|
49
tests/unit/x86_soft_paging_low.s
Normal file
49
tests/unit/x86_soft_paging_low.s
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Zero memory for page directories and page tables
|
||||
mov $0x1000,%edi
|
||||
mov $0x1000,%ecx
|
||||
xor %eax,%eax
|
||||
rep stos %eax,(%edi)
|
||||
|
||||
// Load DWORD [0x4000] with 0xDEADBEEF to retrieve later
|
||||
mov $0x4000,%edi
|
||||
mov $0xBEEF,%eax
|
||||
mov %eax, (%edi)
|
||||
|
||||
// Identify map the first 4MiB of memory
|
||||
mov $0x400,%ecx
|
||||
mov $0x2000,%edi
|
||||
mov $3, %eax
|
||||
loop:
|
||||
stos %eax,(%edi)
|
||||
add $0x1000,%eax
|
||||
loop loop
|
||||
|
||||
// Map phyiscal address 0x4000 to cirtual address 0x7FF000
|
||||
mov $0x3ffc,%edi
|
||||
mov $0x4003,%eax
|
||||
mov %eax, (%edi)
|
||||
|
||||
// Add page tables into page directory
|
||||
mov $0x1000, %edi
|
||||
mov $0x2003, %eax
|
||||
mov %eax, (%edi)
|
||||
mov $0x1004, %edi
|
||||
mov $0x3003, %eax
|
||||
mov %eax, (%edi)
|
||||
|
||||
// Load the page directory register
|
||||
mov $0x1000, %eax
|
||||
mov %eax, %cr3
|
||||
|
||||
// Enable paging
|
||||
mov %cr0, %eax
|
||||
or $0x80000000, %eax
|
||||
|
||||
// Clear EAX
|
||||
mov %eax, %cr0
|
||||
|
||||
//Load using virtual memory address; EAX = 0xBEEF
|
||||
xor %eax,%eax
|
||||
mov $0x7FF000, %esi
|
||||
mov (%esi), %eax
|
||||
hlt
|
Loading…
Reference in a new issue