updated gdtr/idtr/ldtr/tr read/write code

This commit is contained in:
Chris Eagle 2016-02-04 16:44:52 -08:00
parent 9977054a15
commit e59382e030
4 changed files with 120 additions and 155 deletions

13
include/unicorn/x86.h Normal file → Executable file
View File

@ -8,6 +8,15 @@
extern "C" {
#endif
//Memory-Management Register fields (idtr, gdtr, ldtr, tr)
//borrow from SegmentCache in qemu/target-i386/cpu.h
typedef struct x86_mmr {
uint32_t selector;
uint64_t base; /* handle 32 or 64 bit CPUs */
uint32_t limit;
uint32_t flags;
} x86_mmr;
// Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr())
// @user_data: user data passed to tracing APIs.
typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data);
@ -64,9 +73,7 @@ typedef enum uc_x86_reg {
UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D,
UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W,
UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W,
UC_X86_REG_IDTR_LIMIT, UC_X86_REG_IDTR_BASE, UC_X86_REG_GDTR_LIMIT, UC_X86_REG_GDTR_BASE,
UC_X86_REG_LDTR_SS, UC_X86_REG_LDTR_LIMIT, UC_X86_REG_LDTR_BASE, UC_X86_REG_LDTR_ATTR,
UC_X86_REG_TR_SS, UC_X86_REG_TR_LIMIT, UC_X86_REG_TR_BASE, UC_X86_REG_TR_ATTR,
UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR,
UC_X86_REG_ENDING // <-- mark the end of the list of registers
} uc_x86_reg;

2
qemu/target-i386/cpu.h Normal file → Executable file
View File

