Merges encoding branch (#1187)

* Added encoding field to instructions, as per encoding branch

The encoding branch appears to have added some useful fields
accessible from the public API, including the size and offsets
of displacements and immediates in instructions.  I needed access
to these fields, but the encoding branch is months behind the
active branches, so I took the minimum code from the old encoding
branch and put them into a more recent version of master.

It does seem that the most recent version does not have an offset
for the modRM byte in the InternalInstruction struct, so I did
not keep this field when bringing it to the more recent version.

I also added some of the changes made by user jellever, who added
support for accessing these new fields from the python bindings.

(cherry picked from commit d358c4b987cc77af90e24da15937e021c42f682f)

* Fixed bug with python bindings from adding encoding field

I had forgotten an import that resulted in failure when trying
to obtain instruction details.

(cherry picked from commit 44a15e378900efb624e7cdb952d32558ba0de684)

* promoted displacement to 64 bits

* Added modrm offset

* formatting from review fixed

* updated 32 bit C tests

* Added 64 and 16 bit C tests

* Updated python tests

* fixed formatting and size in py bindings

* Delete Solution.VC.db-shm

* Delete Solution.VC.db-wal

* Update test_x86.c

* fixed formatting and conditional prints

* fixed formatting
diff --git a/arch/X86/X86Disassembler.c b/arch/X86/X86Disassembler.c
index 2c2d680..f295845 100644
--- a/arch/X86/X86Disassembler.c
+++ b/arch/X86/X86Disassembler.c
@@ -759,12 +759,23 @@
 	pub->detail->x86.addr_size = inter->addressSize;
 
 	pub->detail->x86.modrm = inter->orgModRM;
-	pub->detail->x86.sib = inter->sib;
-	pub->detail->x86.disp = inter->displacement;
+	pub->detail->x86.encoding.modrm_offset = (inter->modRMLocation != 0) ? (inter->modRMLocation - inter->startLocation) : 0;
 
+	pub->detail->x86.sib = inter->sib;
 	pub->detail->x86.sib_index = x86_map_sib_index(inter->sibIndex);
 	pub->detail->x86.sib_scale = inter->sibScale;
 	pub->detail->x86.sib_base = x86_map_sib_base(inter->sibBase);
+
+	pub->detail->x86.disp = inter->displacement;
+	if (inter->consumedDisplacement) {
+		pub->detail->x86.encoding.disp_offset = inter->displacementOffset;
+		pub->detail->x86.encoding.disp_size = inter->displacementSize;
+	}
+
+	pub->detail->x86.encoding.imm_offset = inter->immediateOffset;
+	if (/*pub->detail->x86.encoding.imm_size == 0 && */inter->immediateOffset != 0) {
+		pub->detail->x86.encoding.imm_size = inter->immediateSize;
+	}
 }
 
 void X86_init(MCRegisterInfo *MRI)
@@ -812,6 +823,7 @@
 		memset(instr->flat_insn->detail->x86.prefix, 0, sizeof(instr->flat_insn->detail->x86.prefix));
 		memset(instr->flat_insn->detail->x86.opcode, 0, sizeof(instr->flat_insn->detail->x86.opcode));
 		memset(instr->flat_insn->detail->x86.operands, 0, sizeof(instr->flat_insn->detail->x86.operands));
+		memset(&instr->flat_insn->detail->x86.encoding, 0, sizeof(instr->flat_insn->detail->x86.encoding));
 	}
 
 	if (handle->mode & CS_MODE_16)
diff --git a/arch/X86/X86DisassemblerDecoder.c b/arch/X86/X86DisassemblerDecoder.c
index b4381b5..8c76420 100644
--- a/arch/X86/X86DisassemblerDecoder.c
+++ b/arch/X86/X86DisassemblerDecoder.c
@@ -1537,6 +1537,8 @@
 	if (insn->consumedModRM)
 		return 0;
 
+	insn->modRMLocation = insn->readerCursor;
+
 	if (consumeByte(insn, &insn->modRM))
 		return -1;
 
