diff options
Diffstat (limited to 'src/3rdparty/masm/disassembler/udis86/ud_opcode.py')
-rw-r--r-- | src/3rdparty/masm/disassembler/udis86/ud_opcode.py | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/src/3rdparty/masm/disassembler/udis86/ud_opcode.py b/src/3rdparty/masm/disassembler/udis86/ud_opcode.py new file mode 100644 index 0000000000..f301b52461 --- /dev/null +++ b/src/3rdparty/masm/disassembler/udis86/ud_opcode.py @@ -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, '' ) |