help
          Compiles the Palacios library with debugging symbols
 
+choice 
+       prompt "X86 decoder"
+       default XED
+
+config XED
+       bool "XED decoder library"
+       help
+          This uses the XED decoder library from pintools 
+
+config V3_DECODER
+       bool "Internal Palacios decoder"
+       help
+           This selects the internal V3Vee x86 decoder
+
+
+endchoice
 
 menu "Supported host OS features"
       
 
 };
 
 
-struct basic_instr_info {
-    uint_t instr_length;
-    uint_t op_size;
-    uint_t str_op    : 1;
-    uint_t has_rep : 1;
-};
-
-
-
 /************************/
 /* EXTERNAL DECODER API */
 /************************/
 int v3_encode(struct guest_info * info, struct x86_instr * instr, char * instr_buf);
 
 
-/*
- * Gets the operand size for a memory operation
- *
- */
-int v3_basic_mem_decode(struct guest_info * info, addr_t instr_ptr, struct basic_instr_info * instr_info);
-
-
 
 /* Removes a rep prefix in place */
 void v3_strip_rep_prefix(uchar_t * instr, int length);
 void v3_get_prefixes(uchar_t * instr, struct x86_prefixes * prefixes);
 
 
-/* 
- * JRL: Some of this was taken from the Xen sources... 
- */
-
-#define PACKED __attribute__((packed))
-
-#define MODRM_MOD(x) ((x >> 6) & 0x3)
-#define MODRM_REG(x) ((x >> 3) & 0x7)
-#define MODRM_RM(x)  (x & 0x7)
-
-struct modrm_byte {
-    uint_t rm   :   3 PACKED;
-    uint_t reg  :   3 PACKED;
-    uint_t mod  :   2 PACKED;
-};
-
-
-#define SIB_BASE(x) ((x >> 6) & 0x3)
-#define SIB_INDEX(x) ((x >> 3) & 0x7)
-#define SIB_SCALE(x) (x & 0x7)
-
-struct sib_byte {
-    uint_t base     :   3 PACKED;
-    uint_t index    :   3 PACKED;
-    uint_t scale    :   2 PACKED;
-};
-
-
-
-#define MAKE_INSTR(nm, ...) static  const uchar_t V3_OPCODE_##nm[] = { __VA_ARGS__ }
-
-/* 
- * Here's how it works:
- * First byte: Length. 
- * Following bytes: Opcode bytes. 
- * Special case: Last byte, if zero, doesn't need to match. 
- */
-MAKE_INSTR(INVD,   2, 0x0f, 0x08);
-MAKE_INSTR(CPUID,  2, 0x0f, 0xa2);
-MAKE_INSTR(RDMSR,  2, 0x0f, 0x32);
-MAKE_INSTR(WRMSR,  2, 0x0f, 0x30);
-MAKE_INSTR(RDTSC,  2, 0x0f, 0x31);
-MAKE_INSTR(RDTSCP, 3, 0x0f, 0x01, 0xf9);
-MAKE_INSTR(CLI,    1, 0xfa);
-MAKE_INSTR(STI,    1, 0xfb);
-MAKE_INSTR(RDPMC,  2, 0x0f, 0x33);
-MAKE_INSTR(CLGI,   3, 0x0f, 0x01, 0xdd);
-MAKE_INSTR(STGI,   3, 0x0f, 0x01, 0xdc);
-MAKE_INSTR(VMRUN,  3, 0x0f, 0x01, 0xd8);
-MAKE_INSTR(VMLOAD, 3, 0x0f, 0x01, 0xda);
-MAKE_INSTR(VMSAVE, 3, 0x0f, 0x01, 0xdb);
-MAKE_INSTR(VMCALL, 3, 0x0f, 0x01, 0xd9);
-MAKE_INSTR(PAUSE,  2, 0xf3, 0x90);
-MAKE_INSTR(SKINIT, 3, 0x0f, 0x01, 0xde);
-MAKE_INSTR(MOV2CR, 3, 0x0f, 0x22, 0x00);
-MAKE_INSTR(MOVCR2, 3, 0x0f, 0x20, 0x00);
-MAKE_INSTR(MOV2DR, 3, 0x0f, 0x23, 0x00);
-MAKE_INSTR(MOVDR2, 3, 0x0f, 0x21, 0x00);
-MAKE_INSTR(PUSHF,  1, 0x9c);
-MAKE_INSTR(POPF,   1, 0x9d);
-MAKE_INSTR(RSM,    2, 0x0f, 0xaa);
-MAKE_INSTR(INVLPG, 3, 0x0f, 0x01, 0x00);
-MAKE_INSTR(INVLPGA,3, 0x0f, 0x01, 0xdf);
-MAKE_INSTR(HLT,    1, 0xf4);
-MAKE_INSTR(CLTS,   2, 0x0f, 0x06);
-MAKE_INSTR(LMSW,   3, 0x0f, 0x01, 0x00);
-MAKE_INSTR(SMSW,   3, 0x0f, 0x01, 0x00);
 
 
 #define PREFIX_LOCK         0xF0
 #define PREFIX_OP_SIZE      0x66
 #define PREFIX_ADDR_SIZE    0x67
 
-int v3_opcode_cmp(const uchar_t * op1, const uchar_t * op2);
+
 
 
 static inline int is_prefix_byte(uchar_t byte) {
 }
 
 