@@ -2044,7 +2046,7 @@
 					return -1;
 				// Apply the AVX512 compressed displacement scaling factor.
 				if (x86OperandSets[insn->spec->operands][index].encoding != ENCODING_REG && insn->eaDisplacement == EA_DISP_8)
-					insn->displacement *= 1 << (x86OperandSets[insn->spec->operands][index].encoding - ENCODING_RM);
+					insn->displacement *= (int64_t)1 << (x86OperandSets[insn->spec->operands][index].encoding - ENCODING_RM);
 				break;
 			case ENCODING_CB:
 			case ENCODING_CW:
@@ -2088,6 +2090,14 @@
 			case ENCODING_Ia:
 				if (readImmediate(insn, insn->addressSize))
 					return -1;
+				/* Direct memory-offset (moffset) immediate will get mapped
+				   to memory operand later. We want the encoding info to
+				   reflect that as well. */
+				insn->displacementOffset = insn->immediateOffset;
+				insn->displacementSize = insn->immediateSize;
+				insn->displacement = insn->immediates[insn->numImmediatesConsumed - 1];
+				insn->immediateOffset = 0;
+				insn->immediateSize = 0;
 				break;
 			case ENCODING_RB:
 				if (readOpcodeRegister(insn, 1))
@@ -2356,6 +2366,7 @@
 	insn->reader = reader;
 	insn->readerArg = readerArg;
 	insn->startLocation = startLoc;
+	insn->modRMLocation = 0;
 	insn->readerCursor = startLoc;
 	insn->mode = mode;
 
diff --git a/arch/X86/X86DisassemblerDecoder.h b/arch/X86/X86DisassemblerDecoder.h
index a022be5..5953e3d 100644
--- a/arch/X86/X86DisassemblerDecoder.h
+++ b/arch/X86/X86DisassemblerDecoder.h
@@ -589,7 +589,7 @@
   uint8_t                       sib;
   /* The displacement, used for memory operands */
   bool                          consumedDisplacement;
-  int32_t                       displacement;
+  int64_t                       displacement;
   /* The value of the two-byte escape prefix (usually 0x0f) */
   uint8_t twoByteEscape;
   /* The value of the three-byte escape prefix (usually 0x38 or 0x3a) */
@@ -680,6 +680,9 @@
      all memory operands */
   uint8_t                       modRM;
 
+  /* contains the location (for use with the reader) of the modRM byte */
+  uint64_t                      modRMLocation;
+
   // special data to handle MOVcr, MOVdr, MOVrc, MOVrd
   uint8_t                       firstByte;     // save the first byte in stream
 
diff --git a/bindings/python/capstone/__init__.py b/bindings/python/capstone/__init__.py
index ec8a9ff..de6e0c1 100644
--- a/bindings/python/capstone/__init__.py
+++ b/bindings/python/capstone/__init__.py
@@ -552,7 +552,7 @@
             (self.prefix, self.opcode, self.rex, self.addr_size, \
                 self.modrm, self.sib, self.disp, \
                 self.sib_index, self.sib_scale, self.sib_base, self.sse_cc, \
-                self.avx_cc, self.avx_sae, self.avx_rm, self.operands) = x86.get_arch_info(self._detail.arch.x86)
+                self.avx_cc, self.avx_sae, self.avx_rm, self.operands, self.encoding) = x86.get_arch_info(self._detail.arch.x86)
         elif arch == CS_ARCH_MIPS:
                 self.operands = mips.get_arch_info(self._detail.arch.mips)
         elif arch == CS_ARCH_PPC:
diff --git a/bindings/python/capstone/x86.py b/bindings/python/capstone/x86.py
index dd393a7..479060c 100644
--- a/bindings/python/capstone/x86.py
+++ b/bindings/python/capstone/x86.py
@@ -1,7 +1,7 @@
 # Capstone Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
 
 import ctypes
-from . import copy_ctypes_list
+from . import copy_ctypes, copy_ctypes_list
 from .x86_const import *
 
 # define the API
@@ -47,6 +47,14 @@
     def mem(self):
         return self.value.mem
 