@ -699,7 +699,7 @@ typedef enum {
typedef struct SegmentCache {
uint32_t selector;
target_ulong base;
uint64_t base; /* handle 32 or 64 bit CPUs */
uint32_t limit;
uint32_t flags;
} SegmentCache;

192
qemu/target-i386/unicorn.c Normal file → Executable file
View File

@ -277,41 +277,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
case UC_X86_REG_GS:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base;
break;
case UC_X86_REG_IDTR_LIMIT:
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.idt.limit);
case UC_X86_REG_IDTR:
((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit;
((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.idt.base;
break;
case UC_X86_REG_IDTR_BASE:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.idt.base;
case UC_X86_REG_GDTR:
((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit;
((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.gdt.base;
break;
case UC_X86_REG_GDTR_LIMIT:
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.gdt.limit);
case UC_X86_REG_LDTR:
((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit;
((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.ldt.base;
((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector;
((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags;
break;
case UC_X86_REG_GDTR_BASE:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.gdt.base;
break;
case UC_X86_REG_LDTR_SS:
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.ldt.selector);
break;
case UC_X86_REG_LDTR_LIMIT:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.limit;
break;
case UC_X86_REG_LDTR_BASE:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.base;
break;
case UC_X86_REG_LDTR_ATTR:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.flags;
break;
case UC_X86_REG_TR_SS:
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.tr.selector);
break;
case UC_X86_REG_TR_LIMIT:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.limit;
break;
case UC_X86_REG_TR_BASE:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.base;
break;
case UC_X86_REG_TR_ATTR:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.flags;
case UC_X86_REG_TR:
((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit;
((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.tr.base;
((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector;
((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags;
break;
}
break;
@ -561,41 +545,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
case UC_X86_REG_R15B:
*(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15]);
break;
case UC_X86_REG_IDTR_LIMIT:
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.idt.limit);
case UC_X86_REG_IDTR:
((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit;
((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.idt.base;
break;
case UC_X86_REG_IDTR_BASE:
*(int64_t *)value = X86_CPU(uc, mycpu)->env.idt.base;
case UC_X86_REG_GDTR:
((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit;
((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.gdt.base;
break;
case UC_X86_REG_GDTR_LIMIT:
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.gdt.limit);
case UC_X86_REG_LDTR:
((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit;
((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.ldt.base;
((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector;
((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags;
break;
case UC_X86_REG_GDTR_BASE:
*(int64_t *)value = X86_CPU(uc, mycpu)->env.gdt.base;
break;
case UC_X86_REG_LDTR_SS:
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.ldt.selector);
break;
case UC_X86_REG_LDTR_LIMIT:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.limit;
break;
case UC_X86_REG_LDTR_BASE:
*(int64_t *)value = X86_CPU(uc, mycpu)->env.ldt.base;
break;
case UC_X86_REG_LDTR_ATTR:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.flags;
break;
case UC_X86_REG_TR_SS:
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.tr.selector);
break;
case UC_X86_REG_TR_LIMIT:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.limit;
break;
case UC_X86_REG_TR_BASE:
*(int64_t *)value = X86_CPU(uc, mycpu)->env.tr.base;
break;
case UC_X86_REG_TR_ATTR:
*(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.flags;
case UC_X86_REG_TR:
((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit;
((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.tr.base;
((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector;
((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags;
break;
}
break;
@ -756,41 +724,25 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
case UC_X86_REG_GS:
X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint32_t *)value;
break;
case UC_X86_REG_IDTR_LIMIT:
WRITE_WORD(X86_CPU(uc, mycpu)->env.idt.limit, *(uint16_t *)value);
case UC_X86_REG_IDTR:
X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((SegmentCache *)value)->limit;
X86_CPU(uc, mycpu)->env.idt.base = (uint32_t)((SegmentCache *)value)->base;
break;
case UC_X86_REG_IDTR_BASE:
X86_CPU(uc, mycpu)->env.idt.base = *(uint32_t *)value;
case UC_X86_REG_GDTR:
X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((SegmentCache *)value)->limit;
X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((SegmentCache *)value)->base;
break;
case UC_X86_REG_GDTR_LIMIT:
WRITE_WORD(X86_CPU(uc, mycpu)->env.gdt.limit, *(uint16_t *)value);
case UC_X86_REG_LDTR:
X86_CPU(uc, mycpu)->env.ldt.limit = ((SegmentCache *)value)->limit;
X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((SegmentCache *)value)->base;
X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((SegmentCache *)value)->selector;
X86_CPU(uc, mycpu)->env.ldt.flags = ((SegmentCache *)value)->flags;
break;
case UC_X86_REG_GDTR_BASE:
X86_CPU(uc, mycpu)->env.gdt.base = *(uint32_t *)value;
break;
case UC_X86_REG_LDTR_SS:
WRITE_WORD(X86_CPU(uc, mycpu)->env.ldt.selector, *(uint16_t *)value);
break;
case UC_X86_REG_LDTR_LIMIT:
X86_CPU(uc, mycpu)->env.ldt.limit = *(uint32_t *)value;
break;
case UC_X86_REG_LDTR_BASE:
X86_CPU(uc, mycpu)->env.ldt.base = *(uint32_t *)value;
break;
case UC_X86_REG_LDTR_ATTR:
X86_CPU(uc, mycpu)->env.ldt.flags = *(uint32_t *)value;
break;
case UC_X86_REG_TR_SS:
WRITE_WORD(X86_CPU(uc, mycpu)->env.tr.selector, *(uint16_t *)value);
break;
case UC_X86_REG_TR_LIMIT:
X86_CPU(uc, mycpu)->env.tr.limit = *(uint32_t *)value;
break;
case UC_X86_REG_TR_BASE:
X86_CPU(uc, mycpu)->env.tr.base = *(uint32_t *)value;
break;
case UC_X86_REG_TR_ATTR:
X86_CPU(uc, mycpu)->env.tr.flags = *(uint32_t *)value;
case UC_X86_REG_TR:
X86_CPU(uc, mycpu)->env.tr.limit = ((SegmentCache *)value)->limit;
X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((SegmentCache *)value)->base;
X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((SegmentCache *)value)->selector;
X86_CPU(uc, mycpu)->env.tr.flags = ((SegmentCache *)value)->flags;
break;
}
break;
@ -1050,41 +1002,25 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
case UC_X86_REG_R15B:
WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15], *(uint8_t *)value);
break;
case UC_X86_REG_IDTR_LIMIT:
WRITE_WORD(X86_CPU(uc, mycpu)->env.idt.limit, *(uint16_t *)value);
case UC_X86_REG_IDTR:
X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((SegmentCache *)value)->limit;
X86_CPU(uc, mycpu)->env.idt.base = ((SegmentCache *)value)->base;
break;
case UC_X86_REG_IDTR_BASE:
X86_CPU(uc, mycpu)->env.idt.base = *(uint64_t *)value;
case UC_X86_REG_GDTR:
X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((SegmentCache *)value)->limit;
X86_CPU(uc, mycpu)->env.gdt.base = ((SegmentCache *)value)->base;
break;
case UC_X86_REG_GDTR_LIMIT:
WRITE_WORD(X86_CPU(uc, mycpu)->env.gdt.limit, *(uint16_t *)value);
case UC_X86_REG_LDTR:
X86_CPU(uc, mycpu)->env.ldt.limit = ((SegmentCache *)value)->limit;
X86_CPU(uc, mycpu)->env.ldt.base = ((SegmentCache *)value)->base;
X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((SegmentCache *)value)->selector;
X86_CPU(uc, mycpu)->env.ldt.flags = ((SegmentCache *)value)->flags;
break;
case UC_X86_REG_GDTR_BASE:
X86_CPU(uc, mycpu)->env.gdt.base = *(uint64_t *)value;
break;
case UC_X86_REG_LDTR_SS:
WRITE_WORD(X86_CPU(uc, mycpu)->env.ldt.selector, *(uint16_t *)value);
break;
case UC_X86_REG_LDTR_LIMIT:
WRITE_DWORD(X86_CPU(uc, mycpu)->env.ldt.limit, *(uint32_t *)value);
break;
case UC_X86_REG_LDTR_BASE:
X86_CPU(uc, mycpu)->env.ldt.base = *(uint64_t *)value;
break;
case UC_X86_REG_LDTR_ATTR:
WRITE_DWORD(X86_CPU(uc, mycpu)->env.ldt.flags, *(uint32_t *)value);
break;
case UC_X86_REG_TR_SS:
WRITE_WORD(X86_CPU(uc, mycpu)->env.tr.selector, *(uint16_t *)value);
break;
case UC_X86_REG_TR_LIMIT:
WRITE_DWORD(X86_CPU(uc, mycpu)->env.tr.limit, *(uint32_t *)value);
break;
case UC_X86_REG_TR_BASE:
X86_CPU(uc, mycpu)->env.tr.base = *(uint64_t *)value;
break;
case UC_X86_REG_TR_ATTR:
WRITE_DWORD(X86_CPU(uc, mycpu)->env.tr.flags, *(uint32_t *)value);
case UC_X86_REG_TR:
X86_CPU(uc, mycpu)->env.tr.limit = ((SegmentCache *)value)->limit;
X86_CPU(uc, mycpu)->env.tr.base = ((SegmentCache *)value)->base;
X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((SegmentCache *)value)->selector;
X86_CPU(uc, mycpu)->env.tr.flags = ((SegmentCache *)value)->flags;
break;
}
break;

View File

@ -47,16 +47,30 @@ static void test_idt_gdt_i386(/*void **state*/)
uc_engine *uc;
uc_err err;
uint8_t buf[6];
x86_mmr idt;
x86_mmr gdt;
x86_mmr ldt;
x86_mmr tr;
const uint8_t code[] = "\x0f\x01\x0c\x24\x0f\x01\x44\x24\x06"; // sidt [esp]; sgdt [esp+6]
const uint64_t address = 0x1000000;
int r_esp = address + 0x1000 - 0x100; // initial esp
int idt_base = 0x12345678;
int idt_limit = 0xabcd;
int gdt_base = 0x87654321;
int gdt_limit = 0xdcba;
idt.base = 0x12345678;
idt.limit = 0xabcd;
gdt.base = 0x87654321;
gdt.limit = 0xdcba;
ldt.base = 0xfedcba98;
ldt.limit = 0x11111111;
ldt.selector = 0x3333;
ldt.flags = 0x55555555;
tr.base = 0x22222222;
tr.limit = 0x33333333;
tr.selector = 0x4444;
tr.flags = 0x66666666;
// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
@ -73,36 +87,44 @@ static void test_idt_gdt_i386(/*void **state*/)
// initialize machine registers
err = uc_reg_write(uc, UC_X86_REG_ESP, &r_esp);
uc_assert_success(err);
err = uc_reg_write(uc, UC_X86_REG_IDTR_BASE, &idt_base);
err = uc_reg_write(uc, UC_X86_REG_IDTR, &idt);
uc_assert_success(err);
err = uc_reg_write(uc, UC_X86_REG_IDTR_LIMIT, &idt_limit);
uc_assert_success(err);
err = uc_reg_write(uc, UC_X86_REG_GDTR_BASE, &gdt_base);
uc_assert_success(err);
err = uc_reg_write(uc, UC_X86_REG_GDTR_LIMIT, &gdt_limit);
err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdt);
uc_assert_success(err);
idt_base = 0;
idt_limit = 0;
gdt_base = 0;
gdt_limit = 0;
idt.base = 0;
idt.limit = 0;
gdt.base = 0;
gdt.limit = 0;
// emulate machine code in infinite time
err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0);
uc_assert_success(err);
uc_reg_read(uc, UC_X86_REG_IDTR_BASE, &idt_base);
assert(idt_base == 0x12345678);
uc_reg_read(uc, UC_X86_REG_IDTR_LIMIT, &idt_limit);
assert(idt_limit == 0xabcd);
uc_reg_read(uc, UC_X86_REG_IDTR, &idt);
assert(idt.base == 0x12345678);
assert(idt.limit == 0xabcd);
uc_reg_read(uc, UC_X86_REG_GDTR_BASE, &gdt_base);
assert(gdt_base == 0x87654321);
uc_reg_read(uc, UC_X86_REG_GDTR, &gdt);
assert(gdt.base == 0x87654321);
assert(gdt.limit == 0xdcba);
uc_reg_read(uc, UC_X86_REG_GDTR_LIMIT, &gdt_limit);
assert(gdt_limit == 0xdcba);
//userspace can only set ldt selector, remainder are loaded from
//GDT/LDT, but we allow all to emulator user
uc_reg_read(uc, UC_X86_REG_LDTR, &ldt);
assert(ldt.base == 0xfedcba98);
assert(ldt.limit == 0x11111111);
assert(ldt.selector == 0x3333);
assert(ldt.flags = 0x55555555);
//userspace can only set tr selector, remainder are loaded from
//GDT/LDT, but we allow all to emulator user
uc_reg_read(uc, UC_X86_REG_TR, &tr);
assert(tr.base == 0x22222222);
assert(tr.limit == 0x33333333);
assert(tr.selector == 0x4444);
assert(tr.flags = 0x66666666);
// read from memory
err = uc_mem_read(uc, r_esp, buf, 6);