Initial commit
authorBernhard Urban <lewurm@gmail.com>
Sat, 19 May 2012 09:42:39 +0000 (11:42 +0200)
committerBernhard Urban <lewurm@gmail.com>
Sat, 19 May 2012 09:42:39 +0000 (11:42 +0200)
0.1.0.1

LICENSE [new file with mode: 0644]
Setup.lhs [new file with mode: 0644]
Text/Disassembler/X86Disassembler.hs [new file with mode: 0644]
disassembler.cabal [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..01088ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) Dirk Kleeblatt and Martin Grabmueller
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644 (file)
index 0000000..5bde0de
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/Text/Disassembler/X86Disassembler.hs b/Text/Disassembler/X86Disassembler.hs
new file mode 100644 (file)
index 0000000..470200c
--- /dev/null
@@ -0,0 +1,3285 @@
+--------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Disassembler.X86Disassembler
+-- Copyright   :  (c) Martin Grabmueller and Dirk Kleeblatt
+-- License     :  BSD3
+-- 
+-- Maintainer  :  martin@grabmueller.de,klee@cs.tu-berlin.de
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- Disassembler for x86 machine code.
+--
+-- This is a disassembler for object code for the x86 architecture.
+-- It provides functions for disassembling byte arrays, byte lists and
+-- memory blocks containing raw binary code.
+-- 
+-- Features:
+--
+-- - Disassembles memory blocks, lists or arrays of bytes into lists of
+--   instructions.
+--
+-- - Abstract instructions provide as much information as possible about
+--   opcodes, addressing modes or operand sizes, allowing for detailed
+--   output.
+--
+-- - Provides functions for displaying instructions in Intel or AT&T
+--   style (like the GNU tools)
+--
+-- Differences to GNU tools, like gdb or objdump:
+--
+-- - Displacements are shown in decimal, with sign if negative.
+--
+-- Missing: 
+--
+-- - LOCK and repeat prefixes are recognized, but not contained in the
+--   opcodes of instructions.
+--
+-- - Support for 16-bit addressing modes.  Could be added when needed.
+--
+-- - Complete disassembly of all 64-bit instructions.  I have tried to
+--   disassemble them properly but have been limited to the information
+--   in the docs, because I have no 64-bit machine to test on.  This will
+--   probably change when I get GNU as to produce 64-bit object files.
+--
+-- - Not all MMX and SSE/SSE2/SSE3 instructions are decoded yet.  This is
+--   just a matter of missing time.
+--
+-- - segment override prefixes are decoded, but not appended to memory
+--   references
+--
+-- On the implementation:
+--
+-- This disassembler uses the Parsec parser combinators, working on byte
+-- lists.  This proved to be very convenient, as the combinators keep
+-- track of the current position, etc.
+--------------------------------------------------------------------------
+
+module Text.Disassembler.X86Disassembler(
+  -- * Types
+  Opcode,
+  Operand(..),
+  InstrOperandSize(..),
+  Instruction(..),
+  ShowStyle(..),
+  Config(..),
+  -- * Functions
+  disassembleBlock,
+  disassembleList,
+  disassembleArray,
+  disassembleFile,
+  disassembleBlockWithConfig,
+  disassembleListWithConfig,
+  disassembleArrayWithConfig,
+  disassembleFileWithConfig,
+  showIntel,
+  showAtt,
+  defaultConfig
+  ) where
+
+import Text.ParserCombinators.Parsec
+import Control.Monad.State
+import System.IO
+import Data.List
+import Data.Char
+import Data.Array.IArray
+import Numeric
+import Foreign
+
+-- | All opcodes are represented by this enumeration type.
+
+data Opcode = InvalidOpcode
+           | AAA
+           | AAD
+           | AAM
+           | AAS
+           | ADC
+           | ADD
+           | ADDPD
+           | ADDPS
+           | ADDSD
+           | ADDSS
+           | ADDSUBPD
+           | ADDUBPS
+           | AND
+           | ANDNPD
+           | ANDNPS
+           | ANDPD
+           | ANDPS
+           | ARPL
+           | BOUND
+           | BSF
+           | BSR
+           | BT
+           | BTC
+           | BTR
+           | BTS
+           | CALL
+           | CALLF
+           | CBW
+           | CDQ
+           | CDQE
+           | CLC
+           | CLD
+           | CLFLUSH
+           | CLI
+           | CLTS
+           | CMC
+           | CMOVA
+           | CMOVB
+           | CMOVBE
+           | CMOVE
+           | CMOVG
+           | CMOVGE
+           | CMOVL
+           | CMOVLE
+           | CMOVNB
+           | CMOVNE
+           | CMOVNO
+           | CMOVNP
+           | CMOVNS
+           | CMOVO
+           | CMOVP
+           | CMOVS
+           | CMP
+           | CMPS
+           | CMPXCHG
+           | CMPXCHG16B
+           | CMPXCHG8B
+           | COMISD
+           | COMISS
+           | CPUID
+           | CWD
+           | CWDE
+           | DAA
+           | DAS
+           | DEC
+           | DIV
+           | DIVPD
+           | DIVPS
+           | DIVSD
+           | DIVSS
+           | EMMS
+           | ENTER
+           | FABS
+           | FADD
+           | FADDP
+           | FBLD
+           | FBSTP
+           | FCHS
+           | FCLEX
+           | FCMOVB
+           | FCMOVBE
+           | FCMOVE
+           | FCMOVNB
+           | FCMOVNBE
+           | FCMOVNE
+           | FCMOVNU
+           | FCMOVU
+           | FCOM
+           | FCOMI
+           | FCOMIP
+           | FCOMP
+           | FCOMPP
+           | FDIV
+           | FDIVP
+           | FDIVR
+           | FDIVRP
+           | FFREE
+           | FIADD
+           | FICOM
+           | FICOMP
+           | FIDIV
+           | FIDIVR
+           | FILD
+           | FIMUL
+           | FINIT
+           | FIST
+           | FISTP
+           | FISTPP
+           | FISTTP
+           | FISUB
+           | FISUBR
+           | FLD
+           | FLD1
+           | FLDCW
+           | FLDENV
+           | FLDL2E
+           | FLDL2T
+           | FLDLG2
+           | FLDLN2
+           | FLDPI
+           | FLDZ
+           | FMUL
+           | FMULP
+           | FNOP
+           | FRSTOR
+           | FSAVE
+           | FST
+           | FSTCW
+           | FSTENV
+           | FSTP
+           | FSTSW
+           | FSUB
+           | FSUBP
+           | FSUBR
+           | FSUBRP
+           | FTST
+           | FUCOM
+           | FUCOMI
+           | FUCOMIP
+           | FUCOMP
+           | FUCOMPP
+           | FXAM
+           | FXCH
+           | FXRSTOR
+           | FXSAVE
+           | HADDPD
+           | HADDPS
+           | HLT
+           | HSUBPD
+           | HSUBPS
+           | IDIV
+           | IMUL
+           | BSWAP
+           | IN
+           | INC
+           | INS
+           | INT
+           | INT3
+           | INTO
+           | INVD
+           | INVLPG
+           | IRET
+           | JA
+           | JB
+           | JBE
+           | JCXZ
+           | JE
+           | JG
+           | JGE
+           | JL
+           | JLE
+           | JMP
+           | JMPF
+           | JMPN
+           | JNB
+           | JNE
+           | JNO
+           | JNP
+           | JNS
+           | JO
+           | JP
+           | JS
+           | LAHF
+           | LAR
+           | LDDQU
+           | LDMXCSR
+           | LDS
+           | LEA
+           | LEAVE
+           | LES
+           | LFENCE
+           | LFS
+           | LGDT
+           | LGS
+           | LIDT
+           | LLDT
+           | LMSW
+           | LODS
+           | LOOP
+           | LOOPE
+           | LOOPNE
+           | LSL
+           | LSS
+           | LTR
+           | MASKMOVQ
+           | MAXPD
+           | MAXPS
+           | MAXSD
+           | MAXSS
+           | MFENCE
+           | MINPD
+           | MINPS
+           | MINSD
+           | MINSS
+           | MONITOR
+           | MOV 
+           | MOVAPD
+           | MOVAPS
+           | MOVDDUP
+           | MOVHPD
+           | MOVHPS
+           | MOVLHPS
+           | MOVLPD
+           | MOVLPS
+           | MOVLSDUP
+           | MOVMSKPD
+           | MOVMSKPS
+           | MOVNTDQ
+           | MOVNTPD
+           | MOVNTPS
+           | MOVNTQ
+           | MOVQ
+           | MOVS
+           | MOVSD
+           | MOVSLDUP
+           | MOVSS
+           | MOVSXB
+           | MOVSXD
+           | MOVSXW
+           | MOVUPD
+           | MOVUPS
+           | MOVZXB
+           | MOVZXW
+           | MUL
+           | MULPD
+           | MULPS
+           | MULSD
+           | MULSS
+           | MWAIT
+           | NEG
+           | NOP
+           | NOT
+           | OR
+           | ORPD
+           | ORPS
+           | OUT
+           | OUTS
+           | PADDB
+           | PADDD
+           | PADDQ
+           | PADDSB
+           | PADDSW
+           | PADDUSB
+           | PADDUSW
+           | PADDW
+           | PAND
+           | PANDN
+           | PAUSE
+           | PAVGB
+           | PAVGW
+           | PMADDWD
+           | PMAXSW
+           | PMAXUB
+           | PMINSW
+           | PMINUB
+           | PMOVMSKB
+           | PMULHUW
+           | PMULHW
+           | PMULLW
+           | PMULUDQ
+           | POP
+           | POPA
+           | POPAD
+           | POPF
+           | POPFD
+           | POPFQ
+           | POR
+           | PREFETCHNTA
+           | PREFETCHT0
+           | PREFETCHT1
+           | PREFETCHT2
+           | PSADBW
+           | PSLLD
+           | PSLLDQ
+           | PSLLQ
+           | PSLLW
+           | PSRAD
+           | PSRAW
+           | PSRLD
+           | PSRLDQ
+           | PSRLQ
+           | PSRLW
+           | PSUBB
+           | PSUBD
+           | PSUBQ
+           | PSUBSB
+           | PSUBSQ
+           | PSUBUSB
+           | PSUBUSW
+           | PSUBW
+           | PUSH
+           | PUSHA
+           | PUSHAD
+           | PUSHF
+           | PUSHFD
+           | PUSHFQ
+           | PXOR
+           | RCL
+           | RCPPS
+           | RCPSS
+           | RCR
+           | RDMSR
+           | RDPMC
+           | RDTSC
+           | RET
+           | RETF
+           | ROL
+           | ROR
+           | RSM
+           | RSQRTPS
+           | RSQRTSS
+           | SAHF
+           | SAR
+           | SBB
+           | SCAS
+           | SETA
+           | SETB
+           | SETBE
+           | SETE
+           | SETG
+           | SETGE
+           | SETL
+           | SETLE
+           | SETNB
+           | SETNE
+           | SETNO
+           | SETNP
+           | SETNS
+           | SETO
+           | SETP
+           | SETS
+           | SFENCE
+           | SGDT
+           | SHL
+           | SHLD
+           | SHR
+           | SHRD
+           | SIDT
+           | SLDT
+           | SMSW
+           | SQRTPD
+           | SQRTPS
+           | SQRTSD
+           | SQRTSS
+           | STC
+           | STD
+           | STI
+           | STMXCSR
+           | STOS
+           | STR
+           | SUB
+           | SUBPD
+           | SUBPS
+           | SUBSD
+           | SUBSS
+           | SWAPGS
+           | SYSCALL
+           | SYSENTER
+           | SYSEXIT
+           | TEST
+           | UCOMISD
+           | UCOMISS
+           | UD2
+           | UNPCKHPD
+           | UNPCKHPS
+           | UNPCKLPD
+           | UNPCKLPS
+           | VERR
+           | VERW
+           | VMCALL
+           | VMCLEAR
+           | VMLAUNCH
+           | VMPTRLD
+           | VMPTRST
+           | VMREAD
+           | VMRESUME
+           | VMWRITE
+           | VMXOFF
+           | VMXON
+           | WAIT
+           | WBINVD
+           | WRMSR
+           | XADD
+           | XCHG
+           | XLAT
+           | XOR
+           | XORPD
+           | XORPS
+  deriving (Show, Eq)
+
+-- Display an opcode in lower case.
+
+showOp :: Opcode -> String
+showOp = (map toLower) . show
+
+-- | All operands are in one of the following locations:
+--
+-- - Constants in the instruction stream
+--
+-- - Memory locations
+--
+-- - Registers
+--
+-- Memory locations are referred to by on of several addressing modes:
+--
+-- - Absolute (address in instruction stream)
+--
+-- - Register-indirect (address in register)
+--
+-- - Register-indirect with displacement
+--
+-- - Base-Index with scale
+--
+-- - Base-Index with scale and displacement 
+--
+-- Displacements can be encoded as 8 or 32-bit immediates in the
+-- instruction stream, but are encoded as Int in instructions for
+-- simplicity.
+--
+data Operand = OpImm Word32            -- ^ Immediate value
+              | OpAddr Word32 InstrOperandSize -- ^ Absolute address
+              | OpReg String Int       -- ^ Register
+              | OpFPReg Int            -- ^ Floating-point register
+              | OpInd String InstrOperandSize -- ^Register-indirect
+              | OpIndDisp String Int InstrOperandSize
+               -- ^ Register-indirect with displacement
+              | OpBaseIndex String String Int InstrOperandSize
+                                       -- ^ Base plus scaled index
+              | OpIndexDisp String Int Int InstrOperandSize
+                        -- ^ Scaled index with displacement
+              | OpBaseIndexDisp String String Int Int InstrOperandSize
+                        -- ^ Base plus scaled index with displacement
+  deriving (Eq)
+
+-- Show an operand in AT&T style.
+
+showAttOps (OpImm w) = showImm w
+showAttOps (OpAddr w _) = showAddr w
+showAttOps (OpReg s num) = "%" ++ s
+showAttOps (OpFPReg 0) = "%st"
+showAttOps (OpFPReg i) = "%st(" ++ show i ++ ")"
+showAttOps (OpInd s _) = "(%" ++ s ++ ")"
+showAttOps (OpIndDisp s disp _) = show disp ++ "(%" ++ s ++ ")"
+showAttOps (OpBaseIndex b i s _) = "(%" ++ b ++ ",%" ++ i ++ "," ++ show s ++ ")"
+showAttOps (OpIndexDisp i s disp _) = show disp ++ "(%" ++ i ++ "," ++ 
+  show s ++ ")"
+showAttOps (OpBaseIndexDisp b i s disp _) = show disp ++ "(%" ++ b ++ ",%" ++ 
+  i ++ "," ++ show s ++ ")"
+
+-- Show an operand in Intel style.
+
+showIntelOps opsize (OpImm w) = showIntelImm w
+showIntelOps opsize (OpAddr w sz) = opInd sz ++ "[" ++ showIntelAddr w ++ "]"
+showIntelOps opsize (OpReg s num) = s
+showIntelOps opsize (OpFPReg 0) = "st"
+showIntelOps opsize (OpFPReg i) = "st(" ++ show i ++ ")"
+showIntelOps opsize (OpInd s sz) = opInd sz ++ "[" ++ s ++ "]"
+showIntelOps opsize (OpIndDisp s disp sz) = 
+    opInd sz ++ "[" ++ s ++ 
+       (if disp < 0 then "" else "+") ++ show disp ++ "]"
+showIntelOps opsize (OpBaseIndex b i s sz) = 
+    opInd sz ++ "[" ++ b ++ "+" ++ i ++ "*" ++ show s ++ "]"
+showIntelOps opsize (OpIndexDisp i s disp sz) = 
+    opInd sz ++ "[" ++ i ++ "*" ++ show s ++ 
+       (if disp < 0 then "" else "+") ++ show disp ++ "]"
+showIntelOps opsize (OpBaseIndexDisp b i s disp sz) = 
+    opInd sz ++ "[" ++ b ++ "+" ++ i ++ "*" ++ show s ++ 
+       (if disp < 0 then "" else "+") ++ 
+      show disp ++ "]"
+opInd OPNONE = ""
+opInd OP8 = "byte ptr "
+opInd OP16 = "word ptr "
+opInd OP32 = "dword ptr "
+opInd OPF32 = "dword ptr "
+opInd OP64 = "qword ptr "
+opInd OPF64 = "qword ptr "
+opInd OPF80 = "tbyte ptr "
+opInd OP128 = "dqword ptr "
+
+-- | Encodes the default and currently active operand or address size.  Can
+-- be changed with the operand- or address-size prefixes 0x66 and 0x67.
+
+data OperandSize = BIT16 | BIT32
+
+-- | Some opcodes can operate on data of several widths.  This information
+-- is encoded in instructions using the following enumeration type..
+
+data InstrOperandSize = OPNONE -- ^ No operand size specified
+                       | OP8          -- ^ 8-bit integer operand
+                       | OP16         -- ^ 16-bit integer operand
+                       | OP32         -- ^ 32-bit integer operand
+                       | OP64         -- ^ 64-bit integer operand
+                       | OP128        -- ^ 128-bit integer operand
+                       | OPF32        -- ^ 32-bit floating point operand
+                       | OPF64        -- ^ 64-bit floating point operand
+                       | OPF80        -- ^ 80-bit floating point operand
+  deriving (Show, Eq)
+
+
+-- | The disassembly routines return lists of the following datatype.  It
+-- encodes both invalid byte sequences (with a useful error message, if
+-- possible), or a valid instruction.  Both variants contain the list of
+-- opcode bytes from which the instruction was decoded and the address of
+-- the instruction.
+
+data Instruction = 
+    BadInstruction Word8 String Int [Word8]   -- ^ Invalid instruction
+  | PseudoInstruction Int String                  -- ^ Pseudo instruction, e.g. label
+  | Instruction { opcode :: Opcode,          -- ^ Opcode of the instruction
+                         opsize :: InstrOperandSize, -- ^ Operand size, if any
+                         operands :: [Operand],      -- ^ Instruction operands
+                  address :: Int,             -- ^ Start address of instruction
+                         bytes ::[Word8]             -- ^ Instruction bytes
+                 }                           -- ^ Valid instruction
+  deriving (Eq)
+
+instance Show Instruction where
+    show = showIntel
+
+data Instr = Bad Word8 String
+            | Instr Opcode InstrOperandSize [Operand]
+
+-- Show an integer as an 8-digit hexadecimal number with leading zeroes.
+
+hex32 :: Int -> String
+hex32 i =
+    let w :: Word32
+        w = fromIntegral i
+        s = showHex w ""
+    in take (8 - length s) (repeat '0') ++ s
+
+-- Show a byte as an 2-digit hexadecimal number with leading zeroes.
+
+hex8 :: Word8 -> String
+hex8 i =
+    let s = showHex i ""
+    in take (2 - length s) ['0','0'] ++ s
+
+
+-- | Instructions can be displayed either in Intel or AT&T style (like in
+-- GNU tools).
+--
+-- Intel style:
+--
+-- - Destination operand comes first, source second.
+--
+-- - No register or immediate prefixes.
+--
+-- - Memory operands are annotated with operand size.
+--
+-- - Hexadecimal numbers are suffixed with @H@ and prefixed with @0@ if
+--   necessary.
+--
+-- AT&T style:
+--
+-- - Source operand comes first, destination second.
+--
+-- - Register names are prefixes with @%@.
+--
+-- - Immediates are prefixed with @$@.
+--
+-- - Hexadecimal numbers are prefixes with @0x@
+--
+-- - Opcodes are suffixed with operand size, when ambiguous otherwise.
+data ShowStyle = IntelStyle            -- ^ Show in Intel style
+                | AttStyle             -- ^ Show in AT&T style
+
+-- | Show an instruction in Intel style.
+
+showIntel :: Instruction -> [Char]
+showIntel (BadInstruction b desc pos bytes) =
+    showPosBytes pos bytes ++
+    "(" ++ desc ++ ", byte=" ++ show b ++ ")"
+showIntel (PseudoInstruction pos s) =
+    hex32 pos ++ "                          " ++ s
+showIntel (Instruction op opsize [] pos bytes) = 
+    showPosBytes pos bytes ++
+       showOp op
+showIntel (Instruction op opsize ops pos bytes) = 
+    showPosBytes pos bytes ++
+        enlarge (showOp op) 6 ++ " " ++
+       concat (intersperse "," (map (showIntelOps opsize) ops))
+
+-- | Show an instruction in AT&T style.
+
+showAtt :: Instruction -> [Char]
+showAtt (BadInstruction b desc pos bytes) = 
+    showPosBytes pos bytes ++
+       "(" ++ desc ++ ", byte=" ++ show b ++ ")"
+showAtt (PseudoInstruction pos s) =
+    hex32 pos ++ "                          " ++ s
+showAtt (Instruction op opsize [] pos bytes) = 
+    showPosBytes pos bytes ++
+       showOp op ++ showInstrSuffix [] opsize
+showAtt (Instruction op opsize ops pos bytes) = 
+    showPosBytes pos bytes ++
+       enlarge (showOp op ++ showInstrSuffix ops opsize) 6 ++ " " ++
+       concat (intersperse "," (map showAttOps (reverse ops)))
+
+showPosBytes pos bytes =
+    hex32 pos ++ "  " ++ 
+      enlarge (concat (intersperse " " (map hex8 bytes))) 30
+
+enlarge s i = s ++ take (i - length s) (repeat ' ')
+
+opSizeSuffix OPNONE = ""
+opSizeSuffix OP8 = "b"
+opSizeSuffix OP16 = "w"
+opSizeSuffix OP32 = "l"
+opSizeSuffix OP64 = "q"
+opSizeSuffix OP128 = "dq"
+opSizeSuffix OPF32 = "s"
+opSizeSuffix OPF64 = "l"
+opSizeSuffix OPF80 = "t"
+
+showInstrSuffix [] sz = opSizeSuffix sz
+showInstrSuffix ((OpImm _) : os) s = showInstrSuffix os s
+--showInstrSuffix ((OpReg _ _) : []) s = ""
+showInstrSuffix ((OpReg _ _) : os) s = showInstrSuffix os OPNONE
+showInstrSuffix ((OpFPReg _) : os) s = showInstrSuffix os s
+showInstrSuffix ((OpAddr _ OPNONE) : os) s = showInstrSuffix os s
+showInstrSuffix ((OpAddr _ sz) : os) s = opSizeSuffix sz
+showInstrSuffix ((OpInd _ OPNONE) : os) s = showInstrSuffix os s
+showInstrSuffix ((OpInd _ sz) : os) s = opSizeSuffix sz
+showInstrSuffix ((OpIndDisp _ _ OPNONE) : os) s = showInstrSuffix os s
+showInstrSuffix ((OpIndDisp _ _ sz) : os) s = opSizeSuffix sz
+showInstrSuffix ((OpBaseIndex _ _ _ OPNONE) : os) s = showInstrSuffix os s
+showInstrSuffix ((OpBaseIndex _ _ _ sz) : os) s = opSizeSuffix sz
+showInstrSuffix ((OpIndexDisp _ _ _ OPNONE) : os) s = showInstrSuffix os s
+showInstrSuffix ((OpIndexDisp _ _ _ sz) : os) s = opSizeSuffix sz
+showInstrSuffix ((OpBaseIndexDisp _ _ _ _ OPNONE) : os) s = showInstrSuffix os s
+showInstrSuffix ((OpBaseIndexDisp _ _ _ _ sz) : os) s = opSizeSuffix sz
+
+-- showInstrOperandSize ops OPNONE | noRegop ops = ""
+-- showInstrOperandSize ops OP8 | noRegop ops = "b"
+-- showInstrOperandSize ops OP16 | noRegop ops = "w"
+-- showInstrOperandSize ops OP32 | noRegop ops = "l"
+-- showInstrOperandSize ops OPF32 | noRegop ops = "s"
+-- showInstrOperandSize ops OP64 | noRegop ops = "q"
+-- showInstrOperandSize ops OPF64 | noRegop ops = "l"
+-- showInstrOperandSize ops OPF80 | noRegop ops = "e"
+-- showInstrOperandSize ops OP128 | noRegop ops = ""
+-- showInstrOperandSize _ _ = ""
+
+-- noRegop ops = null (filter isRegop ops)
+-- isRegop (OpReg _ _) = True
+-- isRegop _ = False
+
+-- Show an immediate value in hexadecimal.
+
+showImm :: Word32 -> String
+showImm i =
+  "$0x" ++ showHex i ""
+
+showIntelImm :: Word32 -> String
+showIntelImm i =
+  let h = showHex i "H"
+      (f:_) = h
+  in (if isDigit f then "" else "0") ++ h
+
+-- Show an address in hexadecimal.
+
+showAddr i =  
+  let w :: Word32
+      w = fromIntegral i
+  in "0x" ++ showHex w ""
+showIntelAddr i = 
+  let w :: Word32
+      w = fromIntegral i
+      h = showHex w "H"
+      (f:_) = h
+  in (if isDigit f then "" else "0") ++ h
+
+-- | Disassemble a block of memory.  Starting at the location
+-- pointed to by the given pointer, the given number of bytes are
+-- disassembled.
+
+disassembleBlock :: Ptr Word8 -> Int -> IO (Either ParseError [Instruction])
+disassembleBlock ptr len = 
+    disassembleBlockWithConfig defaultConfig{confStartAddr = fromIntegral (minusPtr ptr nullPtr)} 
+                               ptr len
+
+disassembleBlockWithConfig :: Config -> Ptr Word8 -> Int -> IO (Either ParseError [Instruction])
+disassembleBlockWithConfig config ptr len = do
+  l <- toList ptr len 0 []
+  parseInstructions (configToState config) (reverse l)
+  where 
+  toList :: (Ptr Word8) -> Int -> Int -> [Word8] -> IO [Word8]
+  toList ptr len idx acc | idx < len =
+                  do p <- peekByteOff ptr idx
+                     toList ptr len (idx + 1) (p : acc)
+--                   return (p : r)
+  toList ptr len idx acc | idx >= len = return acc
+
+-- | Disassemble the contents of the given array.
+
+disassembleArray :: (Monad m, IArray a Word8, Ix i) =>
+                    a i Word8 -> m (Either ParseError [Instruction])
+disassembleArray arr = disassembleArrayWithConfig defaultConfig arr
+
+disassembleArrayWithConfig :: (Monad m, IArray a Word8, Ix i) => Config ->
+                             a i Word8 -> m (Either ParseError [Instruction])
+disassembleArrayWithConfig config arr =
+  let l = elems arr
+  in parseInstructions (configToState config) l
+
+-- | Disassemble the contents of the given list.
+
+disassembleList :: (Monad m) =>
+                   [Word8] -> m (Either ParseError [Instruction])
+disassembleList ls = disassembleListWithConfig defaultConfig ls
+
+disassembleListWithConfig :: (Monad m) => Config ->
+                   [Word8] -> m (Either ParseError [Instruction])
+disassembleListWithConfig config ls =
+    parseInstructions (configToState config) ls
+
+disassembleFile filename = disassembleFileWithConfig defaultConfig filename
+
+disassembleFileWithConfig config filename = do
+  l <- readFile filename
+  parseInstructions (configToState config) (map (fromIntegral . ord) l)
+
+instrToString insts style =
+  map showInstr insts
+ where
+ showInstr = case style of
+                 IntelStyle -> showIntel
+                 AttStyle -> showAtt
+
+-- | Test function for disassembling the contents of a binary file and
+-- displaying it in the provided style ("IntelStyle" or "AttStyle").
+
+testFile :: FilePath -> ShowStyle -> IO ()
+testFile fname style = do
+  l <- readFile fname
+  i <- parseInstructions defaultState (map (fromIntegral . ord) l)
+  case i of
+    Left err -> putStrLn (show err)
+    Right i' -> mapM_ (putStrLn . showInstr) i'
+ where
+ showInstr = case style of
+                 IntelStyle -> showIntel
+                 AttStyle -> showAtt
+
+-- This is the state maintained by the disassembler.
+
+data PState = PState { defaultBitMode :: OperandSize,
+                              operandBitMode :: OperandSize,
+                              addressBitMode :: OperandSize,
+                              in64BitMode :: Bool,
+                       prefixes :: [Word8],
+                              startAddr :: Word32
+                      }
+
+data Config = Config {confDefaultBitMode :: OperandSize,
+                      confOperandBitMode :: OperandSize,
+                      confAddressBitMode :: OperandSize,
+                      confIn64BitMode        :: Bool,
+                      confStartAddr          :: Word32}
+
+defaultConfig = Config{ confDefaultBitMode = BIT32,
+                               confOperandBitMode = BIT32, 
+                               confAddressBitMode = BIT32, 
+                               confIn64BitMode = False,
+                               confStartAddr = 0}
+
+configToState (Config defBitMode opMode addrMode in64 confStartAddr) =
+    defaultState{defaultBitMode = defBitMode,
+                 operandBitMode = opMode,
+                 addressBitMode = addrMode,
+                 in64BitMode = in64,
+                 startAddr = confStartAddr}
+           
+-- Default state to be used if no other is given to the disassembly
+-- routines.
+
+defaultState = PState { defaultBitMode = BIT32,
+                         operandBitMode = BIT32, 
+                         addressBitMode = BIT32, 
+                         in64BitMode = False,
+                         prefixes = [],
+                         startAddr = 0}
+
+type Word8Parser a = GenParser Word8 PState a
+
+parseInstructions st l =
+    return (runParser instructionSequence st "memory block" l)
+
+-- Parse a possibly empty sequence of instructions.
+
+instructionSequence = many instruction
+
+-- Parse a single instruction.  The result is either a valid instruction
+-- or an indicator that there starts no valid instruction at the current
+-- position.
+
+instruction = do
+    startPos' <- getPosition
+    let startPos = sourceColumn startPos' - 1
+    input <- getInput
+    st <- getState
+    setState st{operandBitMode = defaultBitMode st,
+                 addressBitMode = defaultBitMode st,
+               prefixes = []}
+    many parsePrefix
+    b <- anyWord8
+    case lookup b oneByteOpCodeMap of
+      Just p -> do i <- p b
+                          endPos' <- getPosition
+                          let endPos = sourceColumn endPos' - 1
+                  case i of
+                            Instr oc opsize ops -> do
+                              return $ Instruction oc opsize ops
+                                   (fromIntegral (startAddr st) + startPos)
+                                   (take (endPos - startPos) input)
+                            Bad b desc ->
+                              return $ BadInstruction b desc 
+                                   (fromIntegral (startAddr st) + startPos)
+                                   (take (endPos - startPos) input)
+      Nothing -> do Bad b desc <- parseInvalidOpcode b
+                   endPos' <- getPosition
+                           let endPos = sourceColumn endPos' - 1
+                           return $ BadInstruction b desc 
+                               (fromIntegral (startAddr st) + startPos)
+                               (take (endPos - startPos) input)
+
+toggleBitMode BIT16 = BIT32
+toggleBitMode BIT32 = BIT16
+
+rex_B = 0x1
+rex_X = 0x2
+rex_R = 0x4
+rex_W = 0x8
+
+-- Return True if the given REX prefix bit appears in the list of current
+-- instruction prefixes, False otherwise.
+
+hasREX rex st =
+    let rexs = filter (\ b -> b >= 0x40 && b <= 0x4f) (prefixes st) in
+       case rexs of
+         (r : _) -> if r .&. rex == rex then True else False
+         _ -> False
+
+-- Return True if the given prefix appears in the list of current
+-- instruction prefixes, False otherwise.
+
+hasPrefix b st = b `elem` prefixes st
+
+addPrefix b = do
+    st <- getState
+    setState st{prefixes = b : prefixes st}
+
+-- Parse a single prefix byte and remember it in the parser state.  If in
+-- 64-bit mode, accept REX prefixes.
+
+parsePrefix = do
+    (word8 0xf0 >>= addPrefix) -- LOCK
+  <|>
+    (word8 0xf2 >>= addPrefix) -- REPNE/REPNZ
+  <|>
+    (word8 0xf3 >>= addPrefix) -- REP or REPE/REPZ
+  <|>
+    (word8 0x2e >>= addPrefix) -- CS segment override
+  <|>
+    (word8 0x36 >>= addPrefix) -- SS segment override
+  <|>
+    (word8 0x3e >>= addPrefix) -- DS segment override
+  <|>
+    (word8 0x26 >>= addPrefix) -- ES segment override
+  <|>
+    (word8 0x64 >>= addPrefix) -- FS segment override
+  <|>
+    (word8 0x65 >>= addPrefix) -- GS segment override
+  <|>
+    (word8 0x2e >>= addPrefix) -- branch not taken
+  <|>
+    (word8 0x3e >>= addPrefix) -- branch taken
+  <|>
+    do word8 0x66 -- operand-size override
+       st <- getState
+       setState st{operandBitMode = toggleBitMode (operandBitMode st)}
+       addPrefix 0x66
+  <|>
+    do word8 0x67 -- address-size override
+       st <- getState
+       setState st{addressBitMode = toggleBitMode (addressBitMode st)}
+       addPrefix 0x66
+  <|>  do st <- getState
+          if in64BitMode st 
+            then    (word8 0x40 >>= addPrefix)
+                     <|>
+                     (word8 0x41 >>= addPrefix)
+                     <|>
+                     (word8 0x42 >>= addPrefix)
+                     <|>
+                     (word8 0x43 >>= addPrefix)
+                     <|>
+                     (word8 0x44 >>= addPrefix)
+                     <|>
+                     (word8 0x45 >>= addPrefix)
+                     <|>
+                     (word8 0x46 >>= addPrefix)
+                     <|>
+                     (word8 0x47 >>= addPrefix)
+                     <|>
+                     (word8 0x48 >>= addPrefix)
+                     <|>
+                     (word8 0x49 >>= addPrefix)
+                     <|>
+                     (word8 0x4a >>= addPrefix)
+                     <|>
+                     (word8 0x4b >>= addPrefix)
+                     <|>
+                     (word8 0x4c >>= addPrefix)
+                     <|>
+                     (word8 0x4d >>= addPrefix)
+                     <|>
+                     (word8 0x4e >>= addPrefix)
+                     <|>
+                     (word8 0x4f >>= addPrefix)
+             else pzero
+
+-- Accept the single unsigned byte B.
+
+word8 b = do
+    tokenPrim showByte nextPos testByte
+  where
+  showByte by = show by
+  nextPos pos x xs = incSourceColumn pos 1
+  testByte by = if b == by then Just by else Nothing
+
+-- Accept and return a single unsigned byte.
+
+anyWord8 :: Word8Parser Word8
+anyWord8 = do
+    tokenPrim showByte nextPos testByte
+  where
+  showByte by = show by
+  nextPos pos x xs = incSourceColumn pos 1
+  testByte by =  Just by
+
+-- Accept any 8-bit signed byte.
+
+anyInt8 :: Word8Parser Int8
+anyInt8 = do
+   b <- anyWord8
+   let i :: Int8
+       i = fromIntegral b
+   return i
+
+-- Accept any 16-bit unsigned word.
+
+anyWord16 = do
+     b0 <- anyWord8
+     b1 <- anyWord8
+     let w0, w1 :: Word16
+         w0 = fromIntegral b0
+         w1 = fromIntegral b1
+     return $ w0 .|. (w1 `shiftL` 8)
+
+-- Accept any 16-bit signed integer.
+
+anyInt16 = do
+     b0 <- anyWord16
+     let w0 :: Int16
+         w0 = fromIntegral b0
+     return $ w0
+
+-- Accept a 32-bit unsigned word.
+
+anyWord32 = do
+     b0 <- anyWord16
+     b1 <- anyWord16
+     let w0, w1 :: Word32
+         w0 = fromIntegral b0
+         w1 = fromIntegral b1
+     return $ w0 .|. (w1 `shiftL` 16)
+
+-- Accept a 32-bit signed integer.
+
+anyInt32 :: Word8Parser Int32
+anyInt32 = do
+     b0 <- anyWord32
+     let w0 :: Int32
+         w0 = fromIntegral b0
+     return $ w0
+
+-- Accept a 64-bit unsigned word.
+
+anyWord64 :: Word8Parser Word64
+anyWord64 = do
+     b0 <- anyWord32
+     b1 <- anyWord32
+     let w0, w1 :: Word64
+         w0 = fromIntegral b0
+         w1 = fromIntegral b1
+     return $ w0 .|. (w1 `shiftL` 32)
+
+-- Accept a 64-bit signed integer.
+
+anyInt64 :: Word8Parser Int64
+anyInt64 = do
+     b0 <- anyWord64
+     let w0 :: Int64
+         w0 = fromIntegral b0
+     return $ w0
+
+-- Accept a 16-bit word for 16-bit operand-size, a 32-bit word for
+-- 32-bit operand-size, or a 64-bit word in 64-bit mode.
+
+anyWordV :: Word8Parser Word64
+anyWordV = do
+    st <- getState
+    if in64BitMode st
+       then do w <- anyWord64
+               return w
+        else case operandBitMode st of
+              BIT16 -> do w <- anyWord16
+                                 let w' :: Word64
+                                     w' = fromIntegral w
+                                 return w'
+              BIT32 -> do w <- anyWord32
+                                 let w' :: Word64
+                                     w' = fromIntegral w
+                                 return w'
+
+-- Accept a 16-bit word for 16-bit operand-size or a 32-bit word for
+-- 32-bit operand-size or 64-bit mode.
+
+anyWordZ :: Word8Parser Word32
+anyWordZ = do
+    st <- getState
+    case operandBitMode st of
+      BIT16 -> do 
+        w <- anyWord16
+               let w' :: Word32
+                   w' = fromIntegral w
+               return w'
+      BIT32 -> anyWord32
+
+-- Accept a 16-bit integer for 16-bit operand-size or a 32-bit word for
+-- 32-bit operand-size or 64-bit mode.
+
+anyIntZ :: Word8Parser Int32
+anyIntZ = do
+    st <- getState
+    case operandBitMode st of
+      BIT16 -> do 
+        w <- anyInt16
+               let w' :: Int32
+                   w' = fromIntegral w
+               return w'
+      BIT32 -> anyInt32
+
+-- Accept a 32-bit far address for 16-bit operand-size or a 48-bit far
+-- address for 32-bit operand-size.
+
+anyWordP :: Word8Parser Word64
+anyWordP = do
+    st <- getState
+    case operandBitMode st of
+      BIT16 -> do w <- anyWord32
+                         let w' :: Word64
+                             w' = fromIntegral w
+                 return w'
+      _ -> do w1 <- anyWord32
+                     w2 <- anyWord16
+              let w1', w2' :: Word64
+                         w1' = fromIntegral w1
+                  w2' = fromIntegral w2
+                     return (w1' .|. (w2' `shiftL` 32))
+
+oneByteOpCodeMap =
+    [(0x00, parseALU ADD),
+     (0x01, parseALU ADD),
+     (0x02, parseALU ADD),
+     (0x03, parseALU ADD),
+     (0x04, parseALU ADD),
+     (0x05, parseALU ADD),
+     (0x06, invalidIn64BitMode (parsePUSHSeg "es")),
+     (0x07, invalidIn64BitMode (parsePOPSeg "es")),
+     (0x08, parseALU OR),
+     (0x09, parseALU OR),
+     (0x0a, parseALU OR),
+     (0x0b, parseALU OR),
+     (0x0c, parseALU OR),
+     (0x0d, parseALU OR),
+     (0x0e, invalidIn64BitMode (parsePUSHSeg "cs")),
+     (0x0f, twoByteEscape),
+
+     (0x10, parseALU ADC),
+     (0x11, parseALU ADC),
+     (0x12, parseALU ADC),
+     (0x13, parseALU ADC),
+     (0x14, parseALU ADC),
+     (0x15, parseALU ADC),
+     (0x16, invalidIn64BitMode (parsePUSHSeg "ss")),
+     (0x17, invalidIn64BitMode (parsePOPSeg "ss")),
+     (0x18, parseALU SBB),
+     (0x19, parseALU SBB),
+     (0x1a, parseALU SBB),
+     (0x1b, parseALU SBB),
+     (0x1c, parseALU SBB),
+     (0x1d, parseALU SBB),
+     (0x1e, invalidIn64BitMode (parsePUSHSeg "ds")),
+     (0x1f, invalidIn64BitMode (parsePOPSeg "ds")),
+
+     (0x20, parseALU AND),
+     (0x21, parseALU AND),
+     (0x22, parseALU AND),
+     (0x23, parseALU AND),
+     (0x24, parseALU AND),
+     (0x25, parseALU AND),
+     (0x26, parseInvalidPrefix), -- ES segment override prefix
+     (0x27, invalidIn64BitMode (parseGeneric DAA OPNONE)),
+     (0x28, parseALU SUB),
+     (0x29, parseALU SUB),
+     (0x2a, parseALU SUB),
+     (0x2b, parseALU SUB),
+     (0x2c, parseALU SUB),
+     (0x2d, parseALU SUB),
+     (0x2e, parseInvalidPrefix), -- CS segment override prefix
+     (0x2f, invalidIn64BitMode (parseGeneric DAS OPNONE)),
+
+     (0x30, parseALU XOR),
+     (0x31, parseALU XOR),
+     (0x32, parseALU XOR),
+     (0x33, parseALU XOR),
+     (0x34, parseALU XOR),
+     (0x35, parseALU XOR),
+     (0x36, parseInvalidPrefix), -- SS segment override prefix
+     (0x37, invalidIn64BitMode (parseGeneric AAA OPNONE)),
+     (0x38, parseALU CMP),
+     (0x39, parseALU CMP),
+     (0x3a, parseALU CMP),
+     (0x3b, parseALU CMP),
+     (0x3c, parseALU CMP),
+     (0x3d, parseALU CMP),
+     (0x3e, parseInvalidPrefix), -- DS segment override prefix
+     (0x3f, invalidIn64BitMode (parseGeneric AAS OPNONE)),
+
+     (0x40, invalidIn64BitMode parseINC), -- REX Prefix in 64-bit mode
+     (0x41, invalidIn64BitMode parseINC), -- ...
+     (0x42, invalidIn64BitMode parseINC),
+     (0x43, invalidIn64BitMode parseINC),
+     (0x44, invalidIn64BitMode parseINC),
+     (0x45, invalidIn64BitMode parseINC),
+     (0x46, invalidIn64BitMode parseINC),
+     (0x47, invalidIn64BitMode parseINC),
+     (0x48, invalidIn64BitMode parseDEC),
+     (0x49, invalidIn64BitMode parseDEC),
+     (0x4a, invalidIn64BitMode parseDEC),
+     (0x4b, invalidIn64BitMode parseDEC),
+     (0x4c, invalidIn64BitMode parseDEC),
+     (0x4d, invalidIn64BitMode parseDEC),
+     (0x4e, invalidIn64BitMode parseDEC),
+     (0x4f, invalidIn64BitMode parseDEC),
+
+     (0x50, parsePUSH),
+     (0x51, parsePUSH),
+     (0x52, parsePUSH),
+     (0x53, parsePUSH),
+     (0x54, parsePUSH),
+     (0x55, parsePUSH),
+     (0x56, parsePUSH),
+     (0x57, parsePUSH),
+     (0x58, parsePOP),
+     (0x59, parsePOP),
+     (0x5a, parsePOP),
+     (0x5b, parsePOP),
+     (0x5c, parsePOP),
+     (0x5d, parsePOP),
+     (0x5e, parsePOP),
+     (0x5f, parsePOP),
+
+     (0x60, invalidIn64BitMode parsePUSHA),
+     (0x61, invalidIn64BitMode parsePOPA),
+     (0x62, invalidIn64BitMode parseBOUND),
+     (0x63, choose64BitMode parseARPL parseMOVSXD), -- MOVSXD in 64-bit mode
+     (0x64, parseInvalidPrefix), -- FS segment override prefix
+     (0x65, parseInvalidPrefix), -- GS segment override prefix
+     (0x66, parseInvalidPrefix), -- operand-size prefix
+     (0x67, parseInvalidPrefix), -- address-size prefix
+     (0x68, parsePUSHImm),
+     (0x69, parseIMUL),
+     (0x6a, parsePUSHImm),
+     (0x6b, parseIMUL),
+     (0x6c, parseINS),
+     (0x6d, parseINS),
+     (0x6e, parseOUTS),
+     (0x6f, parseOUTS),
+
+     (0x70, parseJccShort),
+     (0x71, parseJccShort),
+     (0x72, parseJccShort),
+     (0x73, parseJccShort),
+     (0x74, parseJccShort),
+     (0x75, parseJccShort),
+     (0x76, parseJccShort),
+     (0x77, parseJccShort),
+     (0x78, parseJccShort),
+     (0x79, parseJccShort),
+     (0x7a, parseJccShort),
+     (0x7b, parseJccShort),
+     (0x7c, parseJccShort),
+     (0x7d, parseJccShort),
+     (0x7e, parseJccShort),
+     (0x7f, parseJccShort),
+
+     (0x80, parseGrp1),
+     (0x81, parseGrp1),
+     (0x82, invalidIn64BitMode parseGrp1),
+     (0x83, parseGrp1),
+     (0x84, parseTEST),
+     (0x85, parseTEST),
+     (0x86, parseXCHG),
+     (0x87, parseXCHG),
+     (0x88, parseMOV),
+     (0x89, parseMOV),
+     (0x8a, parseMOV),
+     (0x8b, parseMOV),
+     (0x8c, parseMOV),
+     (0x8d, parseLEA),
+     (0x8e, parseMOV),
+     (0x8f, parseGrp1A),
+
+     (0x90, parse0x90), -- NOP, PAUSE(F3), XCHG r8,rAX
+     (0x91, parseXCHGReg),
+     (0x92, parseXCHGReg),
+     (0x93, parseXCHGReg),
+     (0x94, parseXCHGReg),
+     (0x95, parseXCHGReg),
+     (0x96, parseXCHGReg),
+     (0x97, parseXCHGReg),
+     (0x98, parseCBW_CWDE_CDQE),
+     (0x99, parseCWD_CDQ_CQO),
+     (0x9a, invalidIn64BitMode parseCALLF),
+     (0x9b, parseGeneric WAIT OPNONE),
+     (0x9c, parsePUSHF),
+     (0x9d, parsePOPF),
+     (0x9e, parseGeneric SAHF OPNONE),
+     (0x9f, parseGeneric LAHF OPNONE),
+
+     (0xa0, parseMOVImm),
+     (0xa1, parseMOVImm),
+     (0xa2, parseMOVImm),
+     (0xa3, parseMOVImm),
+     (0xa4, parseMOVS),
+     (0xa5, parseMOVS),
+     (0xa6, parseCMPS),
+     (0xa7, parseCMPS),
+     (0xa8, parseTESTImm),
+     (0xa9, parseTESTImm),
+     (0xaa, parseSTOS),
+     (0xab, parseSTOS),
+     (0xac, parseLODS),
+     (0xad, parseLODS),
+     (0xae, parseSCAS),
+     (0xaf, parseSCAS),
+
+     (0xb0, parseMOVImmByteToByteReg),
+     (0xb1, parseMOVImmByteToByteReg),
+     (0xb2, parseMOVImmByteToByteReg),
+     (0xb3, parseMOVImmByteToByteReg),
+     (0xb4, parseMOVImmByteToByteReg),
+     (0xb5, parseMOVImmByteToByteReg),
+     (0xb6, parseMOVImmByteToByteReg),
+     (0xb7, parseMOVImmByteToByteReg),
+     (0xb8, parseMOVImmToReg),
+     (0xb9, parseMOVImmToReg),
+     (0xba, parseMOVImmToReg),
+     (0xbb, parseMOVImmToReg),
+     (0xbc, parseMOVImmToReg),
+     (0xbd, parseMOVImmToReg),
+     (0xbe, parseMOVImmToReg),
+     (0xbf, parseMOVImmToReg),
+
+     (0xc0, parseGrp2),
+     (0xc1, parseGrp2),
+     (0xc2, parseRETN),
+     (0xc3, parseRETN),
+     (0xc4, invalidIn64BitMode (parseLoadSegmentRegister LES)),
+     (0xc5, invalidIn64BitMode (parseLoadSegmentRegister LDS)),
+     (0xc6, parseGrp11),
+     (0xc7, parseGrp11),
+     (0xc8, parseENTER),
+     (0xc9, parseGeneric LEAVE OPNONE),
+     (0xca, parseGenericIw RETF),
+     (0xcb, parseGeneric RETF OPNONE),
+     (0xcc, parseGeneric INT3 OPNONE),
+     (0xcd, parseGenericIb INT),
+     (0xce, parseGeneric INTO OPNONE),
+     (0xcf, parseGeneric IRET OPNONE),
+
+     (0xd0, parseGrp2),
+     (0xd1, parseGrp2),
+     (0xd2, parseGrp2),
+     (0xd3, parseGrp2),
+     (0xd4, parseGenericIb AAM),
+     (0xd5, parseGenericIb AAD),
+     (0xd6, parseReserved), -- reserved
+     (0xd7, parseGeneric XLAT OPNONE),
+     (0xd8, parseESC),
+     (0xd9, parseESC),
+     (0xda, parseESC),
+     (0xdb, parseESC),
+     (0xdc, parseESC),
+     (0xdd, parseESC),
+     (0xde, parseESC),
+     (0xdf, parseESC),
+
+     (0xe0, parseGenericJb LOOPNE),
+     (0xe1, parseGenericJb LOOPE),
+     (0xe2, parseGenericJb LOOP),
+     (0xe3, parseGenericJb JCXZ), -- depends on bit mode
+     (0xe4, parseINImm),
+     (0xe5, parseINImm),
+     (0xe6, parseOUTImm),
+     (0xe7, parseOUTImm),
+     (0xe8, parseGenericJz CALL),
+     (0xe9, parseGenericJz JMP),
+     (0xea, parseJMPF),
+     (0xeb, parseGenericJb JMP),
+     (0xec, parseIN),
+     (0xed, parseIN),
+     (0xee, parseOUT),
+     (0xef, parseOUT),
+
+     (0xf0, parseInvalidPrefix), -- LOCK prefix
+     (0xf1, parseReserved), -- reserved
+     (0xf2, parseInvalidPrefix), -- REPNE prefix
+     (0xf3, parseInvalidPrefix), -- REP/REPQ prefix
+     (0xf4, parseGeneric HLT OPNONE),
+     (0xf5, parseGeneric CMC OPNONE),
+     (0xf6, parseGrp3),
+     (0xf7, parseGrp3),
+     (0xf8, parseGeneric CLC OPNONE),
+     (0xf9, parseGeneric STC OPNONE),
+     (0xfa, parseGeneric CLI OPNONE),
+     (0xfb, parseGeneric STI OPNONE),
+     (0xfc, parseGeneric CLD OPNONE),
+     (0xfd, parseGeneric STD OPNONE),
+     (0xfe, parseGrp4),
+     (0xff, parseGrp5)
+
+     ]
+
+parseInvalidPrefix b = do
+  return $ Bad b "invalid prefix"
+
+parseInvalidOpcode b = do
+  return $ Bad b "invalid opcode"
+
+parseReserved b = do
+  return $ Bad b "reserved opcode"
+
+parseUndefined name b = do
+  return $ Bad b ("undefined opcode: " ++ show name)
+
+parseUnimplemented b = do
+  return $ Bad b "not implemented yet"
+
+invalidIn64BitMode p b = do
+  st <- getState
+  if in64BitMode st
+     then return $ Bad b "invalid in 64-bit mode"
+     else p b
+
+onlyIn64BitMode p b = do
+  st <- getState
+  if in64BitMode st
+     then p b
+     else return $ Bad b "only in 64-bit mode"
+
+choose64BitMode p32 p64 b = do
+  st <- getState
+  if in64BitMode st
+     then p64 b
+     else p32 b
+
+chooseOperandSize p16 p32 b = do
+  st <- getState
+  case operandBitMode st of
+    BIT16 -> p16 b
+    BIT32 -> p32 b
+
+chooseAddressSize p16 p32 b = do
+  st <- getState
+  case addressBitMode st of
+    BIT16 -> p16 b
+    BIT32 -> p32 b
+
+parseModRM = do
+  b <- anyWord8
+  parseModRM' b
+parseModRM' b = do
+  return (b `shiftR` 6, (b `shiftR` 3) .&. 7, (b .&. 7))
+
+parseSIB = do
+  b <- anyWord8
+  parseSIB' b
+parseSIB' b = do
+  return (b `shiftR` 6, (b `shiftR` 3) .&. 7, (b .&. 7))
+
+scaleToFactor 0 = 1
+scaleToFactor 1 = 2
+scaleToFactor 2 = 4
+scaleToFactor 3 = 8
+
+
+parseAddress32 :: InstrOperandSize ->
+                 Word8Parser (Operand, Operand, Word8, Word8, Word8)
+parseAddress32 s = do
+  b <- anyWord8
+  parseAddress32' s b
+
+parseAddress32' :: InstrOperandSize -> 
+    Word8 ->
+    Word8Parser (Operand, Operand, Word8, Word8, Word8)
+parseAddress32' opsize modrm = do
+  (mod, reg_opc, rm) <- parseModRM' modrm
+  st <- getState
+  let opregnames = if in64BitMode st && hasREX rex_W st
+                     then regnames64
+                     else case operandBitMode st of 
+                       BIT16 -> regnames16
+                               BIT32 -> regnames32
+  let addregnames = if in64BitMode st && hasREX rex_R st
+                      then regnames64
+                      else case addressBitMode st of 
+                       BIT16 -> regnames16
+                               BIT32 -> regnames32
+  case mod of
+    0 -> case rm of
+            4 -> do 
+            (s, i, b) <- parseSIB
+                    case (i, b) of
+               (4, 5) -> do
+                           disp <- anyWord32
+                           return (OpAddr (fromIntegral disp) opsize,
+                                          OpReg (opregnames !! fromIntegral reg_opc)
+                                                (fromIntegral reg_opc),
+                                          mod, reg_opc, rm)
+               (_, 5) -> do
+                           disp <- anyWord32
+                           return (OpIndexDisp (addregnames !! fromIntegral i)
+                                               (scaleToFactor s)
+                                               (fromIntegral disp)
+                                               opsize,
+                                   OpReg (opregnames !! fromIntegral reg_opc)
+                                         (fromIntegral reg_opc),
+                                   mod, reg_opc, rm)
+                      (4, _) -> return (OpInd (addregnames !! fromIntegral b) opsize,
+                                  OpReg (opregnames !! fromIntegral reg_opc)
+                            (fromIntegral reg_opc),
+                                  mod, reg_opc, rm)
+                      (_ ,_) -> return (OpBaseIndex 
+                                     (addregnames !! fromIntegral b)
+                                     (addregnames !! fromIntegral i)
+                                     (scaleToFactor (fromIntegral s))
+                             opsize,
+                                   OpReg (opregnames !! fromIntegral reg_opc)
+                             (fromIntegral reg_opc),
+                                   mod, reg_opc, rm)
+            5 -> do 
+            disp <- anyWord32
+                    return (OpAddr disp opsize, 
+                            OpReg (opregnames !! fromIntegral reg_opc)
+                      (fromIntegral reg_opc),
+                            mod, reg_opc, rm)
+            _ -> return (OpInd (addregnames !! fromIntegral rm) opsize, 
+                         OpReg (opregnames !! fromIntegral reg_opc)
+                       (fromIntegral reg_opc),
+                         mod, reg_opc, rm)
+    1 -> case rm of
+            4 -> do 
+            (s, i, b) <- parseSIB
+            disp <- anyInt8
+                    case i of
+                      4 -> return (OpIndDisp
+                                   (addregnames !! fromIntegral b) 
+                                   (fromIntegral disp) opsize,
+                                   OpReg (opregnames !! fromIntegral reg_opc)
+                             (fromIntegral reg_opc),
+                                   mod, reg_opc, rm)
+                      _ -> return (OpBaseIndexDisp
+                                   (addregnames !! fromIntegral b)
+                                   (addregnames !! fromIntegral i)
+                                   (scaleToFactor (fromIntegral s))
+                                   (fromIntegral disp)
+                           opsize,
+                                   OpReg (opregnames !! fromIntegral reg_opc)
+                             (fromIntegral reg_opc),
+                                   mod, reg_opc, rm)
+            _ -> do disp <- anyInt8
+                    return (OpIndDisp
+                                   (addregnames !! fromIntegral rm) 
+                                   (fromIntegral disp)
+                           opsize,
+                                   OpReg (opregnames !! fromIntegral reg_opc)
+                             (fromIntegral reg_opc),
+                            mod, reg_opc, rm)
+    2 -> case rm of
+            4 -> do 
+            (s, i, b) <- parseSIB
+            disp <- anyInt32
+             case i of
+                      4 -> return (OpIndDisp
+                                   (addregnames !! fromIntegral b)
+                                   (fromIntegral disp)
+                           opsize,
+                                   OpReg (opregnames !! fromIntegral reg_opc)
+                             (fromIntegral reg_opc),
+                                   mod, reg_opc, rm)
+                      _ -> return (OpBaseIndexDisp
+                                   (addregnames !! fromIntegral b)
+                                   (addregnames !! fromIntegral i)
+                                   (scaleToFactor (fromIntegral s))
+                                   (fromIntegral disp)
+                           opsize,
+                                   OpReg (opregnames !! fromIntegral reg_opc)
+                             (fromIntegral reg_opc),
+                                   mod, reg_opc, rm)
+            _ -> do 
+            disp <- anyInt32
+                    return (OpIndDisp
+                            (addregnames !! fromIntegral rm)
+                            (fromIntegral disp)
+                    opsize,
+                            OpReg (opregnames !! fromIntegral reg_opc)
+                      (fromIntegral reg_opc),
+                            mod, reg_opc, rm)
+    3 -> return (OpReg (opregnames !! fromIntegral rm)
+                  (fromIntegral rm),
+                  OpReg (opregnames !! fromIntegral reg_opc)
+                   (fromIntegral reg_opc),
+                 mod, reg_opc, rm)
+
+parseALU :: Opcode -> Word8 -> Word8Parser Instr
+parseALU op b = do
+    opsize <- instrOperandSize
+    case b .&. 0x07 of
+      0 -> do (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+              return $ Instr op OP8 [op1,
+                          (OpReg (regnames8 !! fromIntegral reg)) (fromIntegral reg)]
+      1 -> do (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+              return $ Instr op opsize [op1, op2]
+      2 -> do (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+              return $ Instr op OP8 
+                          [(OpReg (regnames8 !! fromIntegral reg))
+                      (fromIntegral reg), op1]
+      3 -> do (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+              return $ Instr op opsize [op2, op1]
+      4 -> do b <- anyWord8
+              return $ Instr op OP8 [(OpReg "al" 0), (OpImm (fromIntegral b))]
+      5 -> do b <- anyWordZ
+              rn <- registerName 0
+              return $ Instr op opsize [(OpReg rn 0), (OpImm b)]
+      _ -> return $ Bad b "no ALU opcode (internal error)"
+    
+
+parsePUSHSeg :: String -> Word8 -> Word8Parser Instr
+parsePUSHSeg r _ = do
+     return $ Instr PUSH OP16 [(OpReg r 0)] -- FIXME: register number
+
+parsePOPSeg :: String -> Word8 -> Word8Parser Instr
+parsePOPSeg r _ = do
+     return $ Instr POP OP16 [(OpReg r 0)] -- FIXME: register number
+
+parseGenericGvEw name b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP16
+  case op1 of
+    OpReg _ num -> return $ Instr name OP16 [op2, 
+                                              OpReg (regnames16 !! num) num]
+    _ -> return $ Instr name OP8 [op2, op1]
+
+parseGenericGvEb name b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  case op1 of
+    OpReg _ num -> return $ Instr name OP8 [op2, 
+                                              OpReg (regnames8 !! num) num]
+    _ -> return $ Instr name OP8 [op2, op1]
+
+parseGenericGvEv name b = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr name opsize [op2, op1]
+
+parseGenericEvGv name b = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr name opsize [op1, op2]
+
+parseGenericEbGb name b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  return $ Instr name OP8 [op1, (OpReg (regnames8 !! fromIntegral reg)
+                               (fromIntegral reg))]
+
+parseGenericEv name b = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, _, rm) <- parseAddress32 opsize
+  return $ Instr name opsize [op1]
+
+twoByteOpCodeMap = 
+    [(0x00, parseGrp6),
+     (0x01, parseGrp7),
+     (0x02, parseGenericGvEw LAR),
+     (0x03, parseGenericGvEw LSL),
+     (0x04, parseReserved),
+     (0x05, onlyIn64BitMode (parseGeneric SYSCALL OPNONE)),
+     (0x06, parseGeneric CLTS OPNONE),
+     (0x07, onlyIn64BitMode (parseGeneric SYSCALL OPNONE)),
+     (0x08, parseGeneric INVD OPNONE),
+     (0x09, parseGeneric WBINVD OPNONE),
+     (0x0a, parseReserved),
+     (0x0b, parseUndefined UD2),
+     (0x0c, parseReserved),
+     (0x0d, parseGenericEv NOP),
+     (0x0e, parseReserved),
+     (0x0f, parseReserved),
+
+     (0x10, parseMOVUPS),
+     (0x11, parseMOVUPS),
+     (0x12, parseMOVLPS),
+     (0x13, parseMOVLPS),
+     (0x14, parseUNPCKLPS),
+     (0x15, parseUNPCKHPS),
+     (0x16, parseMOVHPS),
+     (0x17, parseMOVHPS),
+     (0x18, parseGrp16),
+     (0x19, parseReserved),
+     (0x1a, parseReserved),
+     (0x1b, parseReserved),
+     (0x1c, parseReserved),
+     (0x1d, parseReserved),
+     (0x1e, parseReserved),
+     (0x1f, parseGenericEv NOP),
+
+     (0x20, parseMOVCtrlDebug),
+     (0x21, parseMOVCtrlDebug),
+     (0x22, parseMOVCtrlDebug),
+     (0x23, parseMOVCtrlDebug),
+     (0x24, parseReserved),
+     (0x25, parseReserved),
+     (0x26, parseReserved),
+     (0x27, parseReserved),
+     (0x28, parseMOVAPS),
+     (0x29, parseMOVAPS),
+     (0x2a, parseCVTI2PS),
+     (0x2b, parseMOVNTPS),
+     (0x2c, parseCVTTPS2PI),
+     (0x2d, parseCVTPS2PI),
+     (0x2e, parseUCOMISS),
+     (0x2f, parseCOMISS),
+
+     (0x30, parseGeneric WRMSR OPNONE),
+     (0x31, parseGeneric RDTSC OPNONE),
+     (0x32, parseGeneric RDMSR OPNONE),
+     (0x33, parseGeneric RDPMC OPNONE),
+     (0x34, parseGeneric SYSENTER OPNONE),
+     (0x35, parseGeneric SYSEXIT OPNONE),
+     (0x36, parseReserved),
+     (0x37, parseReserved),
+     (0x38, parseReserved),
+     (0x39, parseReserved),
+     (0x3a, parseReserved),
+     (0x3b, parseReserved),
+     (0x3c, parseReserved),
+     (0x3d, parseReserved),
+     (0x3e, parseReserved),
+     (0x3f, parseReserved),
+
+     (0x40, parseCMOVcc),
+     (0x41, parseCMOVcc),
+     (0x42, parseCMOVcc),
+     (0x43, parseCMOVcc),
+     (0x44, parseCMOVcc),
+     (0x45, parseCMOVcc),
+     (0x46, parseCMOVcc),
+     (0x47, parseCMOVcc),
+     (0x48, parseCMOVcc),
+     (0x49, parseCMOVcc),
+     (0x4a, parseCMOVcc),
+     (0x4b, parseCMOVcc),
+     (0x4c, parseCMOVcc),
+     (0x4d, parseCMOVcc),
+     (0x4e, parseCMOVcc),
+     (0x4f, parseCMOVcc),
+
+     (0x50, parseMOVSKPS),
+     (0x51, parseSQRTPS),
+     (0x52, parseRSQRTPS),
+     (0x53, parseRCPPS),
+     (0x54, parseANDPS),
+     (0x55, parseANDNPS),
+     (0x56, parseORPS),
+     (0x57, parseXORPS),
+     (0x58, parseADDPS),
+     (0x59, parseMULPS),
+     (0x5a, parseCVTPS2PD),
+     (0x5b, parseCVTDQ2PS),
+     (0x5c, parseSUBPS),
+     (0x5d, parseMINPS),
+     (0x5e, parseDIVPS),
+     (0x5f, parseMAXPS),
+
+     (0x60, parsePUNPCKLBW),
+     (0x61, parsePUNPCKLWD),
+     (0x62, parsePUNPCKLDQ),
+     (0x63, parsePACKSSWB),
+     (0x64, parsePCMPGTB),
+     (0x65, parsePCMPGTW),
+     (0x66, parsePCMPGTD),
+     (0x67, parsePACKUSWB),
+     (0x68, parsePUNPCKHBW),
+     (0x69, parsePUNPCKHWD),
+     (0x6a, parsePUNPCKHDQ),
+     (0x6b, parsePACKSSDW),
+     (0x6c, parsePUNPCKLQDQ),
+     (0x6d, parsePUNPCKHQDQ),
+     (0x6e, parseMOVD_Q),
+     (0x6f, parseMOVQ),
+
+     (0x70, parsePSHUFW),
+     (0x71, parseGrp12),
+     (0x72, parseGrp13),
+     (0x73, parseGrp14),
+     (0x74, parsePCMPEQB),
+     (0x75, parsePCMPEQW),
+     (0x76, parsePCMPEQD),
+     (0x77, parseGeneric EMMS OPNONE),
+     (0x78, parseVMREAD),
+     (0x79, parseVMWRITE),
+     (0x7a, parseReserved),
+     (0x7b, parseReserved),
+     (0x7c, parseHADDPS),
+     (0x7d, parseHSUBPS),
+     (0x7e, parseMOVD_Q),
+     (0x7f, parseMOVQ),
+
+     (0x80, parseJccLong),
+     (0x81, parseJccLong),
+     (0x82, parseJccLong),
+     (0x83, parseJccLong),
+     (0x84, parseJccLong),
+     (0x85, parseJccLong),
+     (0x86, parseJccLong),
+     (0x87, parseJccLong),
+     (0x88, parseJccLong),
+     (0x89, parseJccLong),
+     (0x8a, parseJccLong),
+     (0x8b, parseJccLong),
+     (0x8c, parseJccLong),
+     (0x8d, parseJccLong),
+     (0x8e, parseJccLong),
+     (0x8f, parseJccLong),
+
+     (0x90, parseSETcc),
+     (0x91, parseSETcc),
+     (0x92, parseSETcc),
+     (0x93, parseSETcc),
+     (0x94, parseSETcc),
+     (0x95, parseSETcc),
+     (0x96, parseSETcc),
+     (0x97, parseSETcc),
+     (0x98, parseSETcc),
+     (0x99, parseSETcc),
+     (0x9a, parseSETcc),
+     (0x9b, parseSETcc),
+     (0x9c, parseSETcc),
+     (0x9d, parseSETcc),
+     (0x9e, parseSETcc),
+     (0x9f, parseSETcc),
+
+     (0xa0, parsePUSHSeg "fs"),
+     (0xa1, parsePOPSeg "fs"),
+     (0xa2, parseGeneric CPUID OPNONE),
+     (0xa3, parseGenericEvGv BT),
+     (0xa4, parseSHLD),
+     (0xa5, parseSHLD),
+     (0xa6, parseReserved),
+     (0xa7, parseReserved),
+     (0xa8, parsePUSHSeg "gs"),
+     (0xa9, parsePOPSeg "gs"),
+     (0xaa, parseGeneric RSM OPNONE),
+     (0xab, parseGenericEvGv BTS),
+     (0xac, parseSHRD),
+     (0xad, parseSHRD),
+     (0xae, parseGrp15),
+     (0xaf, parseGenericGvEv IMUL),
+
+     (0xb0, parseGenericEbGb CMPXCHG),
+     (0xb1, parseGenericEvGv CMPXCHG),
+     (0xb2, parseLoadSegmentRegister LSS),
+     (0xb3, parseGenericEvGv BTR),
+     (0xb4, parseLoadSegmentRegister LFS),
+     (0xb5, parseLoadSegmentRegister LGS),
+     (0xb6, parseGenericGvEb MOVZXB),
+     (0xb7, parseGenericGvEw MOVZXW),
+     (0xb8, parseReserved),
+     (0xb9, parseGrp10),
+     (0xba, parseGrp8),
+     (0xbb, parseGenericEvGv BTC),
+     (0xbc, parseGenericGvEv BSF),
+     (0xbd, parseGenericGvEv BSR),
+     (0xbe, parseGenericGvEb MOVSXB),
+     (0xbf, parseGenericGvEw MOVSXW),
+
+     (0xc0, parseGenericEbGb XADD),
+     (0xc1, parseGenericEvGv XADD),
+     (0xc2, parseCMPPS),
+     (0xc3, parseMOVNTI),
+     (0xc4, parsePINSRW),
+     (0xc5, parsePEXTRW),
+     (0xc6, parseSHUFPS),
+     (0xc7, parseGrp9),
+     (0xc8, parseBSWAP),
+     (0xc9, parseBSWAP),
+     (0xca, parseBSWAP),
+     (0xcb, parseBSWAP),
+     (0xcc, parseBSWAP),
+     (0xcd, parseBSWAP),
+     (0xce, parseBSWAP),
+     (0xcf, parseBSWAP),
+
+     (0xd0, parseADDSUBPS),
+     (0xd1, parsePSRLW),
+     (0xd2, parsePSRLD),
+     (0xd3, parsePSRLQ),
+     (0xd4, parsePADDQ),
+     (0xd5, parsePMULLW),
+     (0xd6, parseMOVQ),
+     (0xd7, parsePMOVMSKB),
+     (0xd8, parsePSUBUSB),
+     (0xd9, parsePSUBUSW),
+     (0xda, parsePMINUB),
+     (0xdb, parsePAND),
+     (0xdc, parsePADDUSB),
+     (0xdd, parsePADDUSW),
+     (0xde, parsePMAXUB),
+     (0xdf, parsePANDN),
+
+     (0xe0, parsePAVGB),
+     (0xe1, parsePSRAW),
+     (0xe2, parsePSRAD),
+     (0xe3, parsePAVGW),
+     (0xe4, parsePMULHUW),
+     (0xe5, parsePMULHW),
+     (0xe6, parseCVTPD2DQ),
+     (0xe7, parseMOVNTQ),
+     (0xe8, parsePSUBSB),
+     (0xe9, parsePSUBSQ),
+     (0xea, parsePMINSW),
+     (0xeb, parsePOR),
+     (0xec, parsePADDSB),
+     (0xed, parsePADDSW),
+     (0xee, parsePMAXSW),
+     (0xef, parsePXOR),
+
+     (0xf0, parseLDDQU),
+     (0xf1, parsePSLLW),
+     (0xf2, parsePSLLD),
+     (0xf3, parsePSLLQ),
+     (0xf4, parsePMULUDQ),
+     (0xf5, parsePMADDWD),
+     (0xf6, parsePSADBW),
+     (0xf7, parseMASKMOVQ),
+     (0xf8, parsePSUBB),
+     (0xf9, parsePSUBW),
+     (0xfa, parsePSUBD),
+     (0xfb, parsePSUBQ),
+     (0xfc, parsePADDB),
+     (0xfd, parsePADDW),
+     (0xfe, parsePADDD),
+     (0xff, parseReserved)
+     ]
+
+twoByteEscape :: Word8 -> Word8Parser Instr
+twoByteEscape b1 = do
+  b <- anyWord8
+  case lookup b twoByteOpCodeMap of
+    Just p -> p b
+    Nothing -> return $ Bad b "invalid two-byte opcode"
+
+parseGeneric name opsize _ = do
+    return (Instr name opsize [])
+parseGenericIb name b = do
+    b <-  anyWord8
+    return $ Instr name OP8 [OpImm (fromIntegral b)]
+parseGenericIw name _ = do
+    w <- anyWord16
+    pos <- getPosition
+    return $ Instr name OP16 [OpImm (fromIntegral w)]
+parseGenericJb name _ = do
+    b <- anyInt8
+    pos <- getPosition
+    st <- getState
+    return $ Instr name OPNONE 
+        [OpAddr (fromIntegral ((fromIntegral b + sourceColumn pos - 1)) +
+                       (startAddr st)) OPNONE]
+parseGenericJz name _ = do
+    b <- anyIntZ
+    pos <- getPosition
+    st <- getState
+    return $ Instr name OPNONE 
+        [OpAddr (fromIntegral ((fromIntegral b + sourceColumn pos - 1)) +
+                      (startAddr st)) OPNONE]
+
+parseINC b = do
+  opsize <- instrOperandSize
+  let reg = b .&. 0x0f
+  rn <- registerName (fromIntegral reg)
+  return $ Instr INC opsize [OpReg rn (fromIntegral reg)]
+
+parseDEC b = do
+  opsize <- instrOperandSize
+  let reg = (b .&. 0x0f) - 8
+  rn <- registerName (fromIntegral reg)
+  return $ Instr DEC opsize [OpReg rn (fromIntegral reg)]
+
+parsePUSH b = 
+    let reg = b .&. 0x0f in do
+      st <- getState
+      rn <- registerName (fromIntegral reg)
+      opsize <- instrOperandSize
+      if hasREX rex_R st
+         then return $ Instr PUSH opsize [OpReg ("r" ++ show (reg + 8))
+                                          (fromIntegral reg)]
+          else return $ Instr PUSH opsize [OpReg rn
+                                           (fromIntegral reg)]
+
+parsePOP b = 
+    let reg = (b .&. 0x0f) - 8 in do
+      st <- getState
+      rn <- registerName (fromIntegral reg)
+      opsize <- instrOperandSize
+      if hasREX rex_R st
+         then return $ Instr POP opsize [OpReg ("r" ++ show (reg + 8))
+                                        (fromIntegral reg)]
+          else return $ Instr POP opsize [OpReg rn (fromIntegral reg)]
+
+parsePUSHA = do
+  chooseOperandSize
+    (\ _ -> return $ Instr PUSHA OPNONE [])
+    (\ _ -> return $ Instr PUSHAD OPNONE [])
+parsePOPA = do
+  chooseOperandSize
+    (\ _ -> return $ Instr POPA OPNONE [])
+    (\ _ -> return $ Instr POPAD OPNONE [])
+
+parseBOUND b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  return $ Instr BOUND OPNONE [op2, op1]
+  
+parseARPL b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP16
+  let rn = regnames16 !! fromIntegral reg
+  return $ Instr ARPL OPNONE [op1, (OpReg rn (fromIntegral reg))]
+     
+parseMOVSXD b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  return $ Instr MOVSXD OPNONE [op2, op1]
+
+parsePUSHImm 0x68 = do
+  w <- anyWordZ
+  opsize <- instrOperandSize
+  return $ Instr PUSH opsize [OpImm w]
+parsePUSHImm 0x6a = do
+  w <- anyWord8
+  opsize <- instrOperandSize
+  return $ Instr PUSH opsize [OpImm (fromIntegral w)]
+
+parseIMUL 0x69 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  imm <- anyWordZ
+  return $ Instr IMUL opsize [op2, op1, OpImm imm]
+parseIMUL 0x6b = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  imm <- anyWord8
+  return $ Instr IMUL opsize [op2, op1, OpImm (fromIntegral imm)]
+
+parseINS 0x6c = return $ Instr INS OP8 []
+parseINS b@0x6d = chooseOperandSize
+                   (\ _ -> return $ Instr INS OP16 [])
+                  (\ _ -> return $ Instr INS OP32 []) b
+
+parseOUTS 0x6e = return $ Instr OUTS OP8 []
+parseOUTS b@0x6f = chooseOperandSize
+                     (\ _ -> return $ Instr OUTS OP16 [])
+                     (\ _ -> return $ Instr OUTS OP32 []) b
+
+parseJccShort b = do
+  disp <- anyInt8
+  pos <- getPosition
+  st <- getState
+  return $ Instr (jccname (b .&. 0xf)) OPNONE
+        [OpAddr (fromIntegral (fromIntegral disp + sourceColumn pos - 1) +
+                (startAddr st)) OPNONE]
+
+parseTEST 0x84 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  return $ Instr TEST OP8 [op1, OpReg (regnames8 !! fromIntegral reg)
+                         (fromIntegral reg)]
+parseTEST 0x85 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr TEST opsize [op1, op2]
+
+parseXCHG 0x86 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  return $ Instr XCHG OP8 [op1, OpReg (regnames8 !! fromIntegral reg)
+                          (fromIntegral reg)]
+parseXCHG 0x87 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr XCHG opsize[op1, op2]
+
+parseMOV 0x88  = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  return $ Instr MOV OP8 [op1, OpReg (regnames8 !! fromIntegral reg)
+                         (fromIntegral reg)]
+parseMOV 0x89  = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr MOV opsize [op1, op2]
+parseMOV 0x8a  = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  return $ Instr MOV OP8 [OpReg (regnames8 !! fromIntegral reg) 
+                         (fromIntegral reg), op1]
+parseMOV 0x8b  = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr MOV opsize [op2, op1]
+parseMOV 0x8c  = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP16
+  let rn = segregnames !! (fromIntegral reg)
+  return $ Instr MOV OP16 [op1, OpReg rn (fromIntegral reg)]
+parseMOV 0x8e  = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP16
+  let rn = segregnames !! (fromIntegral reg)
+  return $ Instr MOV OP16 [OpReg rn (fromIntegral reg), op1]
+
+parseLEA b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  return $ Instr LEA OPNONE [op2, op1]
+
+
+parse0x90 b = do
+  st <- getState
+  if hasPrefix 0xf3 st
+     then return $ Instr PAUSE OPNONE []
+     else do st <- getState
+             if in64BitMode st
+                then parseXCHGReg b
+                       else return $ Instr NOP OPNONE []
+
+-- FIXME: Register name handling not quite right
+
+parseXCHGReg :: Word8 -> Word8Parser Instr
+parseXCHGReg b = 
+    let reg = b .&. 0x0f in do
+      st <- getState
+      if hasREX rex_R st
+         then return $ Instr XCHG OP64 [OpReg "rax" 0, 
+                                               OpReg ("r" ++ show (reg + 8))
+                                       (fromIntegral reg)]
+         else do rn <- registerName (fromIntegral reg)
+                        return $ Instr XCHG OP64 [OpReg "rax" 0,
+                                          OpReg rn (fromIntegral reg)]
+
+parseCBW_CWDE_CDQE b = do
+  st <- getState
+  if in64BitMode st
+     then if hasREX rex_W st
+             then return $ Instr CDQE OPNONE []
+              else return $ Instr CWDE OPNONE []
+     else chooseOperandSize
+            (\ _ -> return $ Instr CBW OPNONE [])
+            (\ _ -> return $ Instr CWDE OPNONE []) b
+
+parseCWD_CDQ_CQO b = do
+  st <- getState
+  if in64BitMode st
+     then if hasREX rex_W st
+             then return $ Instr CDQE OPNONE []
+              else return $ Instr CDQ OPNONE []
+     else chooseOperandSize
+            (\ _ -> return $ Instr CWD OPNONE [])
+            (\ _ -> return $ Instr CDQ OPNONE []) b
+
+parseCALLF b = do
+    w <- anyWord32
+    s <- anyWord16
+    return $ Instr CALLF OPNONE [OpImm (fromIntegral w),
+                                  OpImm (fromIntegral s)]
+
+-- FIXME: Check default/operand sizes.
+
+parsePUSHF b = do
+  st <- getState
+  if in64BitMode st
+     then chooseOperandSize
+             (\ _ -> return $ Instr PUSHF OPNONE [])
+             (\ _ -> return $ Instr PUSHFQ OPNONE []) b
+     else chooseOperandSize
+             (\ _ -> return $ Instr PUSHF OPNONE [])
+             (\ _ -> return $ Instr PUSHFD OPNONE []) b
+
+parsePOPF b = do
+  st <- getState
+  if in64BitMode st
+     then chooseOperandSize
+             (\ _ -> return $ Instr POPF OPNONE [])
+             (\ _ -> return $ Instr POPFQ OPNONE []) b
+     else chooseOperandSize
+             (\ _ -> return $ Instr POPF OPNONE [])
+             (\ _ -> return $ Instr POPFD OPNONE []) b
+
+parseJMPF b = do
+    w <- anyWord32
+    return $ Instr JMPF OPNONE [OpImm w]
+
+parseMOVImm b@0xa0 = do
+  chooseAddressSize
+    (\ _ -> do w <- anyWord16
+               return $ Instr MOV OP8 [OpReg "al" 0, OpImm (fromIntegral w)])
+    (\ _ -> do w <- anyWord32
+               return $ Instr MOV OP8 [OpReg "al" 0, OpImm w]) b
+parseMOVImm b@0xa1 = do
+  opsize <- instrOperandSize
+  reg <- registerName 0
+  chooseAddressSize
+    (\ _ -> do w <- anyWord16
+               return $ Instr MOV opsize [OpReg reg 0, OpImm (fromIntegral w)])
+    (\ _ -> do w <- anyWord32
+                      return $ Instr MOV opsize [OpReg reg 0, OpImm w]) b
+parseMOVImm b@0xa2 = do
+  chooseAddressSize
+    (\ _ -> do w <- anyWord16
+                      return $ Instr MOV OP8 [OpImm (fromIntegral w), OpReg "al" 0])
+    (\ _ -> do w <- anyWord32
+                      return $ Instr MOV OP8 [OpImm w, OpReg "al" 0]) b
+parseMOVImm b@0xa3 = do
+  opsize <- instrOperandSize
+  reg <- registerName 0
+  chooseAddressSize
+    (\ _ -> do w <- anyWord16
+                      return $ Instr MOV opsize [OpImm (fromIntegral w), OpReg reg 0])
+    (\ _ -> do w <- anyWord32
+               return $ Instr MOV opsize [OpImm w, OpReg reg 0]) b
+
+parseMOVS 0xa4 = return $ Instr MOVS OP8 []
+parseMOVS b@0xa5 = do
+  st <- getState
+  opsize <- instrOperandSize
+  return $ Instr MOVS opsize []
+
+parseCMPS 0xa6 = return $ Instr CMPS OP8 []
+parseCMPS 0xa7 = do
+  st <- getState
+  opsize <- instrOperandSize
+  return $ Instr CMPS opsize []
+
+parseTESTImm 0xa8 = do
+  imm <- anyWord8
+  return $ Instr TEST OP8 [OpReg "al" 0, OpImm (fromIntegral imm)]
+parseTESTImm 0xa9 = do
+  imm <- anyWordZ
+  rn <- registerName 0
+  opsize <- instrOperandSize
+  return $ Instr TEST opsize [OpReg rn 0, OpImm imm]
+  
+
+parseSTOS 0xaa = return $ Instr STOS OP8 []
+parseSTOS b@0xab = do
+  st <- getState
+  opsize <- instrOperandSize
+  if in64BitMode st
+     then if hasREX rex_W st
+             then return $ Instr STOS opsize []
+              else chooseOperandSize
+                    (\ _ -> return $ Instr STOS opsize [])
+                    (\ _ -> return $ Instr STOS opsize []) b
+     else chooseOperandSize
+            (\ _ -> return $ Instr STOS opsize [])
+            (\ _ -> return $ Instr STOS opsize []) b
+
+parseLODS 0xac = return $ Instr LODS OP8 []
+parseLODS b@0xad = do
+  st <- getState
+  opsize <- instrOperandSize
+  if in64BitMode st
+     then if hasREX rex_W st
+             then return $ Instr LODS opsize []
+              else chooseOperandSize
+                    (\ _ -> return $ Instr LODS opsize [])
+                    (\ _ -> return $ Instr LODS opsize []) b
+     else chooseOperandSize
+            (\ _ -> return $ Instr LODS opsize [])
+            (\ _ -> return $ Instr LODS opsize []) b
+
+parseSCAS 0xae = return $ Instr SCAS OP8 []
+parseSCAS b@0xaf = do
+  st <- getState
+  opsize <- instrOperandSize
+  if in64BitMode st
+     then if hasREX rex_W st
+             then return $ Instr SCAS opsize []
+              else chooseOperandSize
+                    (\ _ -> return $ Instr SCAS opsize [])
+                    (\ _ -> return $ Instr SCAS opsize []) b
+     else chooseOperandSize
+            (\ _ -> return $ Instr SCAS opsize [])
+            (\ _ -> return $ Instr SCAS opsize []) b
+
+parseMOVImmByteToByteReg :: Word8 -> Word8Parser Instr
+parseMOVImmByteToByteReg b = do
+  let reg = b .&. 0x0f
+  st <- getState
+  imm <- anyWord8
+  if hasREX rex_R st
+     then return $ Instr MOV OP8 [OpReg ("r" ++ show reg ++ "l")
+                                  (fromIntegral reg),
+                                         OpImm (fromIntegral imm)]
+     else return $ Instr MOV OP8 [OpReg (regnames8 !! (fromIntegral reg))
+                                   (fromIntegral reg), 
+                                         OpImm (fromIntegral imm)]
+
+parseMOVImmToReg :: Word8 -> Word8Parser Instr
+parseMOVImmToReg b = do
+  let reg = (b .&. 0x0f - 8)
+  imm <- anyWordV
+  opsize <- instrOperandSize
+  rn <- registerName (fromIntegral reg)
+  return $ Instr MOV opsize [OpReg rn (fromIntegral reg), 
+                            OpImm (fromIntegral imm)]
+
+parseRETN 0xc2 = do
+    w <- anyWord16
+    return $ Instr RET OPNONE [OpImm (fromIntegral w)]
+parseRETN 0xc3 = return $ Instr RET OPNONE []
+
+parseLoadSegmentRegister opcode b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  return $ Instr opcode OPNONE [op2, op1]
+
+parseENTER b = do
+    w <- anyWord16
+    b <- anyWord8
+    return $ Instr ENTER OPNONE [OpImm (fromIntegral w), 
+                                  OpImm (fromIntegral b)]
+
+-- Floating-point operations.  These can probably shortened by doing some
+-- arithmetic/logical tricks on the opcodes, but since the instruction
+-- set is still quite irregular (even though much better than the integer
+-- ops), I haven't bothered yet.
+
+parseESC 0xd8 = do
+  modrm <- anyWord8
+  let modrm' :: Word8
+      modrm' = modrm - 0xc0
+  if modrm <= 0xbf
+     then do (op1, op2, mod, reg, rm) <- parseAddress32' OPF32 modrm
+             return $ Instr (ops !! fromIntegral reg) OPF32 [op1]
+     else if (modrm .&. 0x0f) < 0x8
+             then return $ Instr 
+                    (ops !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg 0, OpFPReg (fromIntegral (modrm .&. 0x0f))]
+              else return $ Instr 
+                    (ops !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg 0, OpFPReg (fromIntegral ((modrm .&. 0x0f) - 8))]
+ where ops = [FADD, FMUL, FCOM, FCOMP, 
+               FSUB, FSUBR, FDIV, FDIVR]
+             
+parseESC b@0xd9 = do
+  modrm <- anyWord8
+  let modrm' :: Word8
+      modrm' = modrm - 0xc0
+  if modrm <= 0xbf
+     then do (op1', op2, mod, reg, rm) <- parseAddress32' OPNONE modrm
+            let op1 = case op1' of 
+                        OpAddr a _ -> OpAddr a  (opsizes !! fromIntegral reg)
+                        op -> op
+             return $ Instr (lowOps !! fromIntegral reg) 
+                             (opsizes !! fromIntegral reg) [op1]
+     else if (modrm < 0xd0)
+             then if (modrm .&. 0x0f) < 8
+                    then return $ Instr 
+                         (ops !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                         [OpFPReg 0, OpFPReg (fromIntegral (modrm .&. 0x0f))]
+                    else return $ Instr 
+                         (ops !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                         [OpFPReg 0, OpFPReg (fromIntegral (modrm .&. 0x0f)
+                                     - 8)]
+              else case modrm of
+                            0xd0 -> return $ Instr FNOP OPNONE []
+                     0xe0 -> return $ Instr FCHS OPNONE []
+                     0xe1 -> return $ Instr FABS OPNONE []
+                     0xe4 -> return $ Instr FTST OPNONE []
+                     0xe5 -> return $ Instr FXAM OPNONE []
+                     0xe8 -> return $ Instr FLD1 OPNONE []
+                     0xe9 -> return $ Instr FLDL2T OPNONE []
+                     0xea -> return $ Instr FLDL2E OPNONE []
+                     0xeb -> return $ Instr FLDPI OPNONE []
+                     0xec -> return $ Instr FLDLG2 OPNONE []
+                     0xed -> return $ Instr FLDLN2 OPNONE []
+                     0xee -> return $ Instr FLDZ OPNONE []
+                     _ -> parseInvalidOpcode b
+ where lowOps = [FLD, InvalidOpcode, FST, FSTP, 
+                  FLDENV, FLDCW, FSTENV, FSTCW]
+       opsizes = [OPF32, OPNONE, OPF32, OPF32,
+                   OPNONE, OPNONE, OPNONE, OPNONE]
+       ops = [FLD, FXCH]
+
+parseESC 0xda = do
+  modrm <- anyWord8
+  let modrm' :: Word8
+      modrm' = modrm - 0xc0
+  if modrm <= 0xbf
+     then do (op1, op2, mod, reg, rm) <- parseAddress32' OPNONE modrm
+             return $ Instr (ops !! fromIntegral reg) OPNONE [op1]
+     else if (modrm < 0xe0)
+             then return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg 0, OpFPReg (fromIntegral (modrm .&. 0x0f))]
+              else case modrm of
+                     0xe1 -> return $ Instr FUCOMPP OPNONE []
+                     _ -> parseInvalidOpcode 0xda
+ where ops = [FIADD, FIMUL, FICOM, FICOMP, 
+               FISUB, FISUBR, FIDIV, FIDIVR]
+       ops' = [FCMOVB, FCMOVE, FCMOVBE, FCMOVU]
+
+parseESC 0xdb = do
+  modrm <- anyWord8
+  let modrm' :: Word8
+      modrm' = modrm - 0xc0
+  if modrm <= 0xbf
+     then do (op1', op2, mod, reg, rm) <- parseAddress32' OPNONE modrm
+            let op1 = case op1' of 
+                        OpAddr a _ -> OpAddr a  (opsizes !! fromIntegral reg)
+                        op -> op
+             return $ Instr (ops !! fromIntegral reg) 
+                             (opsizes !! fromIntegral reg) [op1]
+     else 
+      case modrm of
+         0xe2 -> return $ Instr FCLEX OPNONE []
+         0xe3 -> return $ Instr FINIT OPNONE []
+         _ ->
+           if (modrm .&. 0x0f) < 0x8
+             then return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg 0, OpFPReg (fromIntegral (modrm .&. 0x0f))]
+              else return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg 0, OpFPReg (fromIntegral ((modrm .&. 0x0f) - 8))]
+ where ops = [FILD, FISTP, FIST, FISTP, 
+               InvalidOpcode, FLD, InvalidOpcode, FSTP]
+       opsizes = [OP32, OP32, OP32, OP32,
+                   OPNONE, OPF80, OPNONE, OPF80]
+       ops' = [FCMOVNB, FCMOVNE, FCMOVNBE, FCMOVNU,
+                InvalidOpcode, FUCOMI, FCOMI, InvalidOpcode]
+
+parseESC 0xdc = do
+  modrm <- anyWord8
+  let modrm' :: Word8
+      modrm' = modrm - 0xc0
+  if modrm <= 0xbf
+     then do (op1, op2, mod, reg, rm) <- parseAddress32' OPNONE modrm
+             return $ Instr (ops !! fromIntegral reg) OPNONE [op1]
+     else
+       if modrm >= 0xd0 && modrm < 0xe0
+        then parseInvalidOpcode 0xdc
+        else if (modrm .&. 0x0f) < 0x8
+             then return $ Instr 
+                    (ops !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg (fromIntegral (modrm .&. 0x0f)), OpFPReg 0]
+              else return $ Instr 
+                    (ops !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg (fromIntegral ((modrm .&. 0x0f) - 8)), OpFPReg 0]
+ where ops = [FADD, FMUL, FCOM, FCOMP, 
+               FSUB, FSUBR, FDIV, FDIVR]
+             
+parseESC 0xdd = do
+  modrm <- anyWord8
+  let modrm' :: Word8
+      modrm' = modrm - 0xc0
+  if modrm <= 0xbf
+     then do (op1', op2, mod, reg, rm) <- parseAddress32' OPNONE modrm
+            let op1 = case op1' of 
+                        OpAddr a _ -> OpAddr a  (opsizes !! fromIntegral reg)
+                        op -> op
+             return $ Instr (ops !! fromIntegral reg) 
+                             (opsizes !! fromIntegral reg) [op1]
+     else
+       if (modrm >= 0xc8) && modrm <= 0xd0 || (modrm >= 0xf0 && modrm < 0xff)
+        then parseInvalidOpcode 0xdc
+        else if (modrm .&. 0x0f) < 0x8
+             then return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg (fromIntegral (modrm .&. 0x0f)), OpFPReg 0]
+              else return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg (fromIntegral ((modrm .&. 0x0f) - 8)), OpFPReg 0]
+ where ops = [FLD, FISTTP, FST, FSTP, 
+               FRSTOR, InvalidOpcode, FSAVE, FSTSW]
+       opsizes = [OPF64, OP64, OPF64, OPF64,
+                   OPNONE, OPNONE, OPNONE, OP16]
+       ops' = [FFREE, InvalidOpcode, FST, FSTP, 
+                FUCOM, FUCOMP]
+             
+parseESC 0xde = do
+  modrm <- anyWord8
+  let modrm' :: Word8
+      modrm' = modrm - 0xc0
+  if modrm <= 0xbf
+     then do (op1, op2, mod, reg, rm) <- parseAddress32' OPNONE modrm
+             return $ Instr (ops !! fromIntegral reg) OPNONE [op1]
+     else
+       if modrm >= 0xd0 && modrm <= 0xe0
+        then case modrm of
+                0xd9 -> return $ Instr FCOMPP OPNONE []
+                _ -> parseInvalidOpcode 0xde
+        else if (modrm .&. 0x0f) < 0x8
+             then return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg (fromIntegral (modrm .&. 0x0f)), OpFPReg 0]
+              else return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg (fromIntegral ((modrm .&. 0x0f) - 8)), OpFPReg 0]
+ where ops = [FIADD, FIMUL, FICOM, FICOMP, 
+               FISUB, FISUBR, FIDIV, FIDIVR]
+       ops' = [FADDP, FMULP, InvalidOpcode, InvalidOpcode,
+                FSUBRP, FSUBP, FDIVRP, FDIVP]
+             
+             
+parseESC 0xdf = do
+  modrm <- anyWord8
+  let modrm' :: Word8
+      modrm' = modrm - 0xc0
+  if modrm <= 0xbf
+     then do (op1, op2, mod, reg, rm) <- parseAddress32' OPNONE modrm
+             return $ Instr (ops !! fromIntegral reg) OPNONE [op1]
+     else
+       case modrm of
+           0xe0 -> return $ Instr FSTSW OPNONE [OpReg "ax" 0]
+           _ -> 
+             if (modrm >= 0xe8 && modrm <= 0xef) ||
+                (modrm >= 0xf0 && modrm <= 0xf7)
+             then
+             if (modrm .&. 0x0f) < 0x8
+             then return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg (fromIntegral (modrm .&. 0x0f)), OpFPReg 0]
+              else return $ Instr 
+                    (ops' !! fromIntegral ((modrm' `shiftR` 3))) OPNONE
+                    [OpFPReg (fromIntegral ((modrm .&. 0x0f) - 8)), OpFPReg 0]
+             else parseInvalidOpcode 0xdf
+ where ops = [FILD, FISTPP, FIST, FISTP, 
+               FBLD, FILD, FBSTP, FISTP]
+       ops' = [InvalidOpcode, InvalidOpcode, InvalidOpcode, InvalidOpcode,
+                InvalidOpcode, FUCOMIP, FCOMIP, InvalidOpcode]
+
+parseINImm 0xe4 = do
+    b <- anyWord8
+    return $ Instr IN OP8 [OpReg "al" 0, OpImm (fromIntegral b)]
+parseINImm 0xe5 = do
+    b <- anyWord8
+    rn <- registerName 0
+    opsize <- instrOperandSize
+    return $ Instr IN opsize [OpReg rn 0, OpImm (fromIntegral b)]
+parseOUTImm 0xe6 = do
+    b <- anyWord8
+    return $ Instr OUT OP8 [OpImm (fromIntegral b), OpReg "al" 0]
+parseOUTImm 0xe7 = do
+    b <- anyWord8
+    rn <- registerName 0
+    opsize <- instrOperandSize
+    return $ Instr OUT opsize [OpImm (fromIntegral b), OpReg rn 0]
+
+parseIN 0xec = do
+    return $ Instr IN OP8 [OpReg "al" 0, OpReg "dx" 2]
+parseIN 0xed = do
+    rn <- registerName 0
+    opsize <- instrOperandSize
+    return $ Instr IN opsize [OpReg rn 0, OpReg "dx" 2]
+parseOUT 0xee = do
+    return $ Instr OUT OP8 [OpReg "dx" 2, OpReg "al" 0]
+parseOUT 0xef = do
+    rn <- registerName 0
+    opsize <- instrOperandSize
+    return $ Instr OUT opsize [OpReg "dx" 2, OpReg rn 0]
+
+-- Return the name of the register encoded with R.  Take 64-bit mode and
+-- possible REX and operand-size prefixes into account.
+
+registerName r = do
+    st <- getState
+    if in64BitMode st && hasREX rex_R st
+       then return $ "r" ++ show (r + 8)
+       else case operandBitMode st of
+              BIT16 -> return $ regnames16 !! r
+              BIT32 -> return $ regnames32 !! r
+
+instrOperandSize = do
+    st <- getState
+    if in64BitMode st && hasREX rex_W st
+       then return $ OP64
+       else case operandBitMode st of
+              BIT16 -> return OP16
+              BIT32 -> return OP32
+
+regnames8 = ["al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"]
+regnames16 = ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di"]
+regnames32 = ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"]
+regnames64 = ["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"]
+segregnames = ["es", "cs", "ss", "ds", "fs", "gs", "<invalid>", "<invalid>"]
+mmxregs = ["mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"]
+xmmregs = ["xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"]
+
+jccname 0 = JO
+jccname 1 = JNO
+jccname 2 = JB
+jccname 3 = JNB
+jccname 4 = JE
+jccname 5 = JNE
+jccname 6 = JBE
+jccname 7 = JA
+jccname 8 = JS
+jccname 9 = JNS
+jccname 10 = JP
+jccname 11 = JNP
+jccname 12 = JL
+jccname 13 = JGE
+jccname 14 = JLE
+jccname 15 = JG
+
+setccname 0 = SETO
+setccname 1 = SETNO
+setccname 2 = SETB
+setccname 3 = SETNB
+setccname 4 = SETE
+setccname 5 = SETNE
+setccname 6 = SETBE
+setccname 7 = SETA
+setccname 8 = SETS
+setccname 9 = SETNS
+setccname 10 = SETP
+setccname 11 = SETNP
+setccname 12 = SETL
+setccname 13 = SETGE
+setccname 14 = SETLE
+setccname 15 = SETG
+
+cmovccname 0 = CMOVO
+cmovccname 1 = CMOVNO
+cmovccname 2 = CMOVB
+cmovccname 3 = CMOVNB
+cmovccname 4 = CMOVE
+cmovccname 5 = CMOVNE
+cmovccname 6 = CMOVBE
+cmovccname 7 = CMOVA
+cmovccname 8 = CMOVS
+cmovccname 9 = CMOVNS
+cmovccname 10 = CMOVP
+cmovccname 11 = CMOVNP
+cmovccname 12 = CMOVL
+cmovccname 13 = CMOVGE
+cmovccname 14 = CMOVLE
+cmovccname 15 = CMOVG
+
+parseGrp1 0x80 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  immb <- anyWord8
+  return $ Instr (aluOps !! fromIntegral reg) OP8 
+    [op1, OpImm (fromIntegral immb)]
+parseGrp1 0x81 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  immb <- anyWordZ
+  return $ Instr (aluOps !! fromIntegral reg) opsize 
+    [op1, OpImm (fromIntegral immb)]
+parseGrp1 0x82 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  immb <- anyWord8
+  return $ Instr (aluOps !! fromIntegral reg) OP8 
+    [op1, OpImm (fromIntegral immb)]
+parseGrp1 0x83 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  immb <- anyWord8
+  return $ Instr (aluOps !! fromIntegral reg) opsize
+    [op1, OpImm (fromIntegral immb)]
+aluOps = [ADD, OR, ADC, SBB, AND, SUB, XOR, CMP]
+
+
+parseGrp1A b = do
+   opsize <- instrOperandSize
+   (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+   case reg of
+     0 -> return $ Instr POP opsize [op1]
+     _ -> parseInvalidOpcode b
+
+parseGrp2 0xc0 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  immb <- anyWord8
+  return $ Instr (shiftOps !! fromIntegral reg) OP8 
+      [op1, OpImm (fromIntegral immb)]
+parseGrp2 0xc1 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  imm <- anyWord8
+  return $ Instr (shiftOps !! fromIntegral reg) opsize
+      [op1, OpImm (fromIntegral imm)]
+parseGrp2 0xd0 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  return $ Instr (shiftOps !! fromIntegral reg) OP8 [op1, OpImm 1]
+parseGrp2 0xd1 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr (shiftOps !! fromIntegral reg) opsize [op1, OpImm 1]
+parseGrp2 0xd2 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  return $ Instr (shiftOps !! fromIntegral reg) OP8 [op1, OpReg "cl" 1]
+parseGrp2 0xd3 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr (shiftOps !! fromIntegral reg) opsize [op1, OpReg "cl" 1]
+shiftOps = [ROL, ROR, RCL, RCR, SHL, SHR, InvalidOpcode, SAR]
+
+parseGrp3 0xf6 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  case reg of
+    0 -> do imm <- anyWord8
+            return $ Instr TEST OP8 [op1, OpImm (fromIntegral imm)]
+    1 -> parseInvalidOpcode 0xf6
+    2 -> return $ Instr NOT OP8 [op1]
+    3 -> return $ Instr NEG OP8 [op1]
+    4 -> return $ Instr MUL OP8 [OpReg "al" 0, op1]
+    5 -> return $ Instr IMUL OP8 [OpReg "al" 0, op1]
+    6 -> return $ Instr DIV OP8 [OpReg "al" 0, op1]
+    7 -> return $ Instr IDIV OP8 [OpReg "al" 0, op1]
+parseGrp3 0xf7 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  rn <- registerName 0
+  case reg of
+    0 -> do imm <- anyWordZ
+            return $ Instr TEST opsize [op1, OpImm (fromIntegral imm)]
+    1 -> parseInvalidOpcode 0xf6
+    2 -> return $ Instr NOT opsize [op1]
+    3 -> return $ Instr NEG opsize [op1]
+    4 -> return $ Instr MUL opsize [OpReg rn 0, op1]
+    5 -> return $ Instr IMUL opsize [OpReg rn 0, op1]
+    6 -> return $ Instr DIV opsize [OpReg rn 0, op1]
+    7 -> return $ Instr IDIV opsize [OpReg rn 0, op1]
+
+parseGrp4 b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  case reg of
+    0 -> return $ Instr INC OP8 [op1]
+    1 -> return $ Instr DEC OP8 [op1]
+    _ -> parseInvalidOpcode b
+
+parseGrp5 b = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  case reg of
+    0 -> return $ Instr INC opsize [op1]
+    1 -> return $ Instr DEC opsize [op1]
+    2 -> return $ Instr CALL OPNONE [op1]
+    3 -> do w <- anyWord16
+            return $ Instr CALLF OPNONE [OpAddr (fromIntegral w) OPNONE, op1]
+    4 -> return $ Instr JMPN OPNONE [op1]
+    5 -> do w <- anyWord16
+            return $ Instr JMPF OPNONE [OpAddr (fromIntegral w) OPNONE, op1]
+    6 -> return $ Instr PUSH opsize [op1]
+    _ -> parseInvalidOpcode b
+
+parseGrp6 b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  case reg of
+    0 -> return $ Instr SLDT OPNONE [op1]
+    1 -> return $ Instr STR OPNONE [op1]
+    2 -> return $ Instr LLDT OPNONE [op1]
+    3 -> return $ Instr LTR OPNONE [op1]
+    4 -> return $ Instr VERR OPNONE [op1]
+    5 -> return $ Instr VERW OPNONE [op1]
+    _ -> parseInvalidOpcode b
+
+parseGrp7 b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  case mod of
+    3 -> case reg of
+           0 -> case rm of
+                         1 -> return $ Instr VMCALL OPNONE []
+                         2 -> return $ Instr VMLAUNCH OPNONE []
+                         3 -> return $ Instr VMRESUME OPNONE []
+                         4 -> return $ Instr VMXOFF OPNONE []
+                         _ -> parseInvalidOpcode b
+           1 -> case rm of
+                         0 -> return $ Instr MONITOR OPNONE []
+                         1 -> return $ Instr MWAIT OPNONE []
+                         _ -> parseInvalidOpcode b
+           4 -> return $ Instr SMSW OPNONE [op1]
+           6 -> return $ Instr LMSW OPNONE [op1]
+           7 -> case rm of
+                         0 -> onlyIn64BitMode
+                                (\b -> return $ Instr SWAPGS OPNONE []) b
+                         _ -> parseInvalidOpcode b
+           _ -> parseInvalidOpcode b
+    _ -> case reg of
+           0 -> return $ Instr SGDT OPNONE [op1]
+           1 -> return $ Instr SIDT OPNONE [op1]
+           2 -> return $ Instr LGDT OPNONE [op1]
+           3 -> return $ Instr LIDT OPNONE [op1]
+           4 -> return $ Instr SMSW OPNONE [op1]
+           5 -> parseInvalidOpcode b
+           6 -> return $ Instr LMSW OPNONE [op1]
+           7 -> return $ Instr INVLPG OPNONE [op1]
+
+parseGrp8 b = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  imm <- anyWord8
+  case reg of
+    4 -> return $ Instr BT opsize [op1, OpImm (fromIntegral imm)]
+    5 -> return $ Instr BTS opsize [op1, OpImm (fromIntegral imm)]
+    6 -> return $ Instr BTR opsize [op1, OpImm (fromIntegral imm)]
+    7 -> return $ Instr BTC opsize [op1, OpImm (fromIntegral imm)]
+    _ -> parseInvalidOpcode b
+
+parseGrp9 b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  st <- getState
+  case mod of
+    3 -> parseInvalidOpcode b
+    _ -> case reg of
+            1 -> if hasREX rex_W st
+                    then return $ Instr CMPXCHG16B OPNONE [op1]
+                    else return $ Instr CMPXCHG8B OPNONE [op1]
+            6 -> if hasPrefix 0x66 st
+                   then return $ Instr VMCLEAR OPNONE [op1]
+                    else if hasPrefix 0xf3 st
+                         then return $ Instr VMXON OPNONE [op1]
+                         else return $ Instr VMPTRLD OPNONE [op1]
+            7 -> return $ Instr VMPTRST OPNONE [op1]
+            _ -> parseInvalidOpcode b
+
+parseGrp10 = parseInvalidOpcode
+
+parseGrp11 0xc6 = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  imm <- anyWord8
+  return $ Instr MOV OP8 [op1, OpImm (fromIntegral imm)]
+parseGrp11 0xc7 = do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  imm <- anyWordZ
+  return $ Instr MOV opsize [op1, OpImm (fromIntegral imm)]
+
+mmxInstr op1 mod reg rm name = do
+  st <- getState
+  imm <- anyWord8
+  if hasPrefix 0x66 st
+     then return $ Instr name OP128
+           [OpReg (xmmregs !! fromIntegral rm) (fromIntegral rm),
+           OpImm (fromIntegral imm)]
+     else return $ Instr name OP64
+           [OpReg (mmxregs !! fromIntegral rm) (fromIntegral rm),
+           OpImm (fromIntegral imm)]
+               
+parseGrp12 b = do
+  st <- getState
+  let opsize = if hasPrefix 0x66 st then OP128 else OP64
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  case mod of
+    3 -> case reg of
+           2 -> mmxInstr op1 mod reg rm PSRLW
+           4 -> mmxInstr op1 mod reg rm PSRAW
+           6 -> mmxInstr op1 mod reg rm PSLLW
+           _ -> parseInvalidOpcode b
+    _ -> parseInvalidOpcode b
+parseGrp13 b = do
+  st <- getState
+  let opsize = if hasPrefix 0x66 st then OP128 else OP64
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  case mod of
+    3 -> case reg of
+           2 -> mmxInstr op1 mod reg rm PSRLD
+           4 -> mmxInstr op1 mod reg rm PSRAD
+           6 -> mmxInstr op1 mod reg rm PSLLD
+           _ -> parseInvalidOpcode b
+    _ -> parseInvalidOpcode b
+parseGrp14 b = do
+  st <- getState
+  let opsize = if hasPrefix 0x66 st then OP128 else OP64
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  st <- getState
+  case mod of
+    3 -> case reg of
+           2 -> mmxInstr op1 mod reg rm PSRLQ
+           3 -> if hasPrefix 0x66 st
+                  then mmxInstr op1 mod reg rm PSRLDQ
+                          else parseInvalidOpcode b
+           6 -> mmxInstr op1 mod reg rm PSLLQ
+           7 -> if hasPrefix 0x66 st
+                   then mmxInstr op1 mod reg rm PSLLDQ
+                          else parseInvalidOpcode b
+          _ -> parseInvalidOpcode b
+    _ -> parseInvalidOpcode b
+
+parseGrp15 b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  case mod of
+    3 -> case reg of
+            5 -> return $ Instr LFENCE OPNONE []
+            6 -> return $ Instr MFENCE OPNONE []
+            7 -> return $ Instr SFENCE OPNONE []
+            _ -> parseInvalidOpcode b
+    _ -> case reg of
+            0 -> return $ Instr FXSAVE OPNONE [op1]
+            1 -> return $ Instr FXRSTOR OPNONE [op1]
+            2 -> return $ Instr LDMXCSR OPNONE [op1]
+            3 -> return $ Instr STMXCSR OPNONE [op1]
+            7 -> return $ Instr CLFLUSH OPNONE [op1]
+            _ -> parseInvalidOpcode b
+parseGrp16 b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OPNONE
+  case mod of
+    3 -> parseInvalidOpcode b
+    _ -> case reg of
+            0 -> return $ Instr PREFETCHNTA OPNONE [op1]
+            1 -> return $ Instr PREFETCHT0 OPNONE [op1]
+            2 -> return $ Instr PREFETCHT1 OPNONE [op1]
+            3 -> return $ Instr PREFETCHT2 OPNONE [op1]
+            _ -> parseInvalidOpcode b
+
+parseXmmVW p p0xf3 p0x66 p0xf2 b =
+    do (op1, op2, mod, reg, rm) <- parseAddress32 OP128
+       st <- getState
+       let v = OpReg (xmmregs !! (fromIntegral reg)) (fromIntegral reg)
+       let w = case op1 of
+                OpReg _ num -> OpReg (xmmregs !! num) num
+                op -> op
+       if hasPrefix 0xf3 st
+         then return $ Instr p0xf3 OP128 [v, w]
+         else if hasPrefix 0x66 st
+                 then return $ Instr p0x66 OP128 [v, w]
+                 else if hasPrefix 0xf2 st
+                         then return $ Instr p0xf2 OP128 [v, w]
+                         else return $ Instr p OP128 [v, w]
+parseXmmWV p p0xf3 p0x66 p0xf2 b =
+    do (op1, op2, mod, reg, rm) <- parseAddress32 OP128
+       st <- getState
+       let w = OpReg (xmmregs !! (fromIntegral reg)) (fromIntegral reg)
+       let v = case op1 of
+                OpReg _ num -> OpReg (xmmregs !! num) num
+                op -> op
+       if hasPrefix 0xf3 st
+         then return $ Instr p0xf3 OP128 [v, w]
+         else if hasPrefix 0x66 st
+                 then return $ Instr p0x66 OP128 [v, w]
+                 else if hasPrefix 0xf2 st
+                         then return $ Instr p0xf2 OP128 [v, w]
+                         else return $ Instr p OP128 [v, w]
+
+parseXmmGU p p0xf3 p0x66 p0xf2 b =
+    do (mod, reg, rm) <- parseModRM
+       st <- getState
+       let g = OpReg (regnames32 !! (fromIntegral reg)) (fromIntegral reg)
+       let u = OpReg (xmmregs !! (fromIntegral rm)) (fromIntegral rm)
+       if hasPrefix 0xf3 st
+         then return $ Instr p0xf3 OP32 [g, u]
+         else if hasPrefix 0x66 st
+                 then return $ Instr p0x66 OP32 [g, u]
+                 else if hasPrefix 0xf2 st
+                         then return $ Instr p0xf2 OP32 [g, u]
+                         else return $ Instr p OP32 [g, u]
+
+parseMOVUPS b@0x10 = parseXmmVW MOVUPS MOVSS MOVUPD MOVSD b
+parseMOVUPS b@0x11 = parseXmmWV MOVUPS MOVSS MOVUPD MOVSD b
+parseMOVLPS b@0x12 = parseXmmWV MOVLPS MOVSLDUP MOVLPD MOVDDUP b
+parseMOVLPS b@0x13 = parseXmmVW MOVLPS InvalidOpcode MOVLPD InvalidOpcode b
+parseUNPCKLPS b@0x14 =
+    parseXmmVW UNPCKLPS InvalidOpcode UNPCKLPD InvalidOpcode b
+parseUNPCKHPS b@0x15 = 
+    parseXmmVW UNPCKHPS InvalidOpcode UNPCKHPD InvalidOpcode b
+parseMOVHPS b@0x16 = parseXmmVW MOVHPS MOVLSDUP MOVHPD MOVLHPS b
+parseMOVHPS b@0x17 = parseXmmVW MOVHPS InvalidOpcode MOVHPD InvalidOpcode b
+
+parseMOVCtrlDebug 0x20 = 
+    do (mod, reg, rm) <- parseModRM
+       return $ Instr MOV OPNONE [OpReg (regnames32 !! fromIntegral rm)
+                                 (fromIntegral rm),
+                                 OpReg ("cr" ++ show reg) (fromIntegral reg)]
+parseMOVCtrlDebug 0x21 = 
+    do (mod, reg, rm) <- parseModRM
+       return $ Instr MOV OPNONE [OpReg (regnames32 !! fromIntegral rm)
+                                 (fromIntegral rm),
+                                 OpReg ("db" ++ show reg) (fromIntegral reg)]
+parseMOVCtrlDebug 0x22 = 
+    do (mod, reg, rm) <- parseModRM
+       return $ Instr MOV OPNONE [OpReg ("cr" ++ show reg) (fromIntegral reg),
+                                 OpReg (regnames32 !! fromIntegral rm)
+                                 (fromIntegral rm)]
+parseMOVCtrlDebug 0x23 = 
+    do (mod, reg, rm) <- parseModRM
+       return $ Instr MOV OPNONE [OpReg ("db" ++ show reg) (fromIntegral reg),
+                                 OpReg (regnames32 !! fromIntegral rm)
+                                 (fromIntegral rm)]
+  
+
+parseMOVAPS b@0x28 = parseXmmVW MOVAPS InvalidOpcode MOVAPD InvalidOpcode b
+parseMOVAPS b@0x29 = parseXmmWV MOVAPS InvalidOpcode MOVAPD InvalidOpcode b
+parseCVTI2PS = parseUnimplemented
+parseMOVNTPS = parseXmmWV MOVNTPS InvalidOpcode MOVNTPD InvalidOpcode
+parseCVTPS2PI = parseUnimplemented
+parseCVTTPS2PI = parseUnimplemented
+parseUCOMISS = parseXmmVW UCOMISS InvalidOpcode UCOMISD InvalidOpcode
+parseCOMISS = parseXmmVW COMISS InvalidOpcode COMISD InvalidOpcode
+
+parseCMOVcc b= do
+  opsize <- instrOperandSize
+  (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+  return $ Instr (cmovccname (b .&. 0xf)) OPNONE [op2, op1]
+  
+parseMOVSKPS = parseXmmGU MOVMSKPS InvalidOpcode MOVMSKPD InvalidOpcode
+
+parseSQRTPS = parseXmmVW SQRTPS SQRTSS SQRTPD SQRTSD
+parseRSQRTPS = parseXmmVW RSQRTPS RSQRTSS InvalidOpcode InvalidOpcode
+parseRCPPS = parseXmmVW RCPPS RCPSS InvalidOpcode InvalidOpcode
+parseCVTPS2PD = parseUnimplemented
+parseANDNPS = parseXmmVW ANDNPS InvalidOpcode ANDNPD InvalidOpcode
+parseANDPS =  parseXmmVW ANDPS InvalidOpcode ANDPD InvalidOpcode
+parseORPS = parseXmmVW ORPS InvalidOpcode ORPD InvalidOpcode
+parseXORPS = parseXmmVW XORPS InvalidOpcode XORPD InvalidOpcode
+parseADDPS = parseXmmVW ADDPS ADDSS ADDPD ADDSD
+parseMULPS = parseXmmVW MULPS MULSS MULPD MULSD
+parseCVTDQ2PS = parseUnimplemented
+parsePUNPCKLWD = parseUnimplemented
+parsePACKSSWB = parseUnimplemented
+parsePUNPCKHWD = parseUnimplemented
+parseSUBPS = parseXmmVW SUBPS SUBSS SUBPD SUBSD
+parseMINPS = parseXmmVW MINPS MINSS MINPD MINSD
+parseDIVPS = parseXmmVW DIVPS DIVSS DIVPD DIVSD
+parseMAXPS = parseXmmVW MAXPS MAXSS MAXPD MAXSD
+parsePUNPCKLBW = parseUnimplemented
+parsePUNPCKLDQ = parseUnimplemented
+parsePACKUSWB = parseUnimplemented
+parsePCMPGTB = parseUnimplemented
+parsePCMPGTW = parseUnimplemented
+parsePCMPGTD = parseUnimplemented
+parsePUNPCKHBW = parseUnimplemented
+parsePUNPCKHDQ = parseUnimplemented
+parsePACKSSDW = parseUnimplemented
+parsePUNPCKLQDQ = parseUnimplemented
+parsePUNPCKHQDQ = parseUnimplemented
+parsePSHUFW = parseUnimplemented
+parsePCMPEQB = parseUnimplemented
+parsePCMPEQW = parseUnimplemented
+parsePCMPEQD = parseUnimplemented
+
+parseVMREAD b = 
+    do st <- getState
+       if in64BitMode st
+         then do (op1, op2, mod, reg, rm) <- parseAddress32 OP64
+                 return $ Instr VMREAD OP64 [op1, op2]
+         else do (op1, op2, mod, reg, rm) <- parseAddress32 OP32
+                 return $ Instr VMREAD OP32 [op1, op2]
+parseVMWRITE b = 
+    do st <- getState
+       if in64BitMode st
+         then do (op1, op2, mod, reg, rm) <- parseAddress32 OP64
+                 return $ Instr VMWRITE OP64 [op1, op2]
+         else do (op1, op2, mod, reg, rm) <- parseAddress32 OP32
+                 return $ Instr VMWRITE OP32 [op1, op2]
+
+parseHADDPS = parseXmmVW InvalidOpcode InvalidOpcode HADDPD HADDPS
+parseHSUBPS = parseXmmVW InvalidOpcode InvalidOpcode HSUBPS HSUBPD
+
+parseMOVD_Q = parseUnimplemented
+
+parseJccLong b = do
+  disp <- anyIntZ
+  let disp' :: Int
+      disp' = fromIntegral disp
+  pos <- getPosition
+  st <- getState
+  return $ Instr (jccname (b .&. 0xf)) OPNONE
+        [OpAddr (fromIntegral (disp' + sourceColumn pos - 1) +
+                (startAddr st)) OPNONE]
+
+parseSETcc b = do
+  (op1, op2, mod, reg, rm) <- parseAddress32 OP8
+  case op1 of
+    OpReg name num -> return $ Instr (setccname (b .&. 0xf)) OPNONE 
+                     [OpReg (regnames8 !! fromIntegral num) num]
+    _ -> return $ Instr (setccname (b .&. 0xf)) OPNONE [op1]
+
+parseSHLD 0xa4 = 
+    do opsize <- instrOperandSize
+       (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+       b <- anyWord8
+       opsize <- instrOperandSize
+       return $ Instr SHLD opsize [op1, op2, OpImm (fromIntegral b)]
+parseSHLD 0xa5 = 
+    do opsize <- instrOperandSize
+       (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+       opsize <- instrOperandSize
+       return $ Instr SHLD opsize [op1, op2, OpReg "cl" 1]
+parseSHRD 0xac = 
+    do opsize <- instrOperandSize
+       (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+       b <- anyWord8
+       opsize <- instrOperandSize
+       return $ Instr SHRD opsize [op1, op2, OpImm (fromIntegral b)]
+parseSHRD 0xad = 
+    do opsize <- instrOperandSize
+       (op1, op2, mod, reg, rm) <- parseAddress32 opsize
+       opsize <- instrOperandSize
+       return $ Instr SHRD opsize [op1, op2, OpReg "cl" 1]
+
+parseCMPPS = parseUnimplemented
+parseMOVNTI = parseUnimplemented
+parsePINSRW = parseUnimplemented
+parsePEXTRW = parseUnimplemented
+parseSHUFPS = parseUnimplemented
+
+parseBSWAP b = 
+    do let reg = (b .&. 0xf) - 8
+       r <- registerName (fromIntegral reg)
+       opsize <- instrOperandSize
+       return $ Instr BSWAP opsize [OpReg r (fromIntegral reg)]
+
+parseADDSUBPS = parseXmmVW InvalidOpcode InvalidOpcode ADDSUBPD ADDUBPS
+
+parseMmxXmmPQVW opcode b =
+    do st <- getState
+       if hasPrefix 0x66 st
+         then do (op1, op2, mod, reg, rm) <- parseAddress32 OP128
+                 let v = OpReg (xmmregs !! (fromIntegral reg)) 
+                         (fromIntegral reg)
+                 let w = case op1 of
+                           OpReg _ num -> OpReg (xmmregs !! num) num
+                           op -> op
+                 return $ Instr opcode OP128 [v, w]
+         else do (op1, op2, mod, reg, rm) <- parseAddress32 OP64
+                 let p = OpReg (mmxregs !! (fromIntegral reg)) 
+                         (fromIntegral reg)
+                 let q = case op1 of
+                           OpReg _ num -> OpReg (mmxregs !! num) num
+                           op -> op
+                 return $ Instr opcode OP128 [p, q]
+
+parseMmxXmmMPMV opcode1 opcode2 b =
+    do st <- getState
+       if hasPrefix 0x66 st
+         then do (op1, op2, mod, reg, rm) <- parseAddress32 OP128
+                 let v = OpReg (xmmregs !! (fromIntegral reg)) 
+                         (fromIntegral reg)
+                 return $ Instr opcode2 OP128 [op1, v]
+         else do (op1, op2, mod, reg, rm) <- parseAddress32 OP64
+                 let p = OpReg (mmxregs !! (fromIntegral reg)) 
+                         (fromIntegral reg)
+                 return $ Instr opcode1 OP128 [op1, p]
+
+parseMmxXmmPNVU opcode b =
+    do st <- getState
+       if hasPrefix 0x66 st
+         then do (mod, reg, rm) <- parseModRM
+                 let v = OpReg (xmmregs !! (fromIntegral reg)) 
+                         (fromIntegral reg)
+                 let u = OpReg (xmmregs !! (fromIntegral rm))
+                         (fromIntegral reg)
+                 return $ Instr opcode OP128 [v, u]
+         else do (op1, op2, mod, reg, rm) <- parseAddress32 OP64
+                 let p = OpReg (mmxregs !! (fromIntegral reg)) 
+                         (fromIntegral reg)
+                 let n = OpReg (mmxregs !! (fromIntegral rm))
+                         (fromIntegral reg)
+                 return $ Instr opcode OP128 [p, n]
+
+parsePSRLW = parseMmxXmmPQVW PSRLW
+parsePSRLD = parseMmxXmmPQVW PSRLD
+parsePSRLQ = parseMmxXmmPQVW PSRLQ
+parsePADDQ = parseMmxXmmPQVW PADDQ
+parsePMULLW = parseMmxXmmPQVW PMULLW
+parseMOVQ b@0x6f = parseUnimplemented b
+parseMOVQ b@0x7f = parseUnimplemented b
+parseMOVQ b@0xd6 = 
+    do st <- getState
+       if hasPrefix 0x66 st
+         then do (op1, op2, mod, reg, rm) <- parseAddress32 OP64
+                 return $ Instr MOVQ OP64 [op1, op2]
+         else if hasPrefix 0xf3 st
+                 then do (mod, reg, rm) <- parseModRM
+                         return $ Instr MOVQ OPNONE 
+                                    [OpReg (xmmregs !! (fromIntegral reg))
+                                     (fromIntegral reg),
+                                     OpReg (mmxregs !! (fromIntegral rm))
+                                     (fromIntegral rm)]
+                 else
+                   if hasPrefix 0xf2 st
+                      then do (mod, reg, rm) <- parseModRM
+                              return $ Instr MOVQ OPNONE
+                               [OpReg (mmxregs !! (fromIntegral reg))
+                                (fromIntegral reg),
+                                OpReg (xmmregs !! (fromIntegral rm))
+                                (fromIntegral rm)]
+                      else parseInvalidOpcode b
+                         
+parsePMOVMSKB b = 
+    do st <- getState
+       (mod, reg, rm) <- parseModRM
+       if hasPrefix 0x66 st
+         then do return $ Instr PMOVMSKB OPNONE 
+                            [OpReg (regnames32 !! (fromIntegral reg))
+                             (fromIntegral reg),
+                             OpReg (xmmregs !! (fromIntegral rm))
+                             (fromIntegral rm)]
+         else do return $ Instr PMOVMSKB OPNONE 
+                            [OpReg (regnames32 !! (fromIntegral reg))
+                             (fromIntegral reg),
+                             OpReg (mmxregs !! (fromIntegral rm))
+                             (fromIntegral rm)]
+parsePSUBUSB = parseMmxXmmPQVW PSUBUSB
+parsePSUBUSW = parseMmxXmmPQVW PSUBUSW
+parsePMINUB = parseMmxXmmPQVW PMINUB
+parsePAND = parseMmxXmmPQVW PAND
+parsePADDUSB = parseMmxXmmPQVW PADDUSB
+parsePADDUSW = parseMmxXmmPQVW PADDUSW
+parsePMAXUB = parseMmxXmmPQVW PMAXUB
+parsePANDN = parseMmxXmmPQVW PANDN
+parsePAVGB = parseMmxXmmPQVW PAVGB
+parsePSRAW = parseMmxXmmPQVW PSRAW
+parsePSRAD = parseMmxXmmPQVW PSRAD
+parsePAVGW = parseMmxXmmPQVW PAVGW
+parseCVTPD2DQ = parseUnimplemented
+parsePMULHUW = parseMmxXmmPQVW PMULHUW
+parsePMULHW = parseMmxXmmPQVW PMULHW
+parseMOVNTQ = parseMmxXmmMPMV MOVNTQ MOVNTDQ
+parsePSUBSB = parseMmxXmmPQVW PSUBSB
+parsePSUBSQ = parseMmxXmmPQVW PSUBSQ
+parsePMINSW = parseMmxXmmPQVW PMINSW
+parsePOR = parseMmxXmmPQVW POR
+parsePADDSB = parseMmxXmmPQVW PADDSB
+parsePADDSW = parseMmxXmmPQVW PADDSW
+parsePMAXSW = parseMmxXmmPQVW PMAXSW
+parsePXOR = parseMmxXmmPQVW PXOR
+parseLDDQU b = 
+    do st <- getState
+       if hasPrefix 0xf2 st
+         then do (op1, op2, mod, reg, rm) <- parseAddress32 OP128
+                 let v = OpReg (xmmregs !! (fromIntegral reg))
+                         (fromIntegral reg)
+                 return $ Instr LDDQU OP128 [v, op1]
+         else parseInvalidOpcode b
+parsePSLLW = parseMmxXmmPQVW PSLLW
+parsePSLLD = parseMmxXmmPQVW PSLLD
+parsePSLLQ = parseMmxXmmPQVW PSLLQ
+parsePMULUDQ = parseMmxXmmPQVW PMULUDQ
+parsePMADDWD = parseMmxXmmPQVW PMADDWD
+parsePSADBW = parseMmxXmmPQVW PSADBW
+parseMASKMOVQ = parseMmxXmmPNVU MASKMOVQ
+parsePSUBB = parseMmxXmmPQVW PSUBB
+parsePSUBW = parseMmxXmmPQVW PSUBW
+parsePSUBD = parseMmxXmmPQVW PSUBD
+parsePSUBQ = parseMmxXmmPQVW PSUBQ
+parsePADDB = parseMmxXmmPQVW PADDB
+parsePADDW = parseMmxXmmPQVW PADDW
+parsePADDD = parseMmxXmmPQVW PADDD
diff --git a/disassembler.cabal b/disassembler.cabal
new file mode 100644 (file)
index 0000000..3e6344f
--- /dev/null
@@ -0,0 +1,23 @@
+name:            disassembler
+version:         0.1.0.1
+license:         BSD3
+license-file:    LICENSE
+category:        Development, Disassembler
+author:          Martin Grabmueller <martin@grabmueller.de>, Dirk Kleeblatt <klee@cs.tu-berlin.de>
+maintainer:      Martin Grabmueller <martin@grabmueller.de>
+stability:       experimental
+synopsis:        Disassembler for X86 & AMD64 machine code
+description:     Disassembler for X86 & AMD64 machine code
+cabal-version:   >= 1.2
+build-type:      Simple
+
+library
+  build-depends:
+    base >= 4 && < 5, 
+    containers >= 0.3 && < 1,
+    array >= 0.3 && < 1, 
+    mtl >= 1 && < 2,
+    parsec >= 1 && < 3
+
+  extensions: FlexibleContexts
+  exposed-modules: Text.Disassembler.X86Disassembler