]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - disassembler/udis86/ud_opcode.py
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / disassembler / udis86 / ud_opcode.py
diff --git a/disassembler/udis86/ud_opcode.py b/disassembler/udis86/ud_opcode.py
new file mode 100644 (file)
index 0000000..f301b52
--- /dev/null
@@ -0,0 +1,235 @@
+# udis86 - scripts/ud_opcode.py
+# 
+# Copyright (c) 2009 Vivek Thampi
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without modification, 
+# are permitted provided that the following conditions are met:
+# 
+#     * Redistributions of source code must retain the above copyright notice, 
+#       this list of conditions and the following disclaimer.
+#     * 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.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 COPYRIGHT OWNER 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.
+
+class UdOpcodeTables:
+
+    TableInfo = {
+        'opctbl'    : { 'name' : 'UD_TAB__OPC_TABLE',   'size' : 256 },
+        '/sse'      : { 'name' : 'UD_TAB__OPC_SSE',     'size' : 4 },
+        '/reg'      : { 'name' : 'UD_TAB__OPC_REG',     'size' : 8 },
+        '/rm'       : { 'name' : 'UD_TAB__OPC_RM',      'size' : 8 },
+        '/mod'      : { 'name' : 'UD_TAB__OPC_MOD',     'size' : 2 },
+        '/m'        : { 'name' : 'UD_TAB__OPC_MODE',    'size' : 3 },
+        '/x87'      : { 'name' : 'UD_TAB__OPC_X87',     'size' : 64 },
+        '/a'        : { 'name' : 'UD_TAB__OPC_ASIZE',   'size' : 3 },
+        '/o'        : { 'name' : 'UD_TAB__OPC_OSIZE',   'size' : 3 },
+        '/3dnow'    : { 'name' : 'UD_TAB__OPC_3DNOW',   'size' : 256 },
+        'vendor'    : { 'name' : 'UD_TAB__OPC_VENDOR',  'size' : 3 },
+    }
+
+    OpcodeTable0 = {
+        'type'      : 'opctbl',
+        'entries'   : {},
+        'meta'      : 'table0'
+    }
+
+    OpcExtIndex = {
+
+        # ssef2, ssef3, sse66
+        'sse': {
+            'none' : '00', 
+            'f2'   : '01', 
+            'f3'   : '02', 
+            '66'   : '03'
+        },
+
+        # /mod=
+        'mod': {
+            '!11'   : '00', 
+            '11'    : '01'
+        },
+
+        # /m=, /o=, /a=
+        'mode': { 
+            '16'    : '00', 
+            '32'    : '01', 
+            '64'    : '02'
+        },
+
+        'vendor' : {
+            'amd'   : '00',
+            'intel' : '01',
+            'any'   : '02'
+        }
+    }
+
+    InsnTable = []
+    MnemonicsTable = []
+
+    ThreeDNowTable = {}
+
+    def sizeOfTable( self, t ): 
+        return self.TableInfo[ t ][ 'size' ]
+
+    def nameOfTable( self, t ): 
+        return self.TableInfo[ t ][ 'name' ]
+
+    #
+    # Updates a table entry: If the entry doesn't exist
+    # it will create the entry, otherwise, it will walk
+    # while validating the path.
+    #
+    def updateTable( self, table, index, type, meta ):
+        if not index in table[ 'entries' ]:
+            table[ 'entries' ][ index ] = { 'type' : type, 'entries' : {}, 'meta' : meta } 
+        if table[ 'entries' ][ index ][ 'type' ] != type:
+            raise NameError( "error: violation in opcode mapping (overwrite) %s with %s." % 
+                                ( table[ 'entries' ][ index ][ 'type' ], type) )
+        return table[ 'entries' ][ index ]
+
+    class Insn:
+        """An abstract type representing an instruction in the opcode map.
+        """
+
+        # A mapping of opcode extensions to their representational
+        # values used in the opcode map.
+        OpcExtMap = {
+            '/rm'    : lambda v: "%02x" % int(v, 16),
+            '/x87'   : lambda v: "%02x" % int(v, 16),
+            '/3dnow' : lambda v: "%02x" % int(v, 16),
+            '/reg'   : lambda v: "%02x" % int(v, 16),
+            # modrm.mod
+            # (!11, 11)    => (00, 01)
+            '/mod'   : lambda v: '00' if v == '!11' else '01',
+            # Mode extensions:
+            # (16, 32, 64) => (00, 01, 02)
+            '/o'     : lambda v: "%02x" % (int(v) / 32),
+            '/a'     : lambda v: "%02x" % (int(v) / 32),
+            '/m'     : lambda v: "%02x" % (int(v) / 32),
+            '/sse'   : lambda v: UdOpcodeTables.OpcExtIndex['sse'][v]
+        }
+
+        def __init__(self, prefixes, mnemonic, opcodes, operands, vendor):
+            self.opcodes  = opcodes
+            self.prefixes = prefixes
+            self.mnemonic = mnemonic
+            self.operands = operands
+            self.vendor   = vendor
+            self.opcext   = {}
+
+            ssePrefix = None
+            if self.opcodes[0] in ('ssef2', 'ssef3', 'sse66'):
+                ssePrefix = self.opcodes[0][3:]
+                self.opcodes.pop(0)
+
+            # do some preliminary decoding of the instruction type
+            # 1byte, 2byte or 3byte instruction?
+            self.nByteInsn = 1
+            if self.opcodes[0] == '0f': # 2byte
+                # 2+ byte opcodes are always disambiguated by an
+                # sse prefix, unless it is a 3d now instruction
+                # which is 0f 0f ...
+                if self.opcodes[1] != '0f' and ssePrefix is None:
+                    ssePrefix = 'none'
+                if self.opcodes[1] in ('38', '3a'): # 3byte
+                    self.nByteInsn = 3
+                else:
+                    self.nByteInsn = 2
+           
+            # The opcode that indexes into the opcode table.
+            self.opcode = self.opcodes[self.nByteInsn - 1]
+            
+            # Record opcode extensions
+            for opcode in self.opcodes[self.nByteInsn:]:
+                arg, val = opcode.split('=')
+                self.opcext[arg] = self.OpcExtMap[arg](val)
+
+            # Record sse extension: the reason sse extension is handled 
+            # separately is that historically sse was handled as a first
+            # class opcode, not as an extension. Now that sse is handled
+            # as an extension, we do the manual conversion here, as opposed
+            # to modifying the opcode xml file.
+            if ssePrefix is not None:
+                self.opcext['/sse'] = self.OpcExtMap['/sse'](ssePrefix)
+
+    def parse(self, table, insn):
+        index = insn.opcodes[0];
+        if insn.nByteInsn > 1:
+            assert index == '0f'
+            table = self.updateTable(table, index, 'opctbl', '0f')
+            index = insn.opcodes[1]
+
+            if insn.nByteInsn == 3:
+                table = self.updateTable(table, index, 'opctbl', index)
+                index = insn.opcodes[2]
+
+        # Walk down the tree, create levels as needed, for opcode
+        # extensions. The order is important, and determines how
+        # well the opcode table is packed. Also note, /sse must be
+        # before /o, because /sse may consume operand size prefix
+        # affect the outcome of /o.
+        for ext in ('/mod', '/x87', '/reg', '/rm', '/sse',
+                    '/o',   '/a',   '/m',   '/3dnow'):
+            if ext in insn.opcext:
+                table = self.updateTable(table, index, ext, ext)
+                index = insn.opcext[ext]
+
+        # additional table for disambiguating vendor
+        if len(insn.vendor):
+            table = self.updateTable(table, index, 'vendor', insn.vendor)
+            index = self.OpcExtIndex['vendor'][insn.vendor]
+
+        # make leaf node entries
+        leaf = self.updateTable(table, index, 'insn', '')
+
+        leaf['mnemonic'] = insn.mnemonic
+        leaf['prefixes'] = insn.prefixes
+        leaf['operands'] = insn.operands
+
+        # add instruction to linear table of instruction forms
+        self.InsnTable.append({ 'prefixes' : insn.prefixes,  
+                                'mnemonic' : insn.mnemonic, 
+                                'operands' : insn.operands })
+
+        # add mnemonic to mnemonic table
+        if not insn.mnemonic in self.MnemonicsTable:
+            self.MnemonicsTable.append(insn.mnemonic)
+
+
+    # Adds an instruction definition to the opcode tables
+    def addInsnDef( self, prefixes, mnemonic, opcodes, operands, vendor ):
+        insn = self.Insn(prefixes=prefixes,
+                    mnemonic=mnemonic,
+                    opcodes=opcodes,
+                    operands=operands,
+                    vendor=vendor)
+        self.parse(self.OpcodeTable0, insn)
+
+    def print_table( self, table, pfxs ):
+        print "%s   |" % pfxs
+        keys = table[ 'entries' ].keys()
+        if ( len( keys ) ):
+            keys.sort()
+        for idx in keys:
+            e = table[ 'entries' ][ idx ]
+            if e[ 'type' ] == 'insn':
+                print "%s   |-<%s>" % ( pfxs, idx ),
+                print  "%s %s" % ( e[ 'mnemonic' ], ' '.join( e[ 'operands'] ) )
+            else:
+                print "%s   |-<%s> %s" % ( pfxs, idx, e['type'] )
+                self.print_table( e, pfxs + '   |' )
+
+    def print_tree( self ): 
+        self.print_table( self.OpcodeTable0, '' )