+
 static inline addr_t get_addr_linear(struct guest_info * info, addr_t addr, struct v3_segment * seg) {
     switch (info->cpu_mode) {
        case REAL:
 }
 
 
-typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t;
-typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t;
-
-
-
-
-
-
-struct v3_gprs;
-
-static inline addr_t decode_register(struct v3_gprs * gprs, char reg_code, reg_size_t reg_size) {
-    addr_t reg_addr;
-
-    switch (reg_code) {
-       case 0:
-           reg_addr = (addr_t)&(gprs->rax);
-           break;
-       case 1:
-           reg_addr = (addr_t)&(gprs->rcx);
-           break;
-       case 2:
-           reg_addr = (addr_t)&(gprs->rdx);
-           break;
-       case 3:
-           reg_addr = (addr_t)&(gprs->rbx);
-           break;
-       case 4:
-           if (reg_size == REG8) {
-               reg_addr = (addr_t)&(gprs->rax) + 1;
-           } else {
-               reg_addr = (addr_t)&(gprs->rsp);
-           }
-           break;
-       case 5:
-           if (reg_size == REG8) {
-               reg_addr = (addr_t)&(gprs->rcx) + 1;
-           } else {
-               reg_addr = (addr_t)&(gprs->rbp);
-           }
-           break;
-       case 6:
-           if (reg_size == REG8) {
-               reg_addr = (addr_t)&(gprs->rdx) + 1;
-           } else {
-               reg_addr = (addr_t)&(gprs->rsi);
-           }
-           break;
-       case 7:
-           if (reg_size == REG8) {
-               reg_addr = (addr_t)&(gprs->rbx) + 1;
-           } else {
-               reg_addr = (addr_t)&(gprs->rdi);
-           }
-           break;
-       default:
-           reg_addr = 0;
-           break;
-    }
-
-    return reg_addr;
-}
-
-
-
-static inline v3_operand_type_t decode_operands16(struct v3_gprs * gprs, // input/output
-                                                 char * modrm_instr,       // input
-                                                 int * offset,             // output
-                                                 addr_t * first_operand,   // output
-                                                 addr_t * second_operand,  // output
-                                                 reg_size_t reg_size) {    // input
-  
-    struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
-    addr_t base_addr = 0;
-    modrm_mode_t mod_mode = 0;
-    v3_operand_type_t addr_type = INVALID_OPERAND;
-    char * instr_cursor = modrm_instr;
-
-    //  PrintDebug("ModRM mod=%d\n", modrm->mod);
-
-    instr_cursor += 1;
-
-    if (modrm->mod == 3) {
-       mod_mode = REG;
-       addr_type = REG_OPERAND;
-       //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
-
-       *first_operand = decode_register(gprs, modrm->rm, reg_size);
-
-    } else {
-
-       addr_type = MEM_OPERAND;
-
-       if (modrm->mod == 0) {
-           mod_mode = DISP0;
-       } else if (modrm->mod == 1) {
-           mod_mode = DISP8;
-       } else if (modrm->mod == 2) {
-           mod_mode = DISP16;
-       }
-
-       switch (modrm->rm) {
-           case 0:
-               base_addr = gprs->rbx + gprs->rsi;
-               break;
-           case 1:
-               base_addr = gprs->rbx + gprs->rdi;
-               break;
-           case 2:
-               base_addr = gprs->rbp + gprs->rsi;
-               break;
-           case 3:
-               base_addr = gprs->rbp + gprs->rdi;
-               break;
-           case 4:
-               base_addr = gprs->rsi;
-               break;
-           case 5:
-               base_addr = gprs->rdi;
-               break;
-           case 6:
-               if (modrm->mod == 0) {
-                   base_addr = 0;
-                   mod_mode = DISP16;
-               } else {
-                   base_addr = gprs->rbp;
-               }
-               break;
-           case 7:
-               base_addr = gprs->rbx;
-               break;
-       }
-
-
-
-       if (mod_mode == DISP8) {
-           base_addr += (uchar_t)*(instr_cursor);
-           instr_cursor += 1;
-       } else if (mod_mode == DISP16) {
-           base_addr += (ushort_t)*(instr_cursor);
-           instr_cursor += 2;
-       }
-    
-       *first_operand = base_addr;
-    }
-
-    *offset +=  (instr_cursor - modrm_instr);
-    *second_operand = decode_register(gprs, modrm->reg, reg_size);
-
-    return addr_type;
-}
-
-
-
-static inline v3_operand_type_t decode_operands32(struct v3_gprs * gprs, // input/output
-                                                 uchar_t * modrm_instr,       // input
-                                                 int * offset,             // output
-                                                 addr_t * first_operand,   // output
-                                                 addr_t * second_operand,  // output
-                                                 reg_size_t reg_size) {    // input
-  
-    uchar_t * instr_cursor = modrm_instr;
-    struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
-    addr_t base_addr = 0;
-    modrm_mode_t mod_mode = 0;
-    uint_t has_sib_byte = 0;
-    v3_operand_type_t addr_type = INVALID_OPERAND;
-
-
-
-    instr_cursor += 1;
-
-    if (modrm->mod == 3) {
-       mod_mode = REG;
-       addr_type = REG_OPERAND;
-    
-       //    PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
-
-       *first_operand = decode_register(gprs, modrm->rm, reg_size);
-
-    } else {
-
-       addr_type = MEM_OPERAND;
-
-       if (modrm->mod == 0) {
-           mod_mode = DISP0;
-       } else if (modrm->mod == 1) {
-           mod_mode = DISP8;
-       } else if (modrm->mod == 2) {
-           mod_mode = DISP32;
-       }
-    
-       switch (modrm->rm) {
-           case 0:
-               base_addr = gprs->rax;
-               break;
-           case 1:
-               base_addr = gprs->rcx;
-               break;
-           case 2:
-               base_addr = gprs->rdx;
-               break;
-           case 3:
-               base_addr = gprs->rbx;
-               break;
-           case 4:
-               has_sib_byte = 1;
-               break;
-           case 5:
-               if (modrm->mod == 0) {
-                   base_addr = 0;
-                   mod_mode = DISP32;
-               } else {
-                   base_addr = gprs->rbp;
-               }
-               break;
-           case 6:
-               base_addr = gprs->rsi;
-               break;
-           case 7:
-               base_addr = gprs->rdi;
-               break;
-       }
-
-       if (has_sib_byte) {
-           instr_cursor += 1;
-           struct sib_byte * sib = (struct sib_byte *)(instr_cursor);
-           int scale = 1;
-
-           instr_cursor += 1;
-
-
-           if (sib->scale == 1) {
-               scale = 2;
-           } else if (sib->scale == 2) {
-               scale = 4;
-           } else if (sib->scale == 3) {
-               scale = 8;
-           }
-
-
-           switch (sib->index) {
-               case 0:
-                   base_addr = gprs->rax;
-                   break;
-               case 1:
-                   base_addr = gprs->rcx;
-                   break;
-               case 2:
-                   base_addr = gprs->rdx;
-                   break;
-               case 3:
-                   base_addr = gprs->rbx;
-                   break;
-               case 4:
-                   base_addr = 0;
-                   break;
-               case 5:
-                   base_addr = gprs->rbp;
-                   break;
-               case 6:
-                   base_addr = gprs->rsi;
-                   break;
-               case 7:
-                   base_addr = gprs->rdi;
-                   break;
-           }
-
-           base_addr *= scale;
-
-
-           switch (sib->base) {
-               case 0:
-                   base_addr += gprs->rax;
-                   break;
-               case 1:
-                   base_addr += gprs->rcx;
-                   break;
-               case 2:
-                   base_addr += gprs->rdx;
-                   break;
-               case 3:
-                   base_addr += gprs->rbx;
-                   break;
-               case 4:
-                   base_addr += gprs->rsp;
-                   break;
-               case 5:
-                   if (modrm->mod != 0) {
-                       base_addr += gprs->rbp;
-                   }
-                   break;
-               case 6:
-                   base_addr += gprs->rsi;
-                   break;
-               case 7:
-                   base_addr += gprs->rdi;
-                   break;
-           }
-
-       } 
-
-
-       if (mod_mode == DISP8) {
-           base_addr += (uchar_t)*(instr_cursor);
-           instr_cursor += 1;
-       } else if (mod_mode == DISP32) {
-           base_addr += (uint_t)*(instr_cursor);
-           instr_cursor += 4;
-       }
-    
-
-       *first_operand = base_addr;
-    }
-
-    *offset += (instr_cursor - modrm_instr);
-
-    *second_operand = decode_register(gprs, modrm->reg, reg_size);
-
-    return addr_type;
-}
-
-
 
 #endif // !__V3VEE__
 
 
+++ /dev/null
-/*
- * This file is part of the Palacios Virtual Machine Monitor developed
- * by the V3VEE Project with funding from the United States National 
- * Science Foundation and the Department of Energy.  
- *
- * The V3VEE Project is a joint project between Northwestern University
- * and the University of New Mexico.  You can find out more at 
- * http://www.v3vee.org
- *
- * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
- * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
- * All rights reserved.
- *
- * Author: Jack Lange <jarusl@cs.northwestern.edu>
- *
- * This is free software.  You are permitted to use,
- * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
- */
-
-#ifndef __VMM_EMULATOR_H__
-#define __VMM_EMULATOR_H__
-
-#ifdef __V3VEE__
-
-#include <palacios/vmm_list.h>
-#include <palacios/vmm_shadow_paging.h>
-#include <palacios/vmm_paging.h>
-
-
-
-
-
-
-
-
-struct emulation_state {
-
-    uint_t running : 1;
-    uint_t instr_length;
-
-    uint_t tf_enabled : 1;
-};
-
-
-int v3_init_emulator(struct guest_info * info);
-
-
-int v3_emulation_exit_handler(struct guest_info * info);
-
-int v3_emulate_memory_write(struct guest_info * info, addr_t fault_gva,
-                           int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), 
-                           addr_t write_addr, void * private_data);
-int v3_emulate_memory_read(struct guest_info * info, addr_t fault_gva, 
-                          int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), 
-                          addr_t read_addr, void * private_data);
-
-
-#endif // !__V3VEE__
-
-#endif
 
-obj-y := libxed.a \
-        v3-xed-compat.o 
+obj-$(CONFIG_XED) :=   libxed.a \
+                       v3-xed-compat.o 
 
-obj-y := libxed32e.a \
-        v3-xed-compat.o
+obj-$(CONFIG_XED) :=   libxed32e.a \
+                       v3-xed-compat.o
 
        vmm_string.o \
        vmm_time.o \
        vmm_util.o \
-       vmm_xed.o \
        vmm_binaries.o \
        vmm_cpuid.o \
        vmm_xml.o \
        vmm_mtrr.o \
 
 
+
+obj-$(CONFIG_XED) +=   vmm_xed.o
+obj-$(CONFIG_V3_DECODER) += vmm_v3dec.o
+
 obj-$(CONFIG_SVM) +=    svm.o \
                        svm_io.o \
                        svm_lowlevel.o \
 
 
 
     if (vm->num_cores > avail_cores) {
-       PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n", vm->num_cores, avail_cores, MAX_CORES);
+       PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n", 
+                  vm->num_cores, avail_cores, MAX_CORES);
        return -1;
     }
 
 
 #include <palacios/vmm_decoder.h>
 
 
-int v3_opcode_cmp(const uchar_t * op1, const uchar_t * op2) {
-    if (op1[0] != op2[0]) {
-       return op1[0] - op2[0];;
-    } else {
-       return memcmp(op1 + 1, op2 + 1, op1[0]);
-    }
-}
+
 
 
 void v3_get_prefixes(uchar_t * instr, struct x86_prefixes * prefixes) {
 
+++ /dev/null
-/* 
- * This file is part of the Palacios Virtual Machine Monitor developed
- * by the V3VEE Project with funding from the United States National 
- * Science Foundation and the Department of Energy.  
- *
- * The V3VEE Project is a joint project between Northwestern University
- * and the University of New Mexico.  You can find out more at 
- * http://www.v3vee.org
- *
- * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
- * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
- * All rights reserved.
- *
- * Author: Jack Lange <jarusl@cs.northwestern.edu>
- *
- * This is free software.  You are permitted to use,
- * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
- */
-
-#include <palacios/vmm.h>
-#include <palacios/vmm_emulator.h>
-#include <palacios/vm_guest_mem.h>
-#include <palacios/vmm_decoder.h>
-#include <palacios/vmm_debug.h>
-#include <palacios/vmcb.h>
-#include <palacios/vmm_ctrl_regs.h>
-
-
-#ifndef CONFIG_DEBUG_EMULATOR
-#undef PrintDebug
-#define PrintDebug(fmt, args...)
-#endif
-
-
-int v3_init_emulator(struct guest_info * info) {
-
-
-    emulator->tf_enabled = 0;
-
-    return 0;
-}
-
-
-
-
-
-
-
-
-
-
-static int set_stepping(struct guest_info * info) {
-    vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
-    ctrl_area->exceptions.db = 1;
-
-    info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf;
-
-    ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1;
-
-    return 0;
-}
-
-
-static int unset_stepping(struct guest_info * info) {
-    vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
-    ctrl_area->exceptions.db = 0;
-
-    ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled;
-
-    if (info->emulator.tf_enabled) {
-       // Inject breakpoint exception into guest
-    }
-
-    return 0;
-
-}
-
-
-int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva, 
-                          int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), 
-                          addr_t read_gpa, void * private_data) {
-    struct basic_instr_info instr_info;
-    uchar_t instr[15];
-    int ret;
-    addr_t data_addr_offset = PAGE_OFFSET(read_gva);
- 
-    PrintDebug("Emulating Read\n");
-
-    if (info->mem_mode == PHYSICAL_MEM) { 
-       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
-    } else { 
-       ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
-    }
-
-    if (ret == -1) {
-       PrintError("Could not read guest memory\n");
-       return -1;
-    }
-
-#ifdef CONFIG_DEBUG_EMULATOR
-    PrintDebug("Instr (15 bytes) at %p:\n", (void *)(addr_t)instr);
-    PrintTraceMemDump(instr, 15);
-#endif  
-
-
-    if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
-       PrintError("Could not do a basic memory instruction decode\n");
-       V3_Free(data_page);
-       return -1;
-    }
-
-    // Read the data directly onto the emulated page
-    ret = read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data);
-    if ((ret == -1) || ((uint_t)ret != instr_info.op_size)) {
-       PrintError("Read error in emulator\n");
-       return -1;
-    }
-
- 
-
-    // setup_code_page(info, instr, &instr_info);
-    set_stepping(info);
-
-    info->emulator.running = 1;
-    info->run_state = VM_EMULATING;
-    info->emulator.instr_length = instr_info.instr_length;
-
-    return 0;
-}
-
-
-
-int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
-                           int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), 
-                           addr_t write_gpa, void * private_data) {
-
-    struct basic_instr_info instr_info;
-    uchar_t instr[15];
-    int ret;
-    addr_t data_addr_offset = PAGE_OFFSET(write_gva);
-    int i;
-
-    PrintDebug("Emulating Write for instruction at 0x%p\n", (void *)(addr_t)(info->rip));
-
-    if (info->mem_mode == PHYSICAL_MEM) { 
-       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
-    } else { 
-       ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
-    }
-
-
-  
-    if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
-       PrintError("Could not do a basic memory instruction decode\n");
-       V3_Free(write_op);
-       V3_Free(data_page);
-       return -1;
-    }
-
-    if (instr_info.has_rep==1) { 
-       PrintDebug("Emulated instruction has rep\n");
-    }
-
-
-    if (info->emulator.running == 0) {
-       //    setup_code_page(info, instr, &instr_info);
-       set_stepping(info);
-       info->emulator.running = 1;
-       info->run_state = VM_EMULATING;
-       info->emulator.instr_length = instr_info.instr_length;
-    }
-
-    return 0;
-}
-
-
-// end emulation
-int v3_emulation_exit_handler(struct guest_info * info) {
-  
-    unset_stepping(info);
-
-
-    PrintDebug("returning from emulation\n");
-
-    return 0;
-}
 
--- /dev/null
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm_decoder.h>
+
+
+/* .... Giant fucking switch tables */
+
+
+
+#define MODRM_MOD(x) (((x) >> 6) & 0x3)
+#define MODRM_REG(x) (((x) >> 3) & 0x7)
+#define MODRM_RM(x)  ((x) & 0x7)
+
+struct modrm_byte {
+    uint_t rm   :   3;
+    uint_t reg  :   3;
+    uint_t mod  :   2;
+} __attribute__((packed));
+
+
+#define SIB_BASE(x) (((x) >> 6) & 0x3)
+#define SIB_INDEX(x) (((x) >> 3) & 0x7)
+#define SIB_SCALE(x) ((x) & 0x7)
+
+struct sib_byte {
+    uint_t base     :   3;
+    uint_t index    :   3;
+    uint_t scale    :   2;
+} __attribute__((packed));
+
+
+
+
+typedef enum {
+    INVALID_INSTR,
+    LMSW,
+    SMSW,
+    CLTS,
+    INVLPG,
+
+    MOV_CR2,
+    MOV_2CR,
+    MOV_DR2,
+    MOV_2DR,
+    MOV_SR2,
+    MOV_2SR,
+
+    MOV_2GPR_8,
+    MOV_2GPR,
+    MOV_GPR2_8,
+    MOV_GPR2,
+    MOV_MEM2AL_8,
+    MOV_MEM2AX,
+    MOV_AL2MEM_8,
+    MOV_AX2MEM,
+    MOV_IMM2_8,
+    MOV_IMM2,
+
+    MOVS_8,
+    MOVS,
+    MOVSX_8,
+    MOVSX,
+    MOVZX_8,
+    MOVZX,
+
+    HLT,
+    PUSHF,
+    POPF,
+
+    ADC_2MEM_8,
+    ADC_2MEM,
+    ADC_MEM2_8,
+    ADC_MEM2,
+    ADC_IMM2_8,
+    ADC_IMM2,
+    ADC_IMM2SX_8,
+    ADD_IMM2_8,
+    ADD_IMM2,
+    ADD_IMM2SX_8,
+    ADD_2MEM_8,
+    ADD_2MEM,
+    ADD_MEM2_8,
+    ADD_MEM2,
+    AND_MEM2_8,
+    AND_MEM2,
+    AND_2MEM_8,
+    AND_2MEM,
+    AND_IMM2_8,
+    AND_IMM2,
+    AND_IMM2SX_8,
+    OR_2MEM_8,
+    OR_2MEM,
+    OR_MEM2_8,
+    OR_MEM2,
+    OR_IMM2_8,
+    OR_IMM2,
+    OR_IMM2SX_8,
+    SUB_2MEM_8,
+    SUB_2MEM,
+    SUB_MEM2_8,
+    SUB_MEM2,
+    SUB_IMM2_8,
+    SUB_IMM2,
+    SUB_IMM2SX_8,
+    XOR_2MEM_8,
+    XOR_2MEM,
+    XOR_MEM2_8,
+    XOR_MEM2,
+    XOR_IMM2_8,
+    XOR_IMM2,
+    XOR_IMM2SX_8,
+
+    INC_8,
+    INC,
+    DEC_8,
+    DEC,
+    NEG_8,
+    NEG, 
+    NOT_8,
+    NOT,
+    XCHG_8,
+    XCHG,
+
+    SETB,
+    SETBE,
+    SETL,
+    SETLE,
+    SETNB,
+    SETNBE,
+    SETNL,
+    SETNLE,
+    SETNO,
+    SETNP,
+    SETNS,
+    SETNZ,
+    SETP,
+    SETS,
+    SETZ,
+    SETO,
+
+    STOS_8,
+    STOS
+} op_form_t;
+
+static op_form_t op_code_to_form(uint8_t * instr);
+
+
+
+typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t;
+typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t;
+
+
+struct v3_gprs;
+
+static inline addr_t decode_register(struct v3_gprs * gprs, char reg_code, reg_size_t reg_size) {
+    addr_t reg_addr;
+
+    switch (reg_code) {
+       case 0:
+           reg_addr = (addr_t)&(gprs->rax);
+           break;
+       case 1:
+           reg_addr = (addr_t)&(gprs->rcx);
+           break;
+       case 2:
+           reg_addr = (addr_t)&(gprs->rdx);
+           break;
+       case 3:
+           reg_addr = (addr_t)&(gprs->rbx);
+           break;
+       case 4:
+           if (reg_size == REG8) {
+               reg_addr = (addr_t)&(gprs->rax) + 1;
+           } else {
+               reg_addr = (addr_t)&(gprs->rsp);
+           }
+           break;
+       case 5:
+           if (reg_size == REG8) {
+               reg_addr = (addr_t)&(gprs->rcx) + 1;
+           } else {
+               reg_addr = (addr_t)&(gprs->rbp);
+           }
+           break;
+       case 6:
+           if (reg_size == REG8) {
+               reg_addr = (addr_t)&(gprs->rdx) + 1;
+           } else {
+               reg_addr = (addr_t)&(gprs->rsi);
+           }
+           break;
+       case 7:
+           if (reg_size == REG8) {
+               reg_addr = (addr_t)&(gprs->rbx) + 1;
+           } else {
+               reg_addr = (addr_t)&(gprs->rdi);
+           }
+           break;
+       default:
+           reg_addr = 0;
+           break;
+    }
+
+    return reg_addr;
+}
+
+
+
+static inline v3_operand_type_t decode_operands16(struct v3_gprs * gprs, // input/output
+                                                 char * modrm_instr,       // input
+                                                 int * offset,             // output
+                                                 addr_t * first_operand,   // output
+                                                 addr_t * second_operand,  // output
+                                                 reg_size_t reg_size) {    // input
+  
+    struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
+    addr_t base_addr = 0;
+    modrm_mode_t mod_mode = 0;
+    v3_operand_type_t addr_type = INVALID_OPERAND;
+    char * instr_cursor = modrm_instr;
+
+    //  PrintDebug("ModRM mod=%d\n", modrm->mod);
+
+    instr_cursor += 1;
+
+    if (modrm->mod == 3) {
+       mod_mode = REG;
+       addr_type = REG_OPERAND;
+       //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
+
+       *first_operand = decode_register(gprs, modrm->rm, reg_size);
+
+    } else {
+
+       addr_type = MEM_OPERAND;
+
+       if (modrm->mod == 0) {
+           mod_mode = DISP0;
+       } else if (modrm->mod == 1) {
+           mod_mode = DISP8;
+       } else if (modrm->mod == 2) {
+           mod_mode = DISP16;
+       }
+
+       switch (modrm->rm) {
+           case 0:
+               base_addr = gprs->rbx + gprs->rsi;
+               break;
+           case 1:
+               base_addr = gprs->rbx + gprs->rdi;
+               break;
+           case 2:
+               base_addr = gprs->rbp + gprs->rsi;
+               break;
+           case 3:
+               base_addr = gprs->rbp + gprs->rdi;
+               break;
+           case 4:
+               base_addr = gprs->rsi;
+               break;
+           case 5:
+               base_addr = gprs->rdi;
+               break;
+           case 6:
+               if (modrm->mod == 0) {
+                   base_addr = 0;
+                   mod_mode = DISP16;
+               } else {
+                   base_addr = gprs->rbp;
+               }
+               break;
+           case 7:
+               base_addr = gprs->rbx;
+               break;
+       }
+
+
+
+       if (mod_mode == DISP8) {
+           base_addr += (uchar_t)*(instr_cursor);
+           instr_cursor += 1;
+       } else if (mod_mode == DISP16) {
+           base_addr += (ushort_t)*(instr_cursor);
+           instr_cursor += 2;
+       }
+    
+       *first_operand = base_addr;
+    }
+
+    *offset +=  (instr_cursor - modrm_instr);
+    *second_operand = decode_register(gprs, modrm->reg, reg_size);
+
+    return addr_type;
+}
+
+
+
+static inline v3_operand_type_t decode_operands32(struct v3_gprs * gprs, // input/output
+                                                 uchar_t * modrm_instr,       // input
+                                                 int * offset,             // output
+                                                 addr_t * first_operand,   // output
+                                                 addr_t * second_operand,  // output
+                                                 reg_size_t reg_size) {    // input
+  
+    uchar_t * instr_cursor = modrm_instr;
+    struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
+    addr_t base_addr = 0;
+    modrm_mode_t mod_mode = 0;
+    uint_t has_sib_byte = 0;
+    v3_operand_type_t addr_type = INVALID_OPERAND;
+
+
+
+    instr_cursor += 1;
+
+    if (modrm->mod == 3) {
+       mod_mode = REG;
+       addr_type = REG_OPERAND;
+    
+       //    PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
+
+       *first_operand = decode_register(gprs, modrm->rm, reg_size);
+
+    } else {
+
+       addr_type = MEM_OPERAND;
+
+       if (modrm->mod == 0) {
+           mod_mode = DISP0;
+       } else if (modrm->mod == 1) {
+           mod_mode = DISP8;
+       } else if (modrm->mod == 2) {
+           mod_mode = DISP32;
+       }
+    
+       switch (modrm->rm) {
+           case 0:
+               base_addr = gprs->rax;
+               break;
+           case 1:
+               base_addr = gprs->rcx;
+               break;
+           case 2:
+               base_addr = gprs->rdx;
+               break;
+           case 3:
+               base_addr = gprs->rbx;
+               break;
+           case 4:
+               has_sib_byte = 1;
+               break;
+           case 5:
+               if (modrm->mod == 0) {
+                   base_addr = 0;
+                   mod_mode = DISP32;
+               } else {
+                   base_addr = gprs->rbp;
+               }
+               break;
+           case 6:
+               base_addr = gprs->rsi;
+               break;
+           case 7:
+               base_addr = gprs->rdi;
+               break;
+       }
+
+       if (has_sib_byte) {
+           instr_cursor += 1;
+           struct sib_byte * sib = (struct sib_byte *)(instr_cursor);
+           int scale = 1;
+
+           instr_cursor += 1;
+
+
+           if (sib->scale == 1) {
+               scale = 2;
+           } else if (sib->scale == 2) {
+               scale = 4;
+           } else if (sib->scale == 3) {
+               scale = 8;
+           }
+
+
+           switch (sib->index) {
+               case 0:
+                   base_addr = gprs->rax;
+                   break;
+               case 1:
+                   base_addr = gprs->rcx;
+                   break;
+               case 2:
+                   base_addr = gprs->rdx;
+                   break;
+               case 3:
+                   base_addr = gprs->rbx;
+                   break;
+               case 4:
+                   base_addr = 0;
+                   break;
+               case 5:
+                   base_addr = gprs->rbp;
+                   break;
+               case 6:
+                   base_addr = gprs->rsi;
+                   break;
+               case 7:
+                   base_addr = gprs->rdi;
+                   break;
+           }
+
+           base_addr *= scale;
+
+
+           switch (sib->base) {
+               case 0:
+                   base_addr += gprs->rax;
+                   break;
+               case 1:
+                   base_addr += gprs->rcx;
+                   break;
+               case 2:
+                   base_addr += gprs->rdx;
+                   break;
+               case 3:
+                   base_addr += gprs->rbx;
+                   break;
+               case 4:
+                   base_addr += gprs->rsp;
+                   break;
+               case 5:
+                   if (modrm->mod != 0) {
+                       base_addr += gprs->rbp;
+                   }
+                   break;
+               case 6:
+                   base_addr += gprs->rsi;
+                   break;
+               case 7:
+                   base_addr += gprs->rdi;
+                   break;
+           }
+
+       } 
+
+
+       if (mod_mode == DISP8) {
+           base_addr += (uchar_t)*(instr_cursor);
+           instr_cursor += 1;
+       } else if (mod_mode == DISP32) {
+           base_addr += (uint_t)*(instr_cursor);
+           instr_cursor += 4;
+       }
+    
+
+       *first_operand = base_addr;
+    }
+
+    *offset += (instr_cursor - modrm_instr);
+
+    *second_operand = decode_register(gprs, modrm->reg, reg_size);
+
+    return addr_type;
+}
+
+
+
+static inline op_form_t op_code_to_form_0f(uint8_t * instr) {
+    switch (instr[1]) {
+       case 0x01: {
+           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[2]);
+
+           switch (modrm->reg) {
+               case 4:
+                   return SMSW;
+               case 6:
+                   return LMSW;
+               case 7:
+                   return INVLPG;
+               default:
+                   return INVALID_INSTR;
+           }
+       }
+
+       case 0x06:
+           return CLTS;
+       case 0x20:
+           return MOV_CR2;
+       case 0x21:
+           return MOV_DR2;
+
+       case 0x22:
+           return MOV_2CR;
+       case 0x23:
+           return MOV_2DR;
+
+       case 0x90:
+           return SETO;
+       case 0x91:
+           return SETNO;
+       case 0x92:
+           return SETB;
+       case 0x93:
+           return SETNB;
+       case 0x94:
+           return SETZ;
+       case 0x95:
+           return SETNZ;
+       case 0x96:
+           return SETBE;
+       case 0x97:
+           return SETNBE;
+       case 0x98:
+           return SETS;
+       case 0x99:
+           return SETNS;
+       case 0x9a:
+           return SETP;
+       case 0x9b:
+           return SETNP;
+       case 0x9c:
+           return SETL;
+       case 0x9d:
+           return SETNL;
+       case 0x9e:
+           return SETLE;
+       case 0x9f:
+           return SETNLE;
+
+       case 0xb6:
+           return MOVZX_8;
+       case 0xb7:
+           return MOVZX;
+
+       case 0xbe:
+           return MOVSX_8;
+       case 0xbf:
+           return MOVSX;
+           
+
+       default:
+           return INVALID_INSTR;
+    }
+}
+
+
+static op_form_t op_code_to_form(uint8_t * instr) {
+    switch (instr[0]) {
+       case 0x00:
+           return ADD_2MEM_8;
+       case 0x01:
+           return ADD_2MEM;
+       case 0x02:
+           return ADD_MEM2_8;
+       case 0x03:
+           return ADD_MEM2;
+
+       case 0x08:
+           return OR_2MEM_8;
+       case 0x09:
+           return OR_2MEM;
+       case 0x0a:
+           return OR_MEM2_8;
+       case 0x0b:
+           return OR_MEM2;
+
+
+       case 0x0f:
+           return op_code_to_form_0f(instr);
+
+       case 0x10:
+           return ADC_2MEM_8;
+       case 0x11:
+           return ADC_2MEM;
+       case 0x12:
+           return ADC_MEM2_8;
+       case 0x13:
+           return ADC_MEM2;
+
+       case 0x20:
+           return AND_2MEM_8; 
+       case 0x21:
+           return AND_2MEM;
+       case 0x22:
+           return AND_MEM2_8;
+       case 0x23:
+           return AND_MEM2;
+
+       case 0x28:
+           return SUB_2MEM_8;
+       case 0x29:
+           return SUB_2MEM;
+       case 0x2a:
+           return SUB_MEM2_8;
+       case 0x2b:
+           return SUB_MEM2;
+
+
+       case 0x30:
+           return XOR_2MEM_8;
+       case 0x31:
+           return XOR_2MEM;
+       case 0x32:
+           return XOR_MEM2_8;
+       case 0x33:
+           return XOR_MEM2;
+
+       case 0x80:{
+           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+
+           switch (modrm->reg) {
+               case 0:
+                   return ADD_IMM2_8;
+               case 1:
+                   return OR_IMM2_8;
+               case 2:
+                   return ADC_IMM2_8;
+               case 4:
+                   return AND_IMM2_8;
+               case 5:
+                   return SUB_IMM2_8;
+               case 6:
+                   return XOR_IMM2_8;
+               default:
+                   return INVALID_INSTR;
+           }
+       }
+       case 0x81: {
+           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+           
+           switch (modrm->reg) {
+               case 0:
+                   return ADD_IMM2;
+               case 1:
+                   return OR_IMM2;
+               case 2:
+                   return ADC_IMM2;
+               case 4:
+                   return AND_IMM2;
+               case 5:
+                   return SUB_IMM2;
+               case 6:
+                   return XOR_IMM2;
+               default:
+                   return INVALID_INSTR;
+           }
+       }
+       case 0x83: {
+           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+
+           switch (modrm->reg) {
+               case 0:
+                   return ADD_IMM2SX_8;
+               case 1:
+                   return OR_IMM2SX_8;
+               case 2:
+                   return ADC_IMM2SX_8;
+               case 4:
+                   return AND_IMM2SX_8;
+               case 5:
+                   return SUB_IMM2SX_8;
+               case 6:
+                   return XOR_IMM2SX_8;
+               default:
+                   return INVALID_INSTR;
+           }
+       }
+
+       case 0x86:
+           return XCHG_8;
+       case 0x87:
+           return XCHG;
+       case 0x88:
+           return MOV_2GPR_8;
+       case 0x89:
+           return MOV_2GPR;
+       case 0x8a:
+           return MOV_GPR2_8;
+       case 0x8b:
+           return MOV_GPR2;
+           
+       case 0x8c:
+           return MOV_SR2;
+       case 0x8e:
+           return MOV_2SR;
+
+
+       case 0x9c:
+           return PUSHF;
+       case 0x9d:
+           return POPF;
+
+       case 0xa0:
+           return MOV_MEM2AL_8;
+       case 0xa1:
+           return MOV_MEM2AX;
+       case 0xa2:
+           return MOV_AL2MEM_8;
+       case 0xa3:
+           return MOV_AX2MEM;
+
+       case 0xa4:
+           return MOVS_8;
+       case 0xa5:
+           return MOVS;
+
+       case 0xaa:
+           return STOS_8;
+       case 0xab:
+           return STOS;
+
+       case 0xc6:
+           return MOV_IMM2_8;
+       case 0xc7:
+           return MOV_IMM2;
+
+       case 0xf4:
+           return HLT;
+
+
+       case 0xf6: {
+           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+
+           switch (modrm->reg) {
+               case 2:
+                   return NOT_8;
+               case 3:
+                   return NEG_8;
+               default:
+                   return INVALID_INSTR;
+           }
+       }
+       case 0xf7: {
+           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+
+           switch (modrm->reg) {
+               case 2:
+                   return NOT;
+               case 3:
+                   return NEG;
+               default:
+                   return INVALID_INSTR;
+           }
+       }
+           
+
+       case 0xfe: {
+           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+
+           switch (modrm->reg) {
+               case 0:
+                   return INC_8;
+               case 1:
+                   return DEC_8;
+               default:
+                   return INVALID_INSTR;
+           }
+       }
+
+       case 0xff: {
+           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+
+           switch (modrm->reg) {
+               case 0:
+                   return INC;
+               case 1:
+                   return DEC;
+               default:
+                   return INVALID_INSTR;
+           }
+       }
+
+       default:
+           return INVALID_INSTR;
+    }
+}
+
+int v3_disasm(struct guest_info * info, void *instr_ptr, addr_t * rip, int mark) {
+    return 0;
+}
+
+
+
+int v3_init_decoder(struct guest_info * core) { 
+    return 0;
+}
+
+
+int v3_deinit_decoder(struct guest_info * core) {
+    return 0;
+}
+
+
+int v3_encode(struct guest_info * info, struct x86_instr * instr, char * instr_buf) {
+    return 0;
+}
+
+int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * instr) {
+    op_code_to_form((void *)instr_ptr);
+
+    return 0;
+}
 
 }
 
 