+class CsX86Encoding(ctypes.Structure):
+    _fields_ = (
+        ('modrm_offset', ctypes.c_uint8),
+        ('disp_offset', ctypes.c_uint8),
+        ('disp_size', ctypes.c_uint8),
+        ('imm_offset', ctypes.c_uint8),
+        ('imm_size', ctypes.c_uint8),
+    )
 
 class CsX86(ctypes.Structure):
     _fields_ = (
@@ -66,11 +74,13 @@
         ('avx_rm', ctypes.c_uint),
         ('op_count', ctypes.c_uint8),
         ('operands', X86Op * 8),
+        ('encoding', CsX86Encoding),
     )
 
 def get_arch_info(a):
     return (a.prefix[:], a.opcode[:], a.rex, a.addr_size, \
             a.modrm, a.sib, a.disp, a.sib_index, a.sib_scale, \
             a.sib_base, a.sse_cc, a.avx_cc, a.avx_sae, a.avx_rm, \
-            copy_ctypes_list(a.operands[:a.op_count]))
+            copy_ctypes_list(a.operands[:a.op_count]), \
+            copy_ctypes(a.encoding))
 
diff --git a/bindings/python/test_x86.py b/bindings/python/test_x86.py
index 6d2aa50..c89ea7c 100755
--- a/bindings/python/test_x86.py
+++ b/bindings/python/test_x86.py
@@ -7,9 +7,9 @@
 from xprint import to_hex, to_x, to_x_32
 
 
-X86_CODE64 = b"\x55\x48\x8b\x05\xb8\x13\x00\x00"
-X86_CODE16 = b"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6"
-X86_CODE32 = b"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6"
+X86_CODE64 = b"\x55\x48\x8b\x05\xb8\x13\x00\x00\xe9\xea\xbe\xad\xde\xff\x25\x23\x01\x00\x00\xe8\xdf\xbe\xad\xde\x74\xff"
+X86_CODE16 = b"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6\x66\xe9\xb8\x00\x00\x00\x67\xff\xa0\x23\x01\x00\x00\x66\xe8\xcb\x00\x00\x00\x74\xfc"
+X86_CODE32 = b"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6\xe9\xea\xbe\xad\xde\xff\xa0\x23\x01\x00\x00\xe8\xdf\xbe\xad\xde\x74\xff"
 
 all_tests = (
         (CS_ARCH_X86, CS_MODE_16, X86_CODE16, "X86 16bit (Intel syntax)", 0),
@@ -47,10 +47,22 @@
 
     # print modRM byte
     print("\tmodrm: 0x%x" % (insn.modrm))
-
+    
+    # print modRM offset
+    if insn.modrm_offset != 0:
+        print("\tmodrm_offset: 0x%x" % (insn.modrm_offset))
+    
     # print displacement value
     print("\tdisp: 0x%s" % to_x_32(insn.disp))
 
+    # print displacement offset (offset into instruction bytes)
+    if insn.disp_offset != 0:
+        print("\tdisp_offset: 0x%x" % (insn.disp_offset))
+    
+    # print displacement size
+    if insn.disp_size != 0:
+        print("\tdisp_size: 0x%x" % (insn.disp_size))
+    
     # SIB is not available in 16-bit mode
     if (mode & CS_MODE_16 == 0):
         # print SIB byte
@@ -85,6 +97,10 @@
         for i in range(count):
             op = insn.op_find(X86_OP_IMM, i + 1)
             print("\t\timms[%u]: 0x%s" % (i + 1, to_x(op.imm)))
+            if insn.imm_offset != 0:
+                print("\timm_offset: 0x%x" % (insn.imm_offset))
+            if insn.imm_size != 0:
+                print("\timm_size: 0x%x" % (insn.imm_size))
 
     if len(insn.operands) > 0:
         print("\top_count: %u" % len(insn.operands))
diff --git a/include/x86.h b/include/x86.h
index 2dd162b..e46bb90 100644
--- a/include/x86.h
+++ b/include/x86.h
@@ -203,6 +203,19 @@
 		bool avx_zero_opmask;
 } cs_x86_op;
 
