Mercurial > hg > truffle
comparison graal/com.oracle.max.asmdis/src/com/sun/max/asm/dis/x86/X86Disassembler.java @ 3733:e233f5660da4
Added Java files from Maxine project.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Sat, 17 Dec 2011 19:59:18 +0100 |
parents | |
children | bc8527f3071c |
comparison
equal
deleted
inserted
replaced
3732:3e2e8b8abdaf | 3733:e233f5660da4 |
---|---|
1 /* | |
2 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.sun.max.asm.dis.x86; | |
24 | |
25 import java.io.*; | |
26 import java.util.*; | |
27 | |
28 import com.sun.max.*; | |
29 import com.sun.max.asm.*; | |
30 import com.sun.max.asm.amd64.*; | |
31 import com.sun.max.asm.dis.*; | |
32 import com.sun.max.asm.gen.*; | |
33 import com.sun.max.asm.gen.cisc.x86.*; | |
34 import com.sun.max.asm.x86.*; | |
35 import com.sun.max.io.*; | |
36 import com.sun.max.lang.*; | |
37 import com.sun.max.program.*; | |
38 import com.sun.max.util.*; | |
39 | |
40 /** | |
41 * An x86 instruction disassembler. | |
42 * | |
43 * The string representation for disassembler output has the following format, | |
44 * which borrows from both Intel and AT&T syntax and differs from either | |
45 * regarding indirect addressing and indexing. | |
46 * | |
47 * Operand order follows Intel syntax: | |
48 * | |
49 * mnemonic argument | |
50 * mnemonic destination, source | |
51 * mnemonic argument1, argument2, argument3 | |
52 * | |
53 * Some mnemonics may have operand size suffixes as in AT&T (gas) syntax. | |
54 * Suffix Intel size Java size # bits | |
55 * ------ ----------- --------- ------ | |
56 * b byte byte 8 | |
57 * w word short 16 | |
58 * l long word int 32 | |
59 * q quad word long 64 | |
60 * | |
61 * Using this AT&T syntax feature, there is no need for operand size indicators | |
62 * (e.g. DWORD PTR) for pointers as in Intel syntax. | |
63 * | |
64 * Registers etc. are named as in Intel syntax, | |
65 * in lower case without AT&T's "%" prefix. | |
66 * | |
67 * Indexing is indicated by '[' and ']', similiar to array access in the Java(TM) Programming Language: | |
68 * | |
69 * base[index], e.g. eax[ebx] | |
70 * | |
71 * Indirect access looks like indexing without a base (or with implicit base 0): | |
72 * | |
73 * [indirect], e.g. [ecx] | |
74 * | |
75 * Displacements are added/subtracted from the index/indirect operand: | |
76 * | |
77 * base[index + displacement], e.g. ebp[eax - 12] | |
78 * [indirect + displacement], e.g. [esi + 100] | |
79 * | |
80 * Scale is displayed as multiplication of the index: | |
81 * | |
82 * [base[index * scale] or base[index * scale + displacement], e.g. ecx[ebx * 4 + 10] | |
83 * | |
84 * A scale of 1 is left implicit, i.e. not printed. | |
85 * Scale literals are the unsigned decimal integer numbers 2, 4, 8. | |
86 * | |
87 * Displacement literals are signed decimal integer numbers. | |
88 * | |
89 * Direct memory references (pointer literals) are unsigned hexadecimal integer numbers, e.g.: | |
90 * | |
91 * [0x12345678], 0x12345678[eax] | |
92 * | |
93 * Immediate operands are unsigned hexadecimal integer numbers, e.g.: | |
94 * | |
95 * 0x12, 0xffff, 0x0, 0x123456789abcdef | |
96 * | |
97 * Offset operands are signed decimal integer numbers, like displacements, but without space between the sign and the number, e.g.: | |
98 * | |
99 * jmp +12 | |
100 * call -2048 | |
101 * | |
102 * RIP (Relative to Instruction Pointer) addressing is a combination of an offset operand and indirect addressing, e.g.: | |
103 * | |
104 * add [+20], eax | |
105 * mov ebx, [-200] | |
106 * | |
107 * The disassembler displays synthetic labels for all target addresses | |
108 * within the disassembled address range that hit the start address of an instruction. | |
109 * Operands that coincide with such a label are displayed with the respective Label prepended. e.g.: | |
110 * | |
111 * jmp L1: +100 | |
112 * adc [L2: +128], ESI | |
113 * | |
114 * @see Disassembler | |
115 * @see X86DisassembledInstruction | |
116 */ | |
117 public abstract class X86Disassembler extends Disassembler { | |
118 | |
119 private X86Assembly<? extends X86Template> assembly; | |
120 | |
121 protected X86Disassembler(ImmediateArgument startAddress, X86Assembly<? extends X86Template> assembly, InlineDataDecoder inlineDataDecoder) { | |
122 super(startAddress, Endianness.LITTLE, inlineDataDecoder); | |
123 this.assembly = assembly; | |
124 } | |
125 | |
126 protected abstract boolean isRexPrefix(HexByte opcode); | |
127 | |
128 private X86InstructionHeader scanInstructionHeader(BufferedInputStream stream, boolean justSkip) throws IOException { | |
129 int byteValue = stream.read(); | |
130 if (byteValue < 0) { | |
131 return null; | |
132 } | |
133 final X86InstructionHeader header = new X86InstructionHeader(); | |
134 | |
135 do { | |
136 final HexByte hexByte = HexByte.VALUES.get(byteValue); | |
137 if (header.opcode1 == null) { | |
138 if (hexByte == X86Opcode.ADDRESS_SIZE) { | |
139 header.hasAddressSizePrefix = true; | |
140 } else if (hexByte == X86Opcode.OPERAND_SIZE) { | |
141 if (header.instructionSelectionPrefix != null) { | |
142 return X86InstructionHeader.INVALID; | |
143 } | |
144 header.instructionSelectionPrefix = hexByte; | |
145 } else if (hexByte == X86Opcode.REPE || hexByte == X86Opcode.REPNE) { | |
146 if (header.instructionSelectionPrefix != null) { | |
147 return X86InstructionHeader.INVALID; | |
148 } | |
149 header.instructionSelectionPrefix = hexByte; | |
150 } else if (isRexPrefix(hexByte)) { | |
151 header.rexPrefix = hexByte; | |
152 } else { | |
153 header.opcode1 = hexByte; | |
154 if (hexByte != HexByte._0F) { | |
155 break; | |
156 } | |
157 } | |
158 } else { | |
159 header.opcode2 = hexByte; | |
160 break; | |
161 } | |
162 byteValue = stream.read(); | |
163 } while (byteValue >= 0); | |
164 | |
165 if (TRACE && !justSkip) { | |
166 System.out.println("Scanned header: " + header); | |
167 } | |
168 | |
169 return justSkip ? null : header; | |
170 } | |
171 | |
172 private List<Argument> scanArguments(BufferedInputStream stream, X86Template template, X86InstructionHeader header, byte modRMByte, byte sibByte) throws IOException { | |
173 final List<Argument> arguments = new ArrayList<Argument>(); | |
174 final byte rexByte = (header.rexPrefix != null) ? header.rexPrefix.byteValue() : 0; | |
175 for (X86Parameter parameter : template.parameters()) { | |
176 int value = 0; | |
177 switch (parameter.place()) { | |
178 case MOD_REG_REXR: | |
179 value = X86Field.extractRexValue(X86Field.REX_R_BIT_INDEX, rexByte); | |
180 // fall through... | |
181 case MOD_REG: | |
182 value += X86Field.REG.extract(modRMByte); | |
183 break; | |
184 case MOD_RM_REXB: | |
185 value = X86Field.extractRexValue(X86Field.REX_B_BIT_INDEX, rexByte); | |
186 // fall through... | |
187 case MOD_RM: | |
188 value += X86Field.RM.extract(modRMByte); | |
189 break; | |
190 case SIB_BASE_REXB: | |
191 value = X86Field.extractRexValue(X86Field.REX_B_BIT_INDEX, rexByte); | |
192 // fall through... | |
193 case SIB_BASE: | |
194 value += X86Field.BASE.extract(sibByte); | |
195 break; | |
196 case SIB_INDEX_REXX: | |
197 value = X86Field.extractRexValue(X86Field.REX_X_BIT_INDEX, rexByte); | |
198 // fall through... | |
199 case SIB_INDEX: | |
200 value += X86Field.INDEX.extract(sibByte); | |
201 break; | |
202 case SIB_SCALE: | |
203 value = X86Field.SCALE.extract(sibByte); | |
204 break; | |
205 case APPEND: | |
206 if (parameter instanceof X86EnumerableParameter) { | |
207 final X86EnumerableParameter enumerableParameter = (X86EnumerableParameter) parameter; | |
208 final Enumerator enumerator = enumerableParameter.enumerator(); | |
209 arguments.add((Argument) enumerator.fromValue(endianness().readByte(stream))); | |
210 continue; | |
211 } | |
212 final X86NumericalParameter numericalParameter = (X86NumericalParameter) parameter; | |
213 switch (numericalParameter.width()) { | |
214 case BITS_8: | |
215 arguments.add(new Immediate8Argument(endianness().readByte(stream))); | |
216 break; | |
217 case BITS_16: | |
218 arguments.add(new Immediate16Argument(endianness().readShort(stream))); | |
219 break; | |
220 case BITS_32: | |
221 arguments.add(new Immediate32Argument(endianness().readInt(stream))); | |
222 break; | |
223 case BITS_64: | |
224 arguments.add(new Immediate64Argument(endianness().readLong(stream))); | |
225 break; | |
226 } | |
227 continue; | |
228 case OPCODE1_REXB: | |
229 value = X86Field.extractRexValue(X86Field.REX_B_BIT_INDEX, rexByte); | |
230 // fall through... | |
231 case OPCODE1: | |
232 value += header.opcode1.ordinal() & 7; | |
233 break; | |
234 case OPCODE2_REXB: | |
235 value = X86Field.extractRexValue(X86Field.REX_B_BIT_INDEX, rexByte); | |
236 // fall through... | |
237 case OPCODE2: | |
238 value += header.opcode2.ordinal() & 7; | |
239 break; | |
240 } | |
241 final X86EnumerableParameter enumerableParameter = (X86EnumerableParameter) parameter; | |
242 final Enumerator enumerator = enumerableParameter.enumerator(); | |
243 if (enumerator == AMD64GeneralRegister8.ENUMERATOR) { | |
244 arguments.add(AMD64GeneralRegister8.fromValue(value, header.rexPrefix != null)); | |
245 } else { | |
246 arguments.add((Argument) enumerator.fromValue(value)); | |
247 } | |
248 } | |
249 return arguments; | |
250 } | |
251 | |
252 private int getModVariantParameterIndex(X86Template template, byte modRMByte, byte sibByte) { | |
253 if (template.modCase() == X86TemplateContext.ModCase.MOD_0 && X86Field.MOD.extract(modRMByte) != X86TemplateContext.ModCase.MOD_0.value()) { | |
254 switch (template.rmCase()) { | |
255 case NORMAL: { | |
256 if (template.addressSizeAttribute() == WordWidth.BITS_16) { | |
257 if (X86Field.RM.extract(modRMByte) != X86TemplateContext.RMCase.SWORD.value()) { | |
258 return -1; | |
259 } | |
260 } else if (X86Field.RM.extract(modRMByte) != X86TemplateContext.RMCase.SDWORD.value()) { | |
261 return -1; | |
262 } | |
263 for (int i = 0; i < template.parameters().size(); i++) { | |
264 switch (template.parameters().get(i).place()) { | |
265 case MOD_RM_REXB: | |
266 case MOD_RM: | |
267 return i; | |
268 default: | |
269 break; | |
270 } | |
271 } | |
272 break; | |
273 } | |
274 case SIB: { | |
275 if (template.sibBaseCase() == X86TemplateContext.SibBaseCase.GENERAL_REGISTER && X86Field.BASE.extract(sibByte) == 5) { | |
276 for (int i = 0; i < template.parameters().size(); i++) { | |
277 switch (template.parameters().get(i).place()) { | |
278 case SIB_BASE_REXB: | |
279 case SIB_BASE: | |
280 return i; | |
281 default: | |
282 break; | |
283 } | |
284 } | |
285 } | |
286 break; | |
287 } | |
288 default: { | |
289 break; | |
290 } | |
291 } | |
292 } | |
293 return -1; | |
294 } | |
295 | |
296 private byte getSibByte(BufferedInputStream stream, X86Template template, byte modRMByte) throws IOException { | |
297 if (template.addressSizeAttribute() == WordWidth.BITS_16) { | |
298 return 0; | |
299 } | |
300 if (template.hasSibByte()) { | |
301 return endianness().readByte(stream); | |
302 } | |
303 if (template.hasModRMByte() && X86Field.RM.extract(modRMByte) == X86TemplateContext.RMCase.SIB.value() && | |
304 X86Field.MOD.extract(modRMByte) != X86TemplateContext.ModCase.MOD_3.value()) { | |
305 return endianness().readByte(stream); | |
306 } | |
307 return 0; | |
308 } | |
309 | |
310 protected abstract Map<X86InstructionHeader, List<X86Template>> headerToTemplates(); | |
311 | |
312 private static int serial; | |
313 | |
314 public DisassembledObject scanInstruction(BufferedInputStream stream, X86InstructionHeader header) throws IOException, AssemblyException { | |
315 if (header != X86InstructionHeader.INVALID) { | |
316 serial++; | |
317 Trace.line(4, "instruction: " + serial); | |
318 if (header.opcode1 != null) { | |
319 boolean isFloatingPointEscape = false; | |
320 if (X86Opcode.isFloatingPointEscape(header.opcode1)) { | |
321 final int byte2 = stream.read(); | |
322 if (byte2 >= 0xC0) { | |
323 isFloatingPointEscape = true; | |
324 header.opcode2 = HexByte.VALUES.get(byte2); | |
325 } | |
326 } | |
327 final List<X86Template> templates = headerToTemplates().get(header); | |
328 if (templates != null) { | |
329 for (X86Template template : templates) { | |
330 stream.reset(); | |
331 scanInstructionHeader(stream, true); | |
332 if (isFloatingPointEscape) { | |
333 stream.read(); | |
334 } | |
335 try { | |
336 byte modRMByte = 0; | |
337 byte sibByte = 0; | |
338 int modVariantParameterIndex = -1; | |
339 List<Argument> arguments = null; | |
340 if (template.hasModRMByte()) { | |
341 modRMByte = endianness().readByte(stream); | |
342 sibByte = getSibByte(stream, template, modRMByte); | |
343 modVariantParameterIndex = getModVariantParameterIndex(template, modRMByte, sibByte); | |
344 if (modVariantParameterIndex >= 0) { | |
345 final X86Template modVariantTemplate = X86Assembly.getModVariantTemplate(templates, template, template.parameters().get(modVariantParameterIndex).type()); | |
346 arguments = scanArguments(stream, modVariantTemplate, header, modRMByte, sibByte); | |
347 } | |
348 } | |
349 if (arguments == null) { | |
350 arguments = scanArguments(stream, template, header, modRMByte, sibByte); | |
351 } | |
352 if (modVariantParameterIndex >= 0) { | |
353 final Immediate8Argument immediateArgument = (Immediate8Argument) arguments.get(modVariantParameterIndex); | |
354 if (immediateArgument.value() != 0) { | |
355 continue; | |
356 } | |
357 | |
358 // Remove the mod variant argument | |
359 final Argument modVariantArgument = arguments.get(modVariantParameterIndex); | |
360 final List<Argument> result = new ArrayList<Argument>(); | |
361 for (Argument argument : arguments) { | |
362 if (modVariantArgument != argument) { | |
363 result.add(argument); | |
364 } | |
365 } | |
366 arguments = result; | |
367 } | |
368 if (!(Utils.indexOfIdentical(arguments, null) != -1)) { | |
369 byte[] bytes; | |
370 if (true) { | |
371 final Assembler assembler = createAssembler(currentPosition); | |
372 try { | |
373 assembly.assemble(assembler, template, arguments); | |
374 } catch (AssemblyException e) { | |
375 // try the next template | |
376 continue; | |
377 } | |
378 bytes = assembler.toByteArray(); | |
379 } else { // TODO: does not work yet | |
380 final X86TemplateAssembler templateAssembler = new X86TemplateAssembler(template, addressWidth()); | |
381 bytes = templateAssembler.assemble(arguments); | |
382 } | |
383 if (bytes != null) { | |
384 stream.reset(); | |
385 if (Streams.startsWith(stream, bytes)) { | |
386 final DisassembledInstruction disassembledInstruction = createDisassembledInstruction(currentPosition, bytes, template, arguments); | |
387 currentPosition += bytes.length; | |
388 return disassembledInstruction; | |
389 } | |
390 } | |
391 } | |
392 } catch (NoSuchAssemblerMethodError e) { | |
393 // Until the X86TemplateAssembler is complete, only templates for which a generated assembler | |
394 // method exists can be disassembled | |
395 } catch (IOException ioException) { | |
396 // this one did not work, so loop back up and try another template | |
397 } | |
398 } | |
399 } | |
400 } | |
401 if (header.instructionSelectionPrefix == X86Opcode.REPE || header.instructionSelectionPrefix == X86Opcode.REPNE) { | |
402 | |
403 stream.reset(); | |
404 final int size = 1; | |
405 final byte[] data = new byte[size]; | |
406 Streams.readFully(stream, data); | |
407 | |
408 final X86InstructionHeader prefixHeader = new X86InstructionHeader(); | |
409 prefixHeader.opcode1 = header.instructionSelectionPrefix; | |
410 final List<X86Template> prefixTemplates = headerToTemplates().get(prefixHeader); | |
411 final X86Template template = Utils.first(prefixTemplates); | |
412 final byte[] bytes = new byte[]{header.instructionSelectionPrefix.byteValue()}; | |
413 List<Argument> empty = Collections.emptyList(); | |
414 final DisassembledInstruction disassembledInstruction = createDisassembledInstruction(currentPosition, bytes, template, empty); | |
415 currentPosition++; | |
416 return disassembledInstruction; | |
417 } | |
418 } | |
419 if (INLINE_INVALID_INSTRUCTIONS_AS_BYTES) { | |
420 stream.reset(); | |
421 final int size = 1; | |
422 final byte[] data = new byte[size]; | |
423 Streams.readFully(stream, data); | |
424 final InlineData inlineData = new InlineData(currentPosition, data); | |
425 final DisassembledData disassembledData = createDisassembledDataObjects(inlineData).iterator().next(); | |
426 currentPosition += size; | |
427 return disassembledData; | |
428 } | |
429 throw new AssemblyException("unknown instruction"); | |
430 } | |
431 | |
432 /** | |
433 * Creates a disassembled instruction based on a given sequence of bytes, a template and a set of arguments. The | |
434 * caller has performed the necessary decoding of the bytes to derive the template and arguments. | |
435 * | |
436 * @param position the position an instruction stream from which the bytes were read | |
437 * @param bytes the bytes of an instruction | |
438 * @param template the template that corresponds to the instruction encoded in {@code bytes} | |
439 * @param arguments the arguments of the instruction encoded in {@code bytes} | |
440 * @return a disassembled instruction representing the result of decoding {@code bytes} into an instruction | |
441 */ | |
442 protected X86DisassembledInstruction createDisassembledInstruction(int position, byte[] bytes, X86Template template, List<Argument> arguments) { | |
443 return new X86DisassembledInstruction(this, position, bytes, template, arguments); | |
444 } | |
445 | |
446 private static final int MORE_THAN_ANY_INSTRUCTION_LENGTH = 100; | |
447 private static final boolean INLINE_INVALID_INSTRUCTIONS_AS_BYTES = true; | |
448 | |
449 @Override | |
450 public List<DisassembledObject> scanOne0(BufferedInputStream stream) throws IOException, AssemblyException { | |
451 final List<DisassembledObject> disassembledObjects = new ArrayList<DisassembledObject>(); | |
452 stream.mark(MORE_THAN_ANY_INSTRUCTION_LENGTH); | |
453 final X86InstructionHeader header = scanInstructionHeader(stream, false); | |
454 if (header == null) { | |
455 throw new AssemblyException("unknown instruction"); | |
456 } | |
457 disassembledObjects.add(scanInstruction(stream, header)); | |
458 return disassembledObjects; | |
459 } | |
460 | |
461 @Override | |
462 public List<DisassembledObject> scan0(BufferedInputStream stream) throws IOException, AssemblyException { | |
463 final SortedSet<Integer> knownGoodCodePositions = new TreeSet<Integer>(); | |
464 final List<DisassembledObject> result = new ArrayList<DisassembledObject>(); | |
465 boolean processingKnownValidCode = true; | |
466 | |
467 while (true) { | |
468 while (knownGoodCodePositions.size() > 0 && knownGoodCodePositions.first().intValue() < currentPosition) { | |
469 knownGoodCodePositions.remove(knownGoodCodePositions.first()); | |
470 } | |
471 | |
472 scanInlineData(stream, result); | |
473 | |
474 stream.mark(MORE_THAN_ANY_INSTRUCTION_LENGTH); | |
475 | |
476 final X86InstructionHeader header = scanInstructionHeader(stream, false); | |
477 if (header == null) { | |
478 return result; | |
479 } | |
480 final DisassembledObject disassembledObject = scanInstruction(stream, header); | |
481 | |
482 if (knownGoodCodePositions.size() > 0) { | |
483 final int firstKnownGoodCodePosition = knownGoodCodePositions.first().intValue(); | |
484 final int startPosition = disassembledObject.startPosition(); | |
485 if (firstKnownGoodCodePosition > startPosition && firstKnownGoodCodePosition < disassembledObject.endPosition()) { | |
486 // there is a known valid code location in the middle of this instruction - assume that it is an invalid instruction | |
487 stream.reset(); | |
488 final int size = firstKnownGoodCodePosition - startPosition; | |
489 final byte[] data = new byte[size]; | |
490 Streams.readFully(stream, data); | |
491 final InlineData inlineData = new InlineData(startPosition, data); | |
492 currentPosition += addDisassembledDataObjects(result, inlineData); | |
493 processingKnownValidCode = true; | |
494 } else { | |
495 result.add(disassembledObject); | |
496 if (firstKnownGoodCodePosition == startPosition) { | |
497 processingKnownValidCode = true; | |
498 } | |
499 } | |
500 } else { | |
501 if (processingKnownValidCode && disassembledObject instanceof DisassembledInstruction) { | |
502 final DisassembledInstruction disassembledInstruction = (DisassembledInstruction) disassembledObject; | |
503 if (isRelativeJumpForward(disassembledInstruction)) { | |
504 int jumpOffset; | |
505 if (Utils.first(disassembledInstruction.arguments()) instanceof Immediate32Argument) { | |
506 jumpOffset = ((Immediate32Argument) Utils.first(disassembledInstruction.arguments())).value(); | |
507 } else { | |
508 assert Utils.first(disassembledInstruction.arguments()) instanceof Immediate8Argument; | |
509 jumpOffset = ((Immediate8Argument) Utils.first(disassembledInstruction.arguments())).value(); | |
510 } | |
511 final int targetPosition = disassembledInstruction.endPosition() + jumpOffset; | |
512 knownGoodCodePositions.add(targetPosition); | |
513 processingKnownValidCode = false; | |
514 } | |
515 } | |
516 result.add(disassembledObject); | |
517 } | |
518 } | |
519 } | |
520 | |
521 private boolean isRelativeJumpForward(DisassembledInstruction instruction) { | |
522 return instruction.template().internalName().equals("jmp") && // check if this is a jump instruction... | |
523 instruction.arguments().size() == 1 && // that accepts one operand... | |
524 ((Utils.first(instruction.arguments()) instanceof Immediate32Argument && // which is a relative offset... | |
525 ((Immediate32Argument) Utils.first(instruction.arguments())).value() >= 0) || // forward in the code stream | |
526 (Utils.first(instruction.arguments()) instanceof Immediate8Argument && // which is a relative offset... | |
527 ((Immediate8Argument) Utils.first(instruction.arguments())).value() >= 0)); // forward in the code stream | |
528 } | |
529 | |
530 @Override | |
531 public ImmediateArgument addressForRelativeAddressing(DisassembledInstruction di) { | |
532 return startAddress().plus(di.endPosition()); | |
533 } | |
534 | |
535 @Override | |
536 public String mnemonic(DisassembledInstruction di) { | |
537 return di.template().externalName(); | |
538 } | |
539 | |
540 @Override | |
541 public String operandsToString(DisassembledInstruction di, AddressMapper addressMapper) { | |
542 final LinkedList<X86Operand> operandQueue = new LinkedList<X86Operand>(); | |
543 for (Operand operand : di.template().operands()) { | |
544 operandQueue.add((X86Operand) operand); | |
545 } | |
546 final LinkedList<Argument> argumentQueue = new LinkedList<Argument>(di.arguments()); | |
547 String result = ""; | |
548 String separator = ""; | |
549 while (!operandQueue.isEmpty()) { | |
550 result += separator + getOperand(di, operandQueue, argumentQueue, addressMapper); | |
551 separator = ", "; | |
552 } | |
553 return result; | |
554 } | |
555 | |
556 @Override | |
557 public String toString(DisassembledInstruction di, AddressMapper addressMapper) { | |
558 String s = operandsToString(di, addressMapper); | |
559 if (s.length() > 0) { | |
560 s = " " + s; | |
561 } | |
562 return Strings.padLengthWithSpaces(mnemonic(di), 8) + s; | |
563 } | |
564 | |
565 private String getSibIndexAndScale(Queue<X86Operand> operands, Queue<Argument> arguments) { | |
566 X86Parameter parameter = (X86Parameter) operands.remove(); | |
567 assert parameter.place() == ParameterPlace.SIB_INDEX || parameter.place() == ParameterPlace.SIB_INDEX_REXX; | |
568 final String result = arguments.remove().disassembledValue(); | |
569 parameter = (X86Parameter) operands.remove(); | |
570 assert parameter.place() == ParameterPlace.SIB_SCALE; | |
571 final Scale scale = (Scale) arguments.remove(); | |
572 if (scale == Scale.SCALE_1) { | |
573 return result; | |
574 } | |
575 return result + " * " + scale.disassembledValue(); | |
576 } | |
577 | |
578 private String addition(Argument argument, String space) { | |
579 assert argument instanceof ImmediateArgument; | |
580 final long value = argument.asLong(); | |
581 final String s = Long.toString(value); | |
582 if (value >= 0) { | |
583 return "+" + space + s; | |
584 } | |
585 return "-" + space + s.substring(1); | |
586 } | |
587 | |
588 private String getOperand(DisassembledInstruction di, Queue<X86Operand> operands, Queue<Argument> arguments, AddressMapper addressMapper) { | |
589 final X86Operand operand = operands.remove(); | |
590 if (operand instanceof ImplicitOperand) { | |
591 final ImplicitOperand implicitOperand = (ImplicitOperand) operand; | |
592 return implicitOperand.argument().disassembledValue(); | |
593 } | |
594 final X86Parameter parameter = (X86Parameter) operand; | |
595 final Argument argument = arguments.remove(); | |
596 if (parameter instanceof X86DisplacementParameter) { | |
597 assert parameter.place() == ParameterPlace.APPEND; | |
598 final X86Parameter nextParameter = (X86Parameter) operands.element(); | |
599 String prefix = ""; | |
600 if (IndirectRegister.class.isAssignableFrom(nextParameter.type())) { | |
601 operands.remove(); | |
602 prefix += "[" + arguments.remove().disassembledValue(); | |
603 } else { | |
604 if (nextParameter.place() == ParameterPlace.SIB_BASE || nextParameter.place() == ParameterPlace.SIB_BASE_REXB) { | |
605 operands.remove(); | |
606 prefix += arguments.remove().disassembledValue(); | |
607 } | |
608 prefix += "[" + getSibIndexAndScale(operands, arguments); | |
609 } | |
610 return prefix + " " + addition(argument, " ") + "]"; | |
611 } | |
612 if (parameter.place() == ParameterPlace.SIB_BASE || parameter.place() == ParameterPlace.SIB_BASE_REXB) { | |
613 return argument.disassembledValue() + "[" + getSibIndexAndScale(operands, arguments) + "]"; | |
614 } | |
615 if (IndirectRegister.class.isAssignableFrom(parameter.type())) { | |
616 return "[" + argument.disassembledValue() + "]"; | |
617 } | |
618 if (parameter instanceof X86AddressParameter) { | |
619 String address = argument.disassembledValue(); | |
620 final DisassembledLabel label = addressMapper.labelAt((ImmediateArgument) argument); | |
621 if (label != null) { | |
622 address = label.name() + ": " + address; | |
623 } | |
624 final X86Operand nextOperand = operands.peek(); | |
625 if (nextOperand instanceof X86Parameter) { | |
626 final X86Parameter nextParameter = (X86Parameter) nextOperand; | |
627 if (nextParameter.place() == ParameterPlace.SIB_INDEX || nextParameter.place() == ParameterPlace.SIB_INDEX_REXX) { | |
628 return address + "[" + getSibIndexAndScale(operands, arguments) + "]"; | |
629 } | |
630 } | |
631 return "[" + address + "]"; | |
632 } | |
633 if (parameter instanceof X86OffsetParameter) { | |
634 String offset = addition(argument, ""); | |
635 final ImmediateArgument targetAddress = di.addressForRelativeAddressing().plus((ImmediateArgument) argument); | |
636 final DisassembledLabel label = addressMapper.labelAt(targetAddress); | |
637 if (label != null) { | |
638 offset = label.name() + ": " + offset; | |
639 } | |
640 if (((X86Template) di.template()).addressSizeAttribute() == WordWidth.BITS_64 && ((X86Template) di.template()).rmCase() == X86TemplateContext.RMCase.SDWORD) { | |
641 return "[" + offset + "]"; // RIP | |
642 } | |
643 return offset; | |
644 } | |
645 if (parameter.getClass() == X86ImmediateParameter.class) { | |
646 return argument.disassembledValue(); | |
647 } | |
648 return argument.disassembledValue(); | |
649 } | |
650 } |