1 # udis86 - scripts/ud_opcode.py
3 # Copyright (c) 2009 Vivek Thampi
6 # Redistribution and use in source and binary forms, with or without modification,
7 # are permitted provided that the following conditions are met:
9 # * Redistributions of source code must retain the above copyright notice,
10 # this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above copyright notice,
12 # this list of conditions and the following disclaimer in the documentation
13 # and/or other materials provided with the distribution.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
22 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 'opctbl' : { 'name' : 'UD_TAB__OPC_TABLE', 'size' : 256 }
,
30 '/sse' : { 'name' : 'UD_TAB__OPC_SSE', 'size' : 4 }
,
31 '/reg' : { 'name' : 'UD_TAB__OPC_REG', 'size' : 8 }
,
32 '/rm' : { 'name' : 'UD_TAB__OPC_RM', 'size' : 8 }
,
33 '/mod' : { 'name' : 'UD_TAB__OPC_MOD', 'size' : 2 }
,
34 '/m' : { 'name' : 'UD_TAB__OPC_MODE', 'size' : 3 }
,
35 '/x87' : { 'name' : 'UD_TAB__OPC_X87', 'size' : 64 }
,
36 '/a' : { 'name' : 'UD_TAB__OPC_ASIZE', 'size' : 3 }
,
37 '/o' : { 'name' : 'UD_TAB__OPC_OSIZE', 'size' : 3 }
,
38 '/3dnow' : { 'name' : 'UD_TAB__OPC_3DNOW', 'size' : 256 }
,
39 'vendor' : { 'name' : 'UD_TAB__OPC_VENDOR', 'size' : 3 }
,
83 def sizeOfTable( self
, t
):
84 return self
.TableInfo
[ t
][ 'size' ]
86 def nameOfTable( self
, t
):
87 return self
.TableInfo
[ t
][ 'name' ]
90 # Updates a table entry: If the entry doesn't exist
91 # it will create the entry, otherwise, it will walk
92 # while validating the path.
94 def updateTable( self
, table
, index
, type, meta
):
95 if not index
in table
[ 'entries' ]:
96 table
[ 'entries' ][ index
] = { 'type' : type, 'entries' : {}
, 'meta' : meta
}
97 if table
[ 'entries' ][ index
][ 'type' ] != type:
98 raise NameError( "error: violation in opcode mapping (overwrite) %s with %s." %
99 ( table
[ 'entries' ][ index
][ 'type' ], type) )
100 return table
[ 'entries' ][ index
]
103 """An abstract type representing an instruction in the opcode map.
106 # A mapping of opcode extensions to their representational
107 # values used in the opcode map.
109 '/rm' : lambda v
: "%02x" % int(v
, 16),
110 '/x87' : lambda v
: "%02x" % int(v
, 16),
111 '/3dnow' : lambda v
: "%02x" % int(v
, 16),
112 '/reg' : lambda v
: "%02x" % int(v
, 16),
114 # (!11, 11) => (00, 01)
115 '/mod' : lambda v
: '00' if v
== '!11' else '01',
117 # (16, 32, 64) => (00, 01, 02)
118 '/o' : lambda v
: "%02x" % (int(v
) / 32),
119 '/a' : lambda v
: "%02x" % (int(v
) / 32),
120 '/m' : lambda v
: "%02x" % (int(v
) / 32),
121 '/sse' : lambda v
: UdOpcodeTables
.OpcExtIndex
['sse'][v
]
124 def __init__(self
, prefixes
, mnemonic
, opcodes
, operands
, vendor
):
125 self
.opcodes
= opcodes
126 self
.prefixes
= prefixes
127 self
.mnemonic
= mnemonic
128 self
.operands
= operands
133 if self
.opcodes
[0] in ('ssef2', 'ssef3', 'sse66'):
134 ssePrefix
= self
.opcodes
[0][3:]
137 # do some preliminary decoding of the instruction type
138 # 1byte, 2byte or 3byte instruction?
140 if self
.opcodes
[0] == '0f': # 2byte
141 # 2+ byte opcodes are always disambiguated by an
142 # sse prefix, unless it is a 3d now instruction
144 if self
.opcodes
[1] != '0f' and ssePrefix
is None:
146 if self
.opcodes
[1] in ('38', '3a'): # 3byte
151 # The opcode that indexes into the opcode table.
152 self
.opcode
= self
.opcodes
[self
.nByteInsn
- 1]
154 # Record opcode extensions
155 for opcode
in self
.opcodes
[self
.nByteInsn
:]:
156 arg
, val
= opcode
.split('=')
157 self
.opcext
[arg
] = self
.OpcExtMap
[arg
](val
)
159 # Record sse extension: the reason sse extension is handled
160 # separately is that historically sse was handled as a first
161 # class opcode, not as an extension. Now that sse is handled
162 # as an extension, we do the manual conversion here, as opposed
163 # to modifying the opcode xml file.
164 if ssePrefix
is not None:
165 self
.opcext
['/sse'] = self
.OpcExtMap
['/sse'](ssePrefix
)
167 def parse(self
, table
, insn
):
168 index
= insn
.opcodes
[0];
169 if insn
.nByteInsn
> 1:
171 table
= self
.updateTable(table
, index
, 'opctbl', '0f')
172 index
= insn
.opcodes
[1]
174 if insn
.nByteInsn
== 3:
175 table
= self
.updateTable(table
, index
, 'opctbl', index
)
176 index
= insn
.opcodes
[2]
178 # Walk down the tree, create levels as needed, for opcode
179 # extensions. The order is important, and determines how
180 # well the opcode table is packed. Also note, /sse must be
181 # before /o, because /sse may consume operand size prefix
182 # affect the outcome of /o.
183 for ext
in ('/mod', '/x87', '/reg', '/rm', '/sse',
184 '/o', '/a', '/m', '/3dnow'):
185 if ext
in insn
.opcext
:
186 table
= self
.updateTable(table
, index
, ext
, ext
)
187 index
= insn
.opcext
[ext
]
189 # additional table for disambiguating vendor
191 table
= self
.updateTable(table
, index
, 'vendor', insn
.vendor
)
192 index
= self
.OpcExtIndex
['vendor'][insn
.vendor
]
194 # make leaf node entries
195 leaf
= self
.updateTable(table
, index
, 'insn', '')
197 leaf
['mnemonic'] = insn
.mnemonic
198 leaf
['prefixes'] = insn
.prefixes
199 leaf
['operands'] = insn
.operands
201 # add instruction to linear table of instruction forms
202 self
.InsnTable
.append({ 'prefixes' : insn
.prefixes
,
203 'mnemonic' : insn
.mnemonic
,
204 'operands' : insn
.operands
})
206 # add mnemonic to mnemonic table
207 if not insn
.mnemonic
in self
.MnemonicsTable
:
208 self
.MnemonicsTable
.append(insn
.mnemonic
)
211 # Adds an instruction definition to the opcode tables
212 def addInsnDef( self
, prefixes
, mnemonic
, opcodes
, operands
, vendor
):
213 insn
= self
.Insn(prefixes
=prefixes
,
218 self
.parse(self
.OpcodeTable0
, insn
)
220 def print_table( self
, table
, pfxs
):
222 keys
= table
[ 'entries' ].keys()
226 e
= table
[ 'entries' ][ idx
]
227 if e
[ 'type' ] == 'insn':
228 print("%s |-<%s>" % ( pfxs
, idx
)),
229 print("%s %s" % ( e
[ 'mnemonic' ], ' '.join( e
[ 'operands'] )))
231 print("%s |-<%s> %s" % ( pfxs
, idx
, e
['type'] ))
232 self
.print_table( e
, pfxs
+ ' |' )
234 def print_tree( self
):
235 self
.print_table( self
.OpcodeTable0
, '' )