-int v3_basic_mem_decode(struct guest_info * info, addr_t instr_ptr, struct basic_instr_info * instr_info) {
-    xed_decoded_inst_t xed_instr;
-    xed_error_enum_t xed_error;
-  
-
-    if (set_decoder_mode(info, info->decoder_state) == -1) {
-       PrintError("Could not set decoder mode\n");
-       return -1;
-    }
-
-
-    xed_decoded_inst_zero_set_mode(&xed_instr, info->decoder_state);
-
-    xed_error = xed_decode(&xed_instr, 
-                          REINTERPRET_CAST(const xed_uint8_t *, instr_ptr), 
-                          XED_MAX_INSTRUCTION_BYTES);
-
-    if (xed_error != XED_ERROR_NONE) {
-       PrintError("Xed error: %s\n", xed_error_enum_t2str(xed_error));
-       return -1;
-    }
-
-    instr_info->instr_length = xed_decoded_inst_get_length(&xed_instr);
-
-
-    if (xed_decoded_inst_number_of_memory_operands(&xed_instr) == 0) {
-       PrintError("Tried to decode memory operation with no memory operands\n");
-       return -1;
-    }
-
-    instr_info->op_size = xed_decoded_inst_get_memory_operand_length(&xed_instr, 0);
-
-
-    xed_category_enum_t cat = xed_decoded_inst_get_category(&xed_instr);
-    if (cat == XED_CATEGORY_STRINGOP) {
-       instr_info->str_op = 1;
-    } else {
-       instr_info->str_op = 0;
-    }
-
-    xed_operand_values_t * operands = xed_decoded_inst_operands(&xed_instr);
-    if (xed_operand_values_has_real_rep(operands)) {
-       instr_info->has_rep = 1;
-    } else {
-       instr_info->has_rep = 0;
-    }
-
-    return 0;
-}
 
 
 static int decode_string_op(struct guest_info * info,