+typedef struct cs_x86_encoding {
+	// ModR/M offset, or 0 when irrelevant
+	uint8_t modrm_offset;
+
+	// Displacement offset, or 0 when irrelevant.
+	uint8_t disp_offset;
+	uint8_t disp_size;
+
+	// Immediate offset, or 0 when irrelevant.
+	uint8_t imm_offset;
+	uint8_t imm_size;
+} cs_x86_encoding;
+
 // Instruction structure
 typedef struct cs_x86 {
 	// Instruction prefix, which can be up to 4 bytes.
@@ -259,6 +272,8 @@
 	uint8_t op_count;
 
 	cs_x86_op operands[8];	// operands for this instruction.
+
+	cs_x86_encoding encoding; // encoding information
 } cs_x86;
 
 //> X86 instructions
diff --git a/tests/test_x86.c b/tests/test_x86.c
index 43c4c7e..8b2cef7 100644
--- a/tests/test_x86.c
+++ b/tests/test_x86.c
@@ -50,7 +50,19 @@
 
 	printf("\taddr_size: %u\n", x86->addr_size);
 	printf("\tmodrm: 0x%x\n", x86->modrm);
+	if (x86->encoding.modrm_offset != 0) {
+		printf("\tmodrm_offset: 0x%x\n", x86->encoding.modrm_offset);
+	}
+	
 	printf("\tdisp: 0x%x\n", x86->disp);
+	
+	if (x86->encoding.disp_offset != 0) {
+		printf("\tdisp_offset: 0x%x\n", x86->encoding.disp_offset);
+	}
+	
+	if (x86->encoding.disp_size != 0) {
+	    printf("\tdisp_size: 0x%x\n", x86->encoding.disp_size);
+	}
 
 	// SIB is not available in 16-bit mode
 	if ((mode & CS_MODE_16) == 0) {
@@ -89,6 +101,14 @@
 		for (i = 1; i < count + 1; i++) {
 			int index = cs_op_index(ud, ins, X86_OP_IMM, i);
 			printf("\t\timms[%u]: 0x%" PRIx64 "\n", i, x86->operands[index].imm);
+			
+			if (x86->encoding.imm_offset != 0) {
+				printf("\timm_offset: 0x%x\n", x86->encoding.imm_offset);
+			}
+			
+			if (x86->encoding.imm_size != 0) {
+				printf("\timm_size: 0x%x\n", x86->encoding.imm_size);
+			}
 		}
 	}
 
@@ -145,12 +165,12 @@
 //#define X86_CODE32 "\xa1\x13\x48\x6d\x3a\x8b\x81\x23\x01\x00\x00\x8b\x84\x39\x23\x01\x00\x00"
 //#define X86_CODE32 "\xb4\xc6"	// mov	ah, 0x6c
 //#define X86_CODE32 "\x77\x04"	// ja +6
-#define X86_CODE64 "\x55\x48\x8b\x05\xb8\x13\x00\x00"
+#define X86_CODE64 "\x55\x48\x8b\x05\xb8\x13\x00\x00\xe9\xea\xbe\xad\xde\xff\x25\x23\x01\x00\x00\xe8\xdf\xbe\xad\xde\x74\xff"
 //#define X86_CODE64 "\xe9\x79\xff\xff\xff"	// jmp 0xf7e
 
-#define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6"
+#define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6\x66\xe9\xb8\x00\x00\x00\x67\xff\xa0\x23\x01\x00\x00\x66\xe8\xcb\x00\x00\x00\x74\xfc"
 //#define X86_CODE16 "\x67\x00\x18"
-#define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6"
+#define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6\xe9\xea\xbe\xad\xde\xff\xa0\x23\x01\x00\x00\xe8\xdf\xbe\xad\xde\x74\xff"
 //#define X86_CODE32 "\x0f\xa7\xc0"	// xstorerng
 //#define X86_CODE32 "\x64\xa1\x18\x00\x00\x00"	// mov eax, dword ptr fs:[18]
 //#define X86_CODE32 "\x64\xa3\x00\x00\x00\x00"	// mov [fs:0x0], eax