OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/disassembler.h" | 5 #include "vm/disassembler.h" |
6 | 6 |
7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
8 #if defined(TARGET_ARCH_X64) | 8 #if defined(TARGET_ARCH_X64) |
9 #include "platform/utils.h" | 9 #include "platform/utils.h" |
10 #include "vm/allocation.h" | 10 #include "vm/allocation.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 // Tables | 33 // Tables |
34 //------------------------------------------------------------------ | 34 //------------------------------------------------------------------ |
35 struct ByteMnemonic { | 35 struct ByteMnemonic { |
36 int b; // -1 terminates, otherwise must be in range (0..255) | 36 int b; // -1 terminates, otherwise must be in range (0..255) |
37 OperandType op_order_; | 37 OperandType op_order_; |
38 const char* mnem; | 38 const char* mnem; |
39 }; | 39 }; |
40 | 40 |
41 | 41 |
42 static const ByteMnemonic two_operands_instr[] = { | 42 static const ByteMnemonic two_operands_instr[] = { |
43 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" }, | 43 {0x00, BYTE_OPER_REG_OP_ORDER, "add"}, |
44 { 0x01, OPER_REG_OP_ORDER, "add" }, | 44 {0x01, OPER_REG_OP_ORDER, "add"}, |
45 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" }, | 45 {0x02, BYTE_REG_OPER_OP_ORDER, "add"}, |
46 { 0x03, REG_OPER_OP_ORDER, "add" }, | 46 {0x03, REG_OPER_OP_ORDER, "add"}, |
47 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" }, | 47 {0x08, BYTE_OPER_REG_OP_ORDER, "or"}, |
48 { 0x09, OPER_REG_OP_ORDER, "or" }, | 48 {0x09, OPER_REG_OP_ORDER, "or"}, |
49 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" }, | 49 {0x0A, BYTE_REG_OPER_OP_ORDER, "or"}, |
50 { 0x0B, REG_OPER_OP_ORDER, "or" }, | 50 {0x0B, REG_OPER_OP_ORDER, "or"}, |
51 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" }, | 51 {0x10, BYTE_OPER_REG_OP_ORDER, "adc"}, |
52 { 0x11, OPER_REG_OP_ORDER, "adc" }, | 52 {0x11, OPER_REG_OP_ORDER, "adc"}, |
53 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" }, | 53 {0x12, BYTE_REG_OPER_OP_ORDER, "adc"}, |
54 { 0x13, REG_OPER_OP_ORDER, "adc" }, | 54 {0x13, REG_OPER_OP_ORDER, "adc"}, |
55 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" }, | 55 {0x18, BYTE_OPER_REG_OP_ORDER, "sbb"}, |
56 { 0x19, OPER_REG_OP_ORDER, "sbb" }, | 56 {0x19, OPER_REG_OP_ORDER, "sbb"}, |
57 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" }, | 57 {0x1A, BYTE_REG_OPER_OP_ORDER, "sbb"}, |
58 { 0x1B, REG_OPER_OP_ORDER, "sbb" }, | 58 {0x1B, REG_OPER_OP_ORDER, "sbb"}, |
59 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" }, | 59 {0x20, BYTE_OPER_REG_OP_ORDER, "and"}, |
60 { 0x21, OPER_REG_OP_ORDER, "and" }, | 60 {0x21, OPER_REG_OP_ORDER, "and"}, |
61 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" }, | 61 {0x22, BYTE_REG_OPER_OP_ORDER, "and"}, |
62 { 0x23, REG_OPER_OP_ORDER, "and" }, | 62 {0x23, REG_OPER_OP_ORDER, "and"}, |
63 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" }, | 63 {0x28, BYTE_OPER_REG_OP_ORDER, "sub"}, |
64 { 0x29, OPER_REG_OP_ORDER, "sub" }, | 64 {0x29, OPER_REG_OP_ORDER, "sub"}, |
65 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" }, | 65 {0x2A, BYTE_REG_OPER_OP_ORDER, "sub"}, |
66 { 0x2B, REG_OPER_OP_ORDER, "sub" }, | 66 {0x2B, REG_OPER_OP_ORDER, "sub"}, |
67 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" }, | 67 {0x30, BYTE_OPER_REG_OP_ORDER, "xor"}, |
68 { 0x31, OPER_REG_OP_ORDER, "xor" }, | 68 {0x31, OPER_REG_OP_ORDER, "xor"}, |
69 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" }, | 69 {0x32, BYTE_REG_OPER_OP_ORDER, "xor"}, |
70 { 0x33, REG_OPER_OP_ORDER, "xor" }, | 70 {0x33, REG_OPER_OP_ORDER, "xor"}, |
71 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" }, | 71 {0x38, BYTE_OPER_REG_OP_ORDER, "cmp"}, |
72 { 0x39, OPER_REG_OP_ORDER, "cmp" }, | 72 {0x39, OPER_REG_OP_ORDER, "cmp"}, |
73 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" }, | 73 {0x3A, BYTE_REG_OPER_OP_ORDER, "cmp"}, |
74 { 0x3B, REG_OPER_OP_ORDER, "cmp" }, | 74 {0x3B, REG_OPER_OP_ORDER, "cmp"}, |
75 { 0x63, REG_OPER_OP_ORDER, "movsxd" }, | 75 {0x63, REG_OPER_OP_ORDER, "movsxd"}, |
76 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" }, | 76 {0x84, BYTE_REG_OPER_OP_ORDER, "test"}, |
77 { 0x85, REG_OPER_OP_ORDER, "test" }, | 77 {0x85, REG_OPER_OP_ORDER, "test"}, |
78 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" }, | 78 {0x86, BYTE_REG_OPER_OP_ORDER, "xchg"}, |
79 { 0x87, REG_OPER_OP_ORDER, "xchg" }, | 79 {0x87, REG_OPER_OP_ORDER, "xchg"}, |
80 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" }, | 80 {0x88, BYTE_OPER_REG_OP_ORDER, "mov"}, |
81 { 0x89, OPER_REG_OP_ORDER, "mov" }, | 81 {0x89, OPER_REG_OP_ORDER, "mov"}, |
82 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" }, | 82 {0x8A, BYTE_REG_OPER_OP_ORDER, "mov"}, |
83 { 0x8B, REG_OPER_OP_ORDER, "mov" }, | 83 {0x8B, REG_OPER_OP_ORDER, "mov"}, |
84 { 0x8D, REG_OPER_OP_ORDER, "lea" }, | 84 {0x8D, REG_OPER_OP_ORDER, "lea"}, |
85 { -1, UNSET_OP_ORDER, "" } | 85 {-1, UNSET_OP_ORDER, ""}}; |
86 }; | |
87 | 86 |
88 | 87 |
89 static const ByteMnemonic zero_operands_instr[] = { | 88 static const ByteMnemonic zero_operands_instr[] = { |
90 { 0xC3, UNSET_OP_ORDER, "ret" }, | 89 {0xC3, UNSET_OP_ORDER, "ret"}, {0xC9, UNSET_OP_ORDER, "leave"}, |
91 { 0xC9, UNSET_OP_ORDER, "leave" }, | 90 {0xF4, UNSET_OP_ORDER, "hlt"}, {0xFC, UNSET_OP_ORDER, "cld"}, |
92 { 0xF4, UNSET_OP_ORDER, "hlt" }, | 91 {0xCC, UNSET_OP_ORDER, "int3"}, {0x60, UNSET_OP_ORDER, "pushad"}, |
93 { 0xFC, UNSET_OP_ORDER, "cld" }, | 92 {0x61, UNSET_OP_ORDER, "popad"}, {0x9C, UNSET_OP_ORDER, "pushfd"}, |
94 { 0xCC, UNSET_OP_ORDER, "int3" }, | 93 {0x9D, UNSET_OP_ORDER, "popfd"}, {0x9E, UNSET_OP_ORDER, "sahf"}, |
95 { 0x60, UNSET_OP_ORDER, "pushad" }, | 94 {0x99, UNSET_OP_ORDER, "cdq"}, {0x9B, UNSET_OP_ORDER, "fwait"}, |
96 { 0x61, UNSET_OP_ORDER, "popad" }, | 95 {0xA4, UNSET_OP_ORDER, "movs"}, {0xA5, UNSET_OP_ORDER, "movs"}, |
97 { 0x9C, UNSET_OP_ORDER, "pushfd" }, | 96 {0xA6, UNSET_OP_ORDER, "cmps"}, {0xA7, UNSET_OP_ORDER, "cmps"}, |
98 { 0x9D, UNSET_OP_ORDER, "popfd" }, | 97 {-1, UNSET_OP_ORDER, ""}}; |
99 { 0x9E, UNSET_OP_ORDER, "sahf" }, | |
100 { 0x99, UNSET_OP_ORDER, "cdq" }, | |
101 { 0x9B, UNSET_OP_ORDER, "fwait" }, | |
102 { 0xA4, UNSET_OP_ORDER, "movs" }, | |
103 { 0xA5, UNSET_OP_ORDER, "movs" }, | |
104 { 0xA6, UNSET_OP_ORDER, "cmps" }, | |
105 { 0xA7, UNSET_OP_ORDER, "cmps" }, | |
106 { -1, UNSET_OP_ORDER, "" } | |
107 }; | |
108 | 98 |
109 | 99 |
110 static const ByteMnemonic call_jump_instr[] = { | 100 static const ByteMnemonic call_jump_instr[] = {{0xE8, UNSET_OP_ORDER, "call"}, |
111 { 0xE8, UNSET_OP_ORDER, "call" }, | 101 {0xE9, UNSET_OP_ORDER, "jmp"}, |
112 { 0xE9, UNSET_OP_ORDER, "jmp" }, | 102 {-1, UNSET_OP_ORDER, ""}}; |
113 { -1, UNSET_OP_ORDER, "" } | |
114 }; | |
115 | 103 |
116 | 104 |
117 static const ByteMnemonic short_immediate_instr[] = { | 105 static const ByteMnemonic short_immediate_instr[] = { |
118 { 0x05, UNSET_OP_ORDER, "add" }, | 106 {0x05, UNSET_OP_ORDER, "add"}, {0x0D, UNSET_OP_ORDER, "or"}, |
119 { 0x0D, UNSET_OP_ORDER, "or" }, | 107 {0x15, UNSET_OP_ORDER, "adc"}, {0x1D, UNSET_OP_ORDER, "sbb"}, |
120 { 0x15, UNSET_OP_ORDER, "adc" }, | 108 {0x25, UNSET_OP_ORDER, "and"}, {0x2D, UNSET_OP_ORDER, "sub"}, |
121 { 0x1D, UNSET_OP_ORDER, "sbb" }, | 109 {0x35, UNSET_OP_ORDER, "xor"}, {0x3D, UNSET_OP_ORDER, "cmp"}, |
122 { 0x25, UNSET_OP_ORDER, "and" }, | 110 {-1, UNSET_OP_ORDER, ""}}; |
123 { 0x2D, UNSET_OP_ORDER, "sub" }, | |
124 { 0x35, UNSET_OP_ORDER, "xor" }, | |
125 { 0x3D, UNSET_OP_ORDER, "cmp" }, | |
126 { -1, UNSET_OP_ORDER, "" } | |
127 }; | |
128 | 111 |
129 | 112 |
130 static const char* const conditional_code_suffix[] = { | 113 static const char* const conditional_code_suffix[] = { |
131 "o", "no", "c", "nc", "z", "nz", "na", "a", | 114 "o", "no", "c", "nc", "z", "nz", "na", "a", |
132 "s", "ns", "pe", "po", "l", "ge", "le", "g" | 115 "s", "ns", "pe", "po", "l", "ge", "le", "g"}; |
133 }; | |
134 | 116 |
135 | 117 |
136 enum InstructionType { | 118 enum InstructionType { |
137 NO_INSTR, | 119 NO_INSTR, |
138 ZERO_OPERANDS_INSTR, | 120 ZERO_OPERANDS_INSTR, |
139 TWO_OPERANDS_INSTR, | 121 TWO_OPERANDS_INSTR, |
140 JUMP_CONDITIONAL_SHORT_INSTR, | 122 JUMP_CONDITIONAL_SHORT_INSTR, |
141 REGISTER_INSTR, | 123 REGISTER_INSTR, |
142 PUSHPOP_INSTR, // Has implicit 64-bit operand size. | 124 PUSHPOP_INSTR, // Has implicit 64-bit operand size. |
143 MOVE_REG_INSTR, | 125 MOVE_REG_INSTR, |
(...skipping 16 matching lines...) Expand all Loading... |
160 const char* mnem; | 142 const char* mnem; |
161 InstructionType type; | 143 InstructionType type; |
162 OperandType op_order_; | 144 OperandType op_order_; |
163 bool byte_size_operation; // Fixed 8-bit operation. | 145 bool byte_size_operation; // Fixed 8-bit operation. |
164 }; | 146 }; |
165 | 147 |
166 | 148 |
167 class InstructionTable : public ValueObject { | 149 class InstructionTable : public ValueObject { |
168 public: | 150 public: |
169 InstructionTable(); | 151 InstructionTable(); |
170 const InstructionDesc& Get(uint8_t x) const { | 152 const InstructionDesc& Get(uint8_t x) const { return instructions_[x]; } |
171 return instructions_[x]; | |
172 } | |
173 | 153 |
174 private: | 154 private: |
175 InstructionDesc instructions_[256]; | 155 InstructionDesc instructions_[256]; |
176 void Clear(); | 156 void Clear(); |
177 void Init(); | 157 void Init(); |
178 void CopyTable(const ByteMnemonic bm[], InstructionType type); | 158 void CopyTable(const ByteMnemonic bm[], InstructionType type); |
179 void SetTableRange(InstructionType type, | 159 void SetTableRange(InstructionType type, |
180 uint8_t start, | 160 uint8_t start, |
181 uint8_t end, | 161 uint8_t end, |
182 bool byte_size, | 162 bool byte_size, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 id->type = type; | 222 id->type = type; |
243 id->byte_size_operation = byte_size; | 223 id->byte_size_operation = byte_size; |
244 } | 224 } |
245 } | 225 } |
246 | 226 |
247 | 227 |
248 void InstructionTable::AddJumpConditionalShort() { | 228 void InstructionTable::AddJumpConditionalShort() { |
249 for (uint8_t b = 0x70; b <= 0x7F; b++) { | 229 for (uint8_t b = 0x70; b <= 0x7F; b++) { |
250 InstructionDesc* id = &instructions_[b]; | 230 InstructionDesc* id = &instructions_[b]; |
251 ASSERT(NO_INSTR == id->type); // Information not already entered | 231 ASSERT(NO_INSTR == id->type); // Information not already entered |
252 id->mnem = NULL; // Computed depending on condition code. | 232 id->mnem = NULL; // Computed depending on condition code. |
253 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 233 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
254 } | 234 } |
255 } | 235 } |
256 | 236 |
257 | 237 |
258 static InstructionTable instruction_table; | 238 static InstructionTable instruction_table; |
259 | 239 |
260 | 240 |
261 static InstructionDesc cmov_instructions[16] = { | 241 static InstructionDesc cmov_instructions[16] = { |
262 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 242 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
263 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 243 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
264 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 244 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
265 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 245 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
266 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 246 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
267 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 247 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
268 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 248 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
269 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 249 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
270 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 250 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
271 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 251 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
272 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 252 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
273 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 253 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
274 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 254 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
275 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 255 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
276 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 256 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
277 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false} | 257 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}}; |
278 }; | |
279 | 258 |
280 | 259 |
281 //------------------------------------------------- | 260 //------------------------------------------------- |
282 // DisassemblerX64 implementation. | 261 // DisassemblerX64 implementation. |
283 | 262 |
284 | 263 |
285 static const int kMaxXmmRegisters = 16; | 264 static const int kMaxXmmRegisters = 16; |
286 static const char* xmm_regs[kMaxXmmRegisters] = { | 265 static const char* xmm_regs[kMaxXmmRegisters] = { |
287 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", | 266 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", |
288 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" | 267 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"}; |
289 }; | |
290 | 268 |
291 class DisassemblerX64 : public ValueObject { | 269 class DisassemblerX64 : public ValueObject { |
292 public: | 270 public: |
293 DisassemblerX64(char* buffer, intptr_t buffer_size) | 271 DisassemblerX64(char* buffer, intptr_t buffer_size) |
294 : buffer_(buffer), | 272 : buffer_(buffer), |
295 buffer_size_(buffer_size), | 273 buffer_size_(buffer_size), |
296 buffer_pos_(0), | 274 buffer_pos_(0), |
297 rex_(0), | 275 rex_(0), |
298 operand_size_(0), | 276 operand_size_(0), |
299 group_1_prefix_(0), | 277 group_1_prefix_(0), |
300 byte_size_operand_(false) { | 278 byte_size_operand_(false) { |
301 buffer_[buffer_pos_] = '\0'; | 279 buffer_[buffer_pos_] = '\0'; |
302 } | 280 } |
303 | 281 |
304 virtual ~DisassemblerX64() { | 282 virtual ~DisassemblerX64() {} |
305 } | |
306 | 283 |
307 int InstructionDecode(uword pc); | 284 int InstructionDecode(uword pc); |
308 | 285 |
309 private: | 286 private: |
310 enum OperandSize { | 287 enum OperandSize { |
311 BYTE_SIZE = 0, | 288 BYTE_SIZE = 0, |
312 WORD_SIZE = 1, | 289 WORD_SIZE = 1, |
313 DOUBLEWORD_SIZE = 2, | 290 DOUBLEWORD_SIZE = 2, |
314 QUADWORD_SIZE = 3 | 291 QUADWORD_SIZE = 3 |
315 }; | 292 }; |
(...skipping 16 matching lines...) Expand all Loading... |
332 | 309 |
333 bool rex_w() { return (rex_ & 0x08) != 0; } | 310 bool rex_w() { return (rex_ & 0x08) != 0; } |
334 | 311 |
335 OperandSize operand_size() { | 312 OperandSize operand_size() { |
336 if (byte_size_operand_) return BYTE_SIZE; | 313 if (byte_size_operand_) return BYTE_SIZE; |
337 if (rex_w()) return QUADWORD_SIZE; | 314 if (rex_w()) return QUADWORD_SIZE; |
338 if (operand_size_ != 0) return WORD_SIZE; | 315 if (operand_size_ != 0) return WORD_SIZE; |
339 return DOUBLEWORD_SIZE; | 316 return DOUBLEWORD_SIZE; |
340 } | 317 } |
341 | 318 |
342 char operand_size_code() { | 319 char operand_size_code() { return "bwlq"[operand_size()]; } |
343 return "bwlq"[operand_size()]; | |
344 } | |
345 | 320 |
346 // Disassembler helper functions. | 321 // Disassembler helper functions. |
347 void get_modrm(uint8_t data, | 322 void get_modrm(uint8_t data, int* mod, int* regop, int* rm) { |
348 int* mod, | |
349 int* regop, | |
350 int* rm) { | |
351 *mod = (data >> 6) & 3; | 323 *mod = (data >> 6) & 3; |
352 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0); | 324 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0); |
353 *rm = (data & 7) | (rex_b() ? 8 : 0); | 325 *rm = (data & 7) | (rex_b() ? 8 : 0); |
354 } | 326 } |
355 | 327 |
356 void get_sib(uint8_t data, | 328 void get_sib(uint8_t data, int* scale, int* index, int* base) { |
357 int* scale, | |
358 int* index, | |
359 int* base) { | |
360 *scale = (data >> 6) & 3; | 329 *scale = (data >> 6) & 3; |
361 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0); | 330 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0); |
362 *base = (data & 7) | (rex_b() ? 8 : 0); | 331 *base = (data & 7) | (rex_b() ? 8 : 0); |
363 } | 332 } |
364 | 333 |
365 const char* NameOfCPURegister(int reg) const { | 334 const char* NameOfCPURegister(int reg) const { |
366 return Assembler::RegisterName(static_cast<Register>(reg)); | 335 return Assembler::RegisterName(static_cast<Register>(reg)); |
367 } | 336 } |
368 | 337 |
369 const char* NameOfByteCPURegister(int reg) const { | 338 const char* NameOfByteCPURegister(int reg) const { |
370 return NameOfCPURegister(reg); | 339 return NameOfCPURegister(reg); |
371 } | 340 } |
372 | 341 |
373 const char* NameOfXMMRegister(int reg) const { | 342 const char* NameOfXMMRegister(int reg) const { |
374 ASSERT((0 <= reg) && (reg < kMaxXmmRegisters)); | 343 ASSERT((0 <= reg) && (reg < kMaxXmmRegisters)); |
375 return xmm_regs[reg]; | 344 return xmm_regs[reg]; |
376 } | 345 } |
377 | 346 |
378 void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); | 347 void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
379 void PrintAddress(uint8_t* addr); | 348 void PrintAddress(uint8_t* addr); |
380 | 349 |
381 int PrintOperands(const char* mnem, | 350 int PrintOperands(const char* mnem, OperandType op_order, uint8_t* data); |
382 OperandType op_order, | |
383 uint8_t* data); | |
384 | 351 |
385 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; | 352 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; |
386 | 353 |
387 int PrintRightOperandHelper(uint8_t* modrmp, | 354 int PrintRightOperandHelper(uint8_t* modrmp, |
388 RegisterNameMapping register_name); | 355 RegisterNameMapping register_name); |
389 int PrintRightOperand(uint8_t* modrmp); | 356 int PrintRightOperand(uint8_t* modrmp); |
390 int PrintRightByteOperand(uint8_t* modrmp); | 357 int PrintRightByteOperand(uint8_t* modrmp); |
391 int PrintRightXMMOperand(uint8_t* modrmp); | 358 int PrintRightXMMOperand(uint8_t* modrmp); |
392 void PrintDisp(int disp, const char* after); | 359 void PrintDisp(int disp, const char* after); |
393 int PrintImmediate(uint8_t* data, OperandSize size); | 360 int PrintImmediate(uint8_t* data, OperandSize size); |
394 void PrintImmediateValue(int64_t value); | 361 void PrintImmediateValue(int64_t value); |
395 int PrintImmediateOp(uint8_t* data); | 362 int PrintImmediateOp(uint8_t* data); |
396 const char* TwoByteMnemonic(uint8_t opcode); | 363 const char* TwoByteMnemonic(uint8_t opcode); |
397 int TwoByteOpcodeInstruction(uint8_t* data); | 364 int TwoByteOpcodeInstruction(uint8_t* data); |
398 | 365 |
399 int F6F7Instruction(uint8_t* data); | 366 int F6F7Instruction(uint8_t* data); |
400 int ShiftInstruction(uint8_t* data); | 367 int ShiftInstruction(uint8_t* data); |
401 int JumpShort(uint8_t* data); | 368 int JumpShort(uint8_t* data); |
402 int JumpConditional(uint8_t* data); | 369 int JumpConditional(uint8_t* data); |
403 int JumpConditionalShort(uint8_t* data); | 370 int JumpConditionalShort(uint8_t* data); |
404 int SetCC(uint8_t* data); | 371 int SetCC(uint8_t* data); |
405 int FPUInstruction(uint8_t* data); | 372 int FPUInstruction(uint8_t* data); |
406 int MemoryFPUInstruction(int escape_opcode, int regop, uint8_t* modrm_start); | 373 int MemoryFPUInstruction(int escape_opcode, int regop, uint8_t* modrm_start); |
407 int RegisterFPUInstruction(int escape_opcode, uint8_t modrm_byte); | 374 int RegisterFPUInstruction(int escape_opcode, uint8_t modrm_byte); |
408 | 375 |
409 bool DecodeInstructionType(uint8_t** data); | 376 bool DecodeInstructionType(uint8_t** data); |
410 | 377 |
411 void UnimplementedInstruction() { | 378 void UnimplementedInstruction() { Print("'Unimplemented Instruction'"); } |
412 Print("'Unimplemented Instruction'"); | |
413 } | |
414 | 379 |
415 char* buffer_; // Decode instructions into this buffer. | 380 char* buffer_; // Decode instructions into this buffer. |
416 intptr_t buffer_size_; // The size of the buffer_. | 381 intptr_t buffer_size_; // The size of the buffer_. |
417 intptr_t buffer_pos_; // Current character position in the buffer_. | 382 intptr_t buffer_pos_; // Current character position in the buffer_. |
418 | 383 |
419 // Prefixes parsed | 384 // Prefixes parsed |
420 uint8_t rex_; | 385 uint8_t rex_; |
421 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. | 386 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. |
422 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. | 387 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. |
423 uint8_t group_1_prefix_; | 388 uint8_t group_1_prefix_; |
424 // Byte size operand override. | 389 // Byte size operand override. |
425 bool byte_size_operand_; | 390 bool byte_size_operand_; |
426 | 391 |
427 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64); | 392 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64); |
(...skipping 16 matching lines...) Expand all Loading... |
444 (length >= available) ? (buffer_size_ - 1) : (buffer_pos_ + length); | 409 (length >= available) ? (buffer_size_ - 1) : (buffer_pos_ + length); |
445 ASSERT(buffer_pos_ < buffer_size_); | 410 ASSERT(buffer_pos_ < buffer_size_); |
446 } | 411 } |
447 | 412 |
448 | 413 |
449 int DisassemblerX64::PrintRightOperandHelper( | 414 int DisassemblerX64::PrintRightOperandHelper( |
450 uint8_t* modrmp, | 415 uint8_t* modrmp, |
451 RegisterNameMapping direct_register_name) { | 416 RegisterNameMapping direct_register_name) { |
452 int mod, regop, rm; | 417 int mod, regop, rm; |
453 get_modrm(*modrmp, &mod, ®op, &rm); | 418 get_modrm(*modrmp, &mod, ®op, &rm); |
454 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : | 419 RegisterNameMapping register_name = |
455 &DisassemblerX64::NameOfCPURegister; | 420 (mod == 3) ? direct_register_name : &DisassemblerX64::NameOfCPURegister; |
456 switch (mod) { | 421 switch (mod) { |
457 case 0: | 422 case 0: |
458 if ((rm & 7) == 5) { | 423 if ((rm & 7) == 5) { |
459 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1); | 424 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1); |
460 Print("[rip"); | 425 Print("[rip"); |
461 PrintDisp(disp, "]"); | 426 PrintDisp(disp, "]"); |
462 return 5; | 427 return 5; |
463 } else if ((rm & 7) == 4) { | 428 } else if ((rm & 7) == 4) { |
464 // Codes for SIB byte. | 429 // Codes for SIB byte. |
465 uint8_t sib = *(modrmp + 1); | 430 uint8_t sib = *(modrmp + 1); |
466 int scale, index, base; | 431 int scale, index, base; |
467 get_sib(sib, &scale, &index, &base); | 432 get_sib(sib, &scale, &index, &base); |
468 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { | 433 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { |
469 // index == rsp means no index. Only use sib byte with no index for | 434 // index == rsp means no index. Only use sib byte with no index for |
470 // rsp and r12 base. | 435 // rsp and r12 base. |
471 Print("[%s]", NameOfCPURegister(base)); | 436 Print("[%s]", NameOfCPURegister(base)); |
472 return 2; | 437 return 2; |
473 } else if (base == 5) { | 438 } else if (base == 5) { |
474 // base == rbp means no base register (when mod == 0). | 439 // base == rbp means no base register (when mod == 0). |
475 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); | 440 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); |
476 Print("[%s*%d", NameOfCPURegister(index), 1 << scale); | 441 Print("[%s*%d", NameOfCPURegister(index), 1 << scale); |
477 PrintDisp(disp, "]"); | 442 PrintDisp(disp, "]"); |
478 return 6; | 443 return 6; |
479 } else if (index != 4 && base != 5) { | 444 } else if (index != 4 && base != 5) { |
480 // [base+index*scale] | 445 // [base+index*scale] |
481 Print("[%s+%s*%d]", | 446 Print("[%s+%s*%d]", NameOfCPURegister(base), NameOfCPURegister(index), |
482 NameOfCPURegister(base), | |
483 NameOfCPURegister(index), | |
484 1 << scale); | 447 1 << scale); |
485 return 2; | 448 return 2; |
486 } else { | 449 } else { |
487 UnimplementedInstruction(); | 450 UnimplementedInstruction(); |
488 return 1; | 451 return 1; |
489 } | 452 } |
490 } else { | 453 } else { |
491 Print("[%s]", NameOfCPURegister(rm)); | 454 Print("[%s]", NameOfCPURegister(rm)); |
492 return 1; | 455 return 1; |
493 } | 456 } |
494 break; | 457 break; |
495 case 1: // fall through | 458 case 1: // fall through |
496 case 2: | 459 case 2: |
497 if ((rm & 7) == 4) { | 460 if ((rm & 7) == 4) { |
498 uint8_t sib = *(modrmp + 1); | 461 uint8_t sib = *(modrmp + 1); |
499 int scale, index, base; | 462 int scale, index, base; |
500 get_sib(sib, &scale, &index, &base); | 463 get_sib(sib, &scale, &index, &base); |
501 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2) | 464 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2) |
502 : *reinterpret_cast<char*>(modrmp + 2); | 465 : *reinterpret_cast<char*>(modrmp + 2); |
503 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { | 466 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { |
504 Print("[%s", NameOfCPURegister(base)); | 467 Print("[%s", NameOfCPURegister(base)); |
505 PrintDisp(disp, "]"); | 468 PrintDisp(disp, "]"); |
506 } else { | 469 } else { |
507 Print("[%s+%s*%d", | 470 Print("[%s+%s*%d", NameOfCPURegister(base), NameOfCPURegister(index), |
508 NameOfCPURegister(base), | |
509 NameOfCPURegister(index), | |
510 1 << scale); | 471 1 << scale); |
511 PrintDisp(disp, "]"); | 472 PrintDisp(disp, "]"); |
512 } | 473 } |
513 return mod == 2 ? 6 : 3; | 474 return mod == 2 ? 6 : 3; |
514 } else { | 475 } else { |
515 // No sib. | 476 // No sib. |
516 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1) | 477 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1) |
517 : *reinterpret_cast<char*>(modrmp + 1); | 478 : *reinterpret_cast<char*>(modrmp + 1); |
518 Print("[%s", NameOfCPURegister(rm)); | 479 Print("[%s", NameOfCPURegister(rm)); |
519 PrintDisp(disp, "]"); | 480 PrintDisp(disp, "]"); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
571 void DisassemblerX64::PrintDisp(int disp, const char* after) { | 532 void DisassemblerX64::PrintDisp(int disp, const char* after) { |
572 if (-disp > 0) { | 533 if (-disp > 0) { |
573 Print("-%#x", -disp); | 534 Print("-%#x", -disp); |
574 } else { | 535 } else { |
575 Print("+%#x", disp); | 536 Print("+%#x", disp); |
576 } | 537 } |
577 if (after != NULL) Print("%s", after); | 538 if (after != NULL) Print("%s", after); |
578 } | 539 } |
579 | 540 |
580 | 541 |
581 | |
582 | |
583 // Returns number of bytes used by machine instruction, including *data byte. | 542 // Returns number of bytes used by machine instruction, including *data byte. |
584 // Writes immediate instructions to 'tmp_buffer_'. | 543 // Writes immediate instructions to 'tmp_buffer_'. |
585 int DisassemblerX64::PrintImmediateOp(uint8_t* data) { | 544 int DisassemblerX64::PrintImmediateOp(uint8_t* data) { |
586 bool byte_size_immediate = (*data & 0x02) != 0; | 545 bool byte_size_immediate = (*data & 0x02) != 0; |
587 uint8_t modrm = *(data + 1); | 546 uint8_t modrm = *(data + 1); |
588 int mod, regop, rm; | 547 int mod, regop, rm; |
589 get_modrm(modrm, &mod, ®op, &rm); | 548 get_modrm(modrm, &mod, ®op, &rm); |
590 const char* mnem = "Imm???"; | 549 const char* mnem = "Imm???"; |
591 switch (regop) { | 550 switch (regop) { |
592 case 0: | 551 case 0: |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 break; | 604 break; |
646 case 6: | 605 case 6: |
647 mnem = "div"; | 606 mnem = "div"; |
648 break; | 607 break; |
649 case 7: | 608 case 7: |
650 mnem = "idiv"; | 609 mnem = "idiv"; |
651 break; | 610 break; |
652 default: | 611 default: |
653 UnimplementedInstruction(); | 612 UnimplementedInstruction(); |
654 } | 613 } |
655 Print("%s%c %s", | 614 Print("%s%c %s", mnem, operand_size_code(), NameOfCPURegister(rm)); |
656 mnem, | |
657 operand_size_code(), | |
658 NameOfCPURegister(rm)); | |
659 return 2; | 615 return 2; |
660 } else if (regop == 0) { | 616 } else if (regop == 0) { |
661 Print("test%c ", operand_size_code()); | 617 Print("test%c ", operand_size_code()); |
662 int count = PrintRightOperand(data + 1); // Use name of 64-bit register. | 618 int count = PrintRightOperand(data + 1); // Use name of 64-bit register. |
663 Print(","); | 619 Print(","); |
664 count += PrintImmediate(data + 1 + count, operand_size()); | 620 count += PrintImmediate(data + 1 + count, operand_size()); |
665 return 1 + count; | 621 return 1 + count; |
666 } else { | 622 } else { |
667 UnimplementedInstruction(); | 623 UnimplementedInstruction(); |
668 return 2; | 624 return 2; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 UnimplementedInstruction(); | 669 UnimplementedInstruction(); |
714 return num_bytes; | 670 return num_bytes; |
715 } | 671 } |
716 ASSERT(NULL != mnem); | 672 ASSERT(NULL != mnem); |
717 if (op == 0xD0) { | 673 if (op == 0xD0) { |
718 imm8 = 1; | 674 imm8 = 1; |
719 } else if (op == 0xC0) { | 675 } else if (op == 0xC0) { |
720 imm8 = *(data + 2); | 676 imm8 = *(data + 2); |
721 num_bytes = 3; | 677 num_bytes = 3; |
722 } | 678 } |
723 Print("%s%c %s,", | 679 Print("%s%c %s,", mnem, operand_size_code(), |
724 mnem, | 680 byte_size_operand_ ? NameOfByteCPURegister(rm) : NameOfCPURegister(rm)); |
725 operand_size_code(), | |
726 byte_size_operand_ ? NameOfByteCPURegister(rm) | |
727 : NameOfCPURegister(rm)); | |
728 if (op == 0xD2) { | 681 if (op == 0xD2) { |
729 Print("cl"); | 682 Print("cl"); |
730 } else { | 683 } else { |
731 Print("%d", imm8); | 684 Print("%d", imm8); |
732 } | 685 } |
733 return num_bytes; | 686 return num_bytes; |
734 } | 687 } |
735 | 688 |
736 | 689 |
737 int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) { | 690 int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) { |
738 return PrintRightOperandHelper(modrmp, | 691 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfCPURegister); |
739 &DisassemblerX64::NameOfCPURegister); | |
740 } | 692 } |
741 | 693 |
742 | 694 |
743 int DisassemblerX64::PrintRightByteOperand(uint8_t* modrmp) { | 695 int DisassemblerX64::PrintRightByteOperand(uint8_t* modrmp) { |
744 return PrintRightOperandHelper(modrmp, | 696 return PrintRightOperandHelper(modrmp, |
745 &DisassemblerX64::NameOfByteCPURegister); | 697 &DisassemblerX64::NameOfByteCPURegister); |
746 } | 698 } |
747 | 699 |
748 | 700 |
749 int DisassemblerX64::PrintRightXMMOperand(uint8_t* modrmp) { | 701 int DisassemblerX64::PrintRightXMMOperand(uint8_t* modrmp) { |
750 return PrintRightOperandHelper(modrmp, | 702 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfXMMRegister); |
751 &DisassemblerX64::NameOfXMMRegister); | |
752 } | 703 } |
753 | 704 |
754 | 705 |
755 // Returns number of bytes used including the current *data. | 706 // Returns number of bytes used including the current *data. |
756 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. | 707 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. |
757 int DisassemblerX64::PrintOperands(const char* mnem, | 708 int DisassemblerX64::PrintOperands(const char* mnem, |
758 OperandType op_order, | 709 OperandType op_order, |
759 uint8_t* data) { | 710 uint8_t* data) { |
760 uint8_t modrm = *data; | 711 uint8_t modrm = *data; |
761 int mod, regop, rm; | 712 int mod, regop, rm; |
762 get_modrm(modrm, &mod, ®op, &rm); | 713 get_modrm(modrm, &mod, ®op, &rm); |
763 int advance = 0; | 714 int advance = 0; |
764 const char* register_name = | 715 const char* register_name = byte_size_operand_ ? NameOfByteCPURegister(regop) |
765 byte_size_operand_ ? NameOfByteCPURegister(regop) | 716 : NameOfCPURegister(regop); |
766 : NameOfCPURegister(regop); | |
767 switch (op_order) { | 717 switch (op_order) { |
768 case REG_OPER_OP_ORDER: { | 718 case REG_OPER_OP_ORDER: { |
769 Print("%s%c %s,", mnem, operand_size_code(), register_name); | 719 Print("%s%c %s,", mnem, operand_size_code(), register_name); |
770 advance = byte_size_operand_ ? PrintRightByteOperand(data) | 720 advance = byte_size_operand_ ? PrintRightByteOperand(data) |
771 : PrintRightOperand(data); | 721 : PrintRightOperand(data); |
772 break; | 722 break; |
773 } | 723 } |
774 case OPER_REG_OP_ORDER: { | 724 case OPER_REG_OP_ORDER: { |
775 Print("%s%c ", mnem, operand_size_code()); | 725 Print("%s%c ", mnem, operand_size_code()); |
776 advance = byte_size_operand_ ? PrintRightByteOperand(data) | 726 advance = byte_size_operand_ ? PrintRightByteOperand(data) |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
835 Print("set%s%c ", mnem, operand_size_code()); | 785 Print("set%s%c ", mnem, operand_size_code()); |
836 PrintRightByteOperand(data + 2); | 786 PrintRightByteOperand(data + 2); |
837 return 3; // includes 0x0F | 787 return 3; // includes 0x0F |
838 } | 788 } |
839 | 789 |
840 | 790 |
841 // Returns number of bytes used, including *data. | 791 // Returns number of bytes used, including *data. |
842 int DisassemblerX64::FPUInstruction(uint8_t* data) { | 792 int DisassemblerX64::FPUInstruction(uint8_t* data) { |
843 uint8_t escape_opcode = *data; | 793 uint8_t escape_opcode = *data; |
844 ASSERT(0xD8 == (escape_opcode & 0xF8)); | 794 ASSERT(0xD8 == (escape_opcode & 0xF8)); |
845 uint8_t modrm_byte = *(data+1); | 795 uint8_t modrm_byte = *(data + 1); |
846 | 796 |
847 if (modrm_byte >= 0xC0) { | 797 if (modrm_byte >= 0xC0) { |
848 return RegisterFPUInstruction(escape_opcode, modrm_byte); | 798 return RegisterFPUInstruction(escape_opcode, modrm_byte); |
849 } else { | 799 } else { |
850 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); | 800 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1); |
851 } | 801 } |
852 } | 802 } |
853 | 803 |
854 | 804 |
855 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode, | 805 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode, |
856 int modrm_byte, | 806 int modrm_byte, |
857 uint8_t* modrm_start) { | 807 uint8_t* modrm_start) { |
858 const char* mnem = "?"; | 808 const char* mnem = "?"; |
859 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. | 809 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. |
860 switch (escape_opcode) { | 810 switch (escape_opcode) { |
861 case 0xD9: switch (regop) { | 811 case 0xD9: |
862 case 0: mnem = "fld_s"; break; | 812 switch (regop) { |
863 case 3: mnem = "fstp_s"; break; | 813 case 0: |
864 case 7: mnem = "fstcw"; break; | 814 mnem = "fld_s"; |
865 default: UnimplementedInstruction(); | 815 break; |
| 816 case 3: |
| 817 mnem = "fstp_s"; |
| 818 break; |
| 819 case 7: |
| 820 mnem = "fstcw"; |
| 821 break; |
| 822 default: |
| 823 UnimplementedInstruction(); |
866 } | 824 } |
867 break; | 825 break; |
868 | 826 |
869 case 0xDB: switch (regop) { | 827 case 0xDB: |
870 case 0: mnem = "fild_s"; break; | 828 switch (regop) { |
871 case 1: mnem = "fisttp_s"; break; | 829 case 0: |
872 case 2: mnem = "fist_s"; break; | 830 mnem = "fild_s"; |
873 case 3: mnem = "fistp_s"; break; | 831 break; |
874 default: UnimplementedInstruction(); | 832 case 1: |
| 833 mnem = "fisttp_s"; |
| 834 break; |
| 835 case 2: |
| 836 mnem = "fist_s"; |
| 837 break; |
| 838 case 3: |
| 839 mnem = "fistp_s"; |
| 840 break; |
| 841 default: |
| 842 UnimplementedInstruction(); |
875 } | 843 } |
876 break; | 844 break; |
877 | 845 |
878 case 0xDD: switch (regop) { | 846 case 0xDD: |
879 case 0: mnem = "fld_d"; break; | 847 switch (regop) { |
880 case 3: mnem = "fstp_d"; break; | 848 case 0: |
881 default: UnimplementedInstruction(); | 849 mnem = "fld_d"; |
| 850 break; |
| 851 case 3: |
| 852 mnem = "fstp_d"; |
| 853 break; |
| 854 default: |
| 855 UnimplementedInstruction(); |
882 } | 856 } |
883 break; | 857 break; |
884 | 858 |
885 case 0xDF: switch (regop) { | 859 case 0xDF: |
886 case 5: mnem = "fild_d"; break; | 860 switch (regop) { |
887 case 7: mnem = "fistp_d"; break; | 861 case 5: |
888 default: UnimplementedInstruction(); | 862 mnem = "fild_d"; |
| 863 break; |
| 864 case 7: |
| 865 mnem = "fistp_d"; |
| 866 break; |
| 867 default: |
| 868 UnimplementedInstruction(); |
889 } | 869 } |
890 break; | 870 break; |
891 | 871 |
892 default: UnimplementedInstruction(); | 872 default: |
| 873 UnimplementedInstruction(); |
893 } | 874 } |
894 Print("%s ", mnem); | 875 Print("%s ", mnem); |
895 int count = PrintRightOperand(modrm_start); | 876 int count = PrintRightOperand(modrm_start); |
896 return count + 1; | 877 return count + 1; |
897 } | 878 } |
898 | 879 |
899 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode, | 880 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode, |
900 uint8_t modrm_byte) { | 881 uint8_t modrm_byte) { |
901 bool has_register = false; // Is the FPU register encoded in modrm_byte? | 882 bool has_register = false; // Is the FPU register encoded in modrm_byte? |
902 const char* mnem = "?"; | 883 const char* mnem = "?"; |
903 | 884 |
904 switch (escape_opcode) { | 885 switch (escape_opcode) { |
905 case 0xD8: | 886 case 0xD8: |
906 UnimplementedInstruction(); | 887 UnimplementedInstruction(); |
907 break; | 888 break; |
908 | 889 |
909 case 0xD9: | 890 case 0xD9: |
910 switch (modrm_byte & 0xF8) { | 891 switch (modrm_byte & 0xF8) { |
911 case 0xC0: | 892 case 0xC0: |
912 mnem = "fld"; | 893 mnem = "fld"; |
913 has_register = true; | 894 has_register = true; |
914 break; | 895 break; |
915 case 0xC8: | 896 case 0xC8: |
916 mnem = "fxch"; | 897 mnem = "fxch"; |
917 has_register = true; | 898 has_register = true; |
918 break; | 899 break; |
919 default: | 900 default: |
920 switch (modrm_byte) { | 901 switch (modrm_byte) { |
921 case 0xE0: mnem = "fchs"; break; | 902 case 0xE0: |
922 case 0xE1: mnem = "fabs"; break; | 903 mnem = "fchs"; |
923 case 0xE3: mnem = "fninit"; break; | 904 break; |
924 case 0xE4: mnem = "ftst"; break; | 905 case 0xE1: |
925 case 0xE8: mnem = "fld1"; break; | 906 mnem = "fabs"; |
926 case 0xEB: mnem = "fldpi"; break; | 907 break; |
927 case 0xED: mnem = "fldln2"; break; | 908 case 0xE3: |
928 case 0xEE: mnem = "fldz"; break; | 909 mnem = "fninit"; |
929 case 0xF0: mnem = "f2xm1"; break; | 910 break; |
930 case 0xF1: mnem = "fyl2x"; break; | 911 case 0xE4: |
931 case 0xF2: mnem = "fptan"; break; | 912 mnem = "ftst"; |
932 case 0xF5: mnem = "fprem1"; break; | 913 break; |
933 case 0xF7: mnem = "fincstp"; break; | 914 case 0xE8: |
934 case 0xF8: mnem = "fprem"; break; | 915 mnem = "fld1"; |
935 case 0xFD: mnem = "fscale"; break; | 916 break; |
936 case 0xFE: mnem = "fsin"; break; | 917 case 0xEB: |
937 case 0xFF: mnem = "fcos"; break; | 918 mnem = "fldpi"; |
938 default: UnimplementedInstruction(); | 919 break; |
| 920 case 0xED: |
| 921 mnem = "fldln2"; |
| 922 break; |
| 923 case 0xEE: |
| 924 mnem = "fldz"; |
| 925 break; |
| 926 case 0xF0: |
| 927 mnem = "f2xm1"; |
| 928 break; |
| 929 case 0xF1: |
| 930 mnem = "fyl2x"; |
| 931 break; |
| 932 case 0xF2: |
| 933 mnem = "fptan"; |
| 934 break; |
| 935 case 0xF5: |
| 936 mnem = "fprem1"; |
| 937 break; |
| 938 case 0xF7: |
| 939 mnem = "fincstp"; |
| 940 break; |
| 941 case 0xF8: |
| 942 mnem = "fprem"; |
| 943 break; |
| 944 case 0xFD: |
| 945 mnem = "fscale"; |
| 946 break; |
| 947 case 0xFE: |
| 948 mnem = "fsin"; |
| 949 break; |
| 950 case 0xFF: |
| 951 mnem = "fcos"; |
| 952 break; |
| 953 default: |
| 954 UnimplementedInstruction(); |
939 } | 955 } |
940 } | 956 } |
941 break; | 957 break; |
942 | 958 |
943 case 0xDA: | 959 case 0xDA: |
944 if (modrm_byte == 0xE9) { | 960 if (modrm_byte == 0xE9) { |
945 mnem = "fucompp"; | 961 mnem = "fucompp"; |
946 } else { | 962 } else { |
947 UnimplementedInstruction(); | 963 UnimplementedInstruction(); |
948 } | 964 } |
949 break; | 965 break; |
950 | 966 |
951 case 0xDB: | 967 case 0xDB: |
952 if ((modrm_byte & 0xF8) == 0xE8) { | 968 if ((modrm_byte & 0xF8) == 0xE8) { |
953 mnem = "fucomi"; | 969 mnem = "fucomi"; |
954 has_register = true; | 970 has_register = true; |
955 } else if (modrm_byte == 0xE2) { | 971 } else if (modrm_byte == 0xE2) { |
956 mnem = "fclex"; | 972 mnem = "fclex"; |
957 } else { | 973 } else { |
958 UnimplementedInstruction(); | 974 UnimplementedInstruction(); |
959 } | 975 } |
960 break; | 976 break; |
961 | 977 |
962 case 0xDC: | 978 case 0xDC: |
963 has_register = true; | 979 has_register = true; |
964 switch (modrm_byte & 0xF8) { | 980 switch (modrm_byte & 0xF8) { |
965 case 0xC0: mnem = "fadd"; break; | 981 case 0xC0: |
966 case 0xE8: mnem = "fsub"; break; | 982 mnem = "fadd"; |
967 case 0xC8: mnem = "fmul"; break; | 983 break; |
968 case 0xF8: mnem = "fdiv"; break; | 984 case 0xE8: |
969 default: UnimplementedInstruction(); | 985 mnem = "fsub"; |
| 986 break; |
| 987 case 0xC8: |
| 988 mnem = "fmul"; |
| 989 break; |
| 990 case 0xF8: |
| 991 mnem = "fdiv"; |
| 992 break; |
| 993 default: |
| 994 UnimplementedInstruction(); |
970 } | 995 } |
971 break; | 996 break; |
972 | 997 |
973 case 0xDD: | 998 case 0xDD: |
974 has_register = true; | 999 has_register = true; |
975 switch (modrm_byte & 0xF8) { | 1000 switch (modrm_byte & 0xF8) { |
976 case 0xC0: mnem = "ffree"; break; | 1001 case 0xC0: |
977 case 0xD8: mnem = "fstp"; break; | 1002 mnem = "ffree"; |
978 default: UnimplementedInstruction(); | 1003 break; |
| 1004 case 0xD8: |
| 1005 mnem = "fstp"; |
| 1006 break; |
| 1007 default: |
| 1008 UnimplementedInstruction(); |
979 } | 1009 } |
980 break; | 1010 break; |
981 | 1011 |
982 case 0xDE: | 1012 case 0xDE: |
983 if (modrm_byte == 0xD9) { | 1013 if (modrm_byte == 0xD9) { |
984 mnem = "fcompp"; | 1014 mnem = "fcompp"; |
985 } else { | 1015 } else { |
986 has_register = true; | 1016 has_register = true; |
987 switch (modrm_byte & 0xF8) { | 1017 switch (modrm_byte & 0xF8) { |
988 case 0xC0: mnem = "faddp"; break; | 1018 case 0xC0: |
989 case 0xE8: mnem = "fsubp"; break; | 1019 mnem = "faddp"; |
990 case 0xC8: mnem = "fmulp"; break; | 1020 break; |
991 case 0xF8: mnem = "fdivp"; break; | 1021 case 0xE8: |
992 default: UnimplementedInstruction(); | 1022 mnem = "fsubp"; |
| 1023 break; |
| 1024 case 0xC8: |
| 1025 mnem = "fmulp"; |
| 1026 break; |
| 1027 case 0xF8: |
| 1028 mnem = "fdivp"; |
| 1029 break; |
| 1030 default: |
| 1031 UnimplementedInstruction(); |
993 } | 1032 } |
994 } | 1033 } |
995 break; | 1034 break; |
996 | 1035 |
997 case 0xDF: | 1036 case 0xDF: |
998 if (modrm_byte == 0xE0) { | 1037 if (modrm_byte == 0xE0) { |
999 mnem = "fnstsw_ax"; | 1038 mnem = "fnstsw_ax"; |
1000 } else if ((modrm_byte & 0xF8) == 0xE8) { | 1039 } else if ((modrm_byte & 0xF8) == 0xE8) { |
1001 mnem = "fucomip"; | 1040 mnem = "fucomip"; |
1002 has_register = true; | 1041 has_register = true; |
1003 } | 1042 } |
1004 break; | 1043 break; |
1005 | 1044 |
1006 default: UnimplementedInstruction(); | 1045 default: |
| 1046 UnimplementedInstruction(); |
1007 } | 1047 } |
1008 | 1048 |
1009 if (has_register) { | 1049 if (has_register) { |
1010 Print("%s st%d", mnem, modrm_byte & 0x7); | 1050 Print("%s st%d", mnem, modrm_byte & 0x7); |
1011 } else { | 1051 } else { |
1012 Print("%s", mnem); | 1052 Print("%s", mnem); |
1013 } | 1053 } |
1014 return 2; | 1054 return 2; |
1015 } | 1055 } |
1016 | 1056 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1061 case TWO_OPERANDS_INSTR: | 1101 case TWO_OPERANDS_INSTR: |
1062 (*data)++; | 1102 (*data)++; |
1063 (*data) += PrintOperands(idesc.mnem, idesc.op_order_, *data); | 1103 (*data) += PrintOperands(idesc.mnem, idesc.op_order_, *data); |
1064 break; | 1104 break; |
1065 | 1105 |
1066 case JUMP_CONDITIONAL_SHORT_INSTR: | 1106 case JUMP_CONDITIONAL_SHORT_INSTR: |
1067 (*data) += JumpConditionalShort(*data); | 1107 (*data) += JumpConditionalShort(*data); |
1068 break; | 1108 break; |
1069 | 1109 |
1070 case REGISTER_INSTR: | 1110 case REGISTER_INSTR: |
1071 Print("%s%c %s", | 1111 Print("%s%c %s", idesc.mnem, operand_size_code(), |
1072 idesc.mnem, | |
1073 operand_size_code(), | |
1074 NameOfCPURegister(base_reg(current & 0x07))); | 1112 NameOfCPURegister(base_reg(current & 0x07))); |
1075 (*data)++; | 1113 (*data)++; |
1076 break; | 1114 break; |
1077 case PUSHPOP_INSTR: | 1115 case PUSHPOP_INSTR: |
1078 Print("%s %s", | 1116 Print("%s %s", idesc.mnem, NameOfCPURegister(base_reg(current & 0x07))); |
1079 idesc.mnem, | |
1080 NameOfCPURegister(base_reg(current & 0x07))); | |
1081 (*data)++; | 1117 (*data)++; |
1082 break; | 1118 break; |
1083 case MOVE_REG_INSTR: { | 1119 case MOVE_REG_INSTR: { |
1084 uint8_t* addr = NULL; | 1120 uint8_t* addr = NULL; |
1085 switch (operand_size()) { | 1121 switch (operand_size()) { |
1086 case WORD_SIZE: | 1122 case WORD_SIZE: |
1087 addr = reinterpret_cast<uint8_t*>( | 1123 addr = reinterpret_cast<uint8_t*>( |
1088 *reinterpret_cast<int16_t*>(*data + 1)); | 1124 *reinterpret_cast<int16_t*>(*data + 1)); |
1089 (*data) += 3; | 1125 (*data) += 3; |
1090 break; | 1126 break; |
1091 case DOUBLEWORD_SIZE: | 1127 case DOUBLEWORD_SIZE: |
1092 addr = reinterpret_cast<uint8_t*>( | 1128 addr = reinterpret_cast<uint8_t*>( |
1093 *reinterpret_cast<int32_t*>(*data + 1)); | 1129 *reinterpret_cast<int32_t*>(*data + 1)); |
1094 (*data) += 5; | 1130 (*data) += 5; |
1095 break; | 1131 break; |
1096 case QUADWORD_SIZE: | 1132 case QUADWORD_SIZE: |
1097 addr = reinterpret_cast<uint8_t*>( | 1133 addr = reinterpret_cast<uint8_t*>( |
1098 *reinterpret_cast<int64_t*>(*data + 1)); | 1134 *reinterpret_cast<int64_t*>(*data + 1)); |
1099 (*data) += 9; | 1135 (*data) += 9; |
1100 break; | 1136 break; |
1101 default: | 1137 default: |
1102 UNREACHABLE(); | 1138 UNREACHABLE(); |
1103 } | 1139 } |
1104 Print("mov%c %s,", | 1140 Print("mov%c %s,", operand_size_code(), |
1105 operand_size_code(), | |
1106 NameOfCPURegister(base_reg(current & 0x07))); | 1141 NameOfCPURegister(base_reg(current & 0x07))); |
1107 PrintAddress(addr); | 1142 PrintAddress(addr); |
1108 break; | 1143 break; |
1109 } | 1144 } |
1110 | 1145 |
1111 case CALL_JUMP_INSTR: { | 1146 case CALL_JUMP_INSTR: { |
1112 uint8_t* addr = *data + *reinterpret_cast<int32_t*>(*data + 1) + 5; | 1147 uint8_t* addr = *data + *reinterpret_cast<int32_t*>(*data + 1) + 5; |
1113 Print("%s ", idesc.mnem); | 1148 Print("%s ", idesc.mnem); |
1114 PrintAddress(addr); | 1149 PrintAddress(addr); |
1115 (*data) += 5; | 1150 (*data) += 5; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1157 uint8_t third_byte = *current; | 1192 uint8_t third_byte = *current; |
1158 current = data + 3; | 1193 current = data + 3; |
1159 if (third_byte == 0x17) { | 1194 if (third_byte == 0x17) { |
1160 get_modrm(*current, &mod, ®op, &rm); | 1195 get_modrm(*current, &mod, ®op, &rm); |
1161 Print("extractps "); // reg/m32, xmm, imm8 | 1196 Print("extractps "); // reg/m32, xmm, imm8 |
1162 current += PrintRightOperand(current); | 1197 current += PrintRightOperand(current); |
1163 Print(", %s, %d", NameOfCPURegister(regop), (*current) & 3); | 1198 Print(", %s, %d", NameOfCPURegister(regop), (*current) & 3); |
1164 current += 1; | 1199 current += 1; |
1165 } else if (third_byte == 0x0b) { | 1200 } else if (third_byte == 0x0b) { |
1166 get_modrm(*current, &mod, ®op, &rm); | 1201 get_modrm(*current, &mod, ®op, &rm); |
1167 // roundsd xmm, xmm/m64, imm8 | 1202 // roundsd xmm, xmm/m64, imm8 |
1168 Print("roundsd %s, ", NameOfCPURegister(regop)); | 1203 Print("roundsd %s, ", NameOfCPURegister(regop)); |
1169 current += PrintRightOperand(current); | 1204 current += PrintRightOperand(current); |
1170 Print(", %d", (*current) & 3); | 1205 Print(", %d", (*current) & 3); |
1171 current += 1; | 1206 current += 1; |
1172 } else { | 1207 } else { |
1173 UnimplementedInstruction(); | 1208 UnimplementedInstruction(); |
1174 } | 1209 } |
1175 } else { | 1210 } else { |
1176 get_modrm(*current, &mod, ®op, &rm); | 1211 get_modrm(*current, &mod, ®op, &rm); |
1177 if (opcode == 0x1f) { | 1212 if (opcode == 0x1f) { |
1178 current++; | 1213 current++; |
1179 if (rm == 4) { // SIB byte present. | 1214 if (rm == 4) { // SIB byte present. |
1180 current++; | 1215 current++; |
1181 } | 1216 } |
1182 if (mod == 1) { // Byte displacement. | 1217 if (mod == 1) { // Byte displacement. |
1183 current += 1; | 1218 current += 1; |
1184 } else if (mod == 2) { // 32-bit displacement. | 1219 } else if (mod == 2) { // 32-bit displacement. |
1185 current += 4; | 1220 current += 4; |
1186 } // else no immediate displacement. | 1221 } // else no immediate displacement. |
1187 Print("nop"); | 1222 Print("nop"); |
1188 } else if (opcode == 0x28) { | 1223 } else if (opcode == 0x28) { |
1189 Print("movapd %s, ", NameOfXMMRegister(regop)); | 1224 Print("movapd %s, ", NameOfXMMRegister(regop)); |
1190 current += PrintRightXMMOperand(current); | 1225 current += PrintRightXMMOperand(current); |
1191 } else if (opcode == 0x29) { | 1226 } else if (opcode == 0x29) { |
1192 Print("movapd "); | 1227 Print("movapd "); |
1193 current += PrintRightXMMOperand(current); | 1228 current += PrintRightXMMOperand(current); |
1194 Print(", %s", NameOfXMMRegister(regop)); | 1229 Print(", %s", NameOfXMMRegister(regop)); |
1195 } else if (opcode == 0x6E) { | 1230 } else if (opcode == 0x6E) { |
1196 Print("mov%c %s,", | 1231 Print("mov%c %s,", rex_w() ? 'q' : 'd', NameOfXMMRegister(regop)); |
1197 rex_w() ? 'q' : 'd', | |
1198 NameOfXMMRegister(regop)); | |
1199 current += PrintRightOperand(current); | 1232 current += PrintRightOperand(current); |
1200 } else if (opcode == 0x6F) { | 1233 } else if (opcode == 0x6F) { |
1201 Print("movdqa %s,", | 1234 Print("movdqa %s,", NameOfXMMRegister(regop)); |
1202 NameOfXMMRegister(regop)); | |
1203 current += PrintRightXMMOperand(current); | 1235 current += PrintRightXMMOperand(current); |
1204 } else if (opcode == 0x7E) { | 1236 } else if (opcode == 0x7E) { |
1205 Print("mov%c ", | 1237 Print("mov%c ", rex_w() ? 'q' : 'd'); |
1206 rex_w() ? 'q' : 'd'); | |
1207 current += PrintRightOperand(current); | 1238 current += PrintRightOperand(current); |
1208 Print(", %s", NameOfXMMRegister(regop)); | 1239 Print(", %s", NameOfXMMRegister(regop)); |
1209 } else if (opcode == 0x7F) { | 1240 } else if (opcode == 0x7F) { |
1210 Print("movdqa "); | 1241 Print("movdqa "); |
1211 current += PrintRightXMMOperand(current); | 1242 current += PrintRightXMMOperand(current); |
1212 Print(", %s", NameOfXMMRegister(regop)); | 1243 Print(", %s", NameOfXMMRegister(regop)); |
1213 } else if (opcode == 0xD6) { | 1244 } else if (opcode == 0xD6) { |
1214 Print("movq "); | 1245 Print("movq "); |
1215 current += PrintRightXMMOperand(current); | 1246 current += PrintRightXMMOperand(current); |
1216 Print(", %s", NameOfXMMRegister(regop)); | 1247 Print(", %s", NameOfXMMRegister(regop)); |
1217 } else if (opcode == 0x50) { | 1248 } else if (opcode == 0x50) { |
1218 Print("movmskpd %s,", NameOfCPURegister(regop)); | 1249 Print("movmskpd %s,", NameOfCPURegister(regop)); |
1219 current += PrintRightXMMOperand(current); | 1250 current += PrintRightXMMOperand(current); |
1220 } else { | 1251 } else { |
1221 const char* mnemonic = "?"; | 1252 const char* mnemonic = "?"; |
1222 if (opcode == 0x14) { | 1253 if (opcode == 0x14) { |
1223 mnemonic = "unpcklpd"; | 1254 mnemonic = "unpcklpd"; |
1224 } else if (opcode == 0x15) { | 1255 } else if (opcode == 0x15) { |
1225 mnemonic = "unpckhpd"; | 1256 mnemonic = "unpckhpd"; |
1226 } else if (opcode == 0x54) { | 1257 } else if (opcode == 0x54) { |
1227 mnemonic = "andpd"; | 1258 mnemonic = "andpd"; |
1228 } else if (opcode == 0x56) { | 1259 } else if (opcode == 0x56) { |
1229 mnemonic = "orpd"; | 1260 mnemonic = "orpd"; |
1230 } else if (opcode == 0x57) { | 1261 } else if (opcode == 0x57) { |
1231 mnemonic = "xorpd"; | 1262 mnemonic = "xorpd"; |
1232 } else if (opcode == 0x2E) { | 1263 } else if (opcode == 0x2E) { |
1233 mnemonic = "ucomisd"; | 1264 mnemonic = "ucomisd"; |
1234 } else if (opcode == 0x2F) { | 1265 } else if (opcode == 0x2F) { |
1235 mnemonic = "comisd"; | 1266 mnemonic = "comisd"; |
1236 } else if (opcode == 0xFE) { | 1267 } else if (opcode == 0xFE) { |
1237 mnemonic = "paddd"; | 1268 mnemonic = "paddd"; |
1238 } else if (opcode == 0xFA) { | 1269 } else if (opcode == 0xFA) { |
1239 mnemonic = "psubd"; | 1270 mnemonic = "psubd"; |
1240 } else if (opcode == 0x58) { | 1271 } else if (opcode == 0x58) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1279 // CVTSI2SD: integer to XMM double conversion. | 1310 // CVTSI2SD: integer to XMM double conversion. |
1280 int mod, regop, rm; | 1311 int mod, regop, rm; |
1281 get_modrm(*current, &mod, ®op, &rm); | 1312 get_modrm(*current, &mod, ®op, &rm); |
1282 Print("%sd %s,", mnemonic, NameOfXMMRegister(regop)); | 1313 Print("%sd %s,", mnemonic, NameOfXMMRegister(regop)); |
1283 current += PrintRightOperand(current); | 1314 current += PrintRightOperand(current); |
1284 } else if (opcode == 0x2C) { | 1315 } else if (opcode == 0x2C) { |
1285 // CVTTSD2SI: | 1316 // CVTTSD2SI: |
1286 // Convert with truncation scalar double-precision FP to integer. | 1317 // Convert with truncation scalar double-precision FP to integer. |
1287 int mod, regop, rm; | 1318 int mod, regop, rm; |
1288 get_modrm(*current, &mod, ®op, &rm); | 1319 get_modrm(*current, &mod, ®op, &rm); |
1289 Print("cvttsd2si%c %s,", | 1320 Print("cvttsd2si%c %s,", operand_size_code(), NameOfCPURegister(regop)); |
1290 operand_size_code(), NameOfCPURegister(regop)); | |
1291 current += PrintRightXMMOperand(current); | 1321 current += PrintRightXMMOperand(current); |
1292 } else if (opcode == 0x2D) { | 1322 } else if (opcode == 0x2D) { |
1293 // CVTSD2SI: Convert scalar double-precision FP to integer. | 1323 // CVTSD2SI: Convert scalar double-precision FP to integer. |
1294 int mod, regop, rm; | 1324 int mod, regop, rm; |
1295 get_modrm(*current, &mod, ®op, &rm); | 1325 get_modrm(*current, &mod, ®op, &rm); |
1296 Print("cvtsd2si%c %s,", | 1326 Print("cvtsd2si%c %s,", operand_size_code(), NameOfCPURegister(regop)); |
1297 operand_size_code(), NameOfCPURegister(regop)); | |
1298 current += PrintRightXMMOperand(current); | 1327 current += PrintRightXMMOperand(current); |
1299 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) { | 1328 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) { |
1300 // XMM arithmetic. Mnemonic was retrieved at the start of this function. | 1329 // XMM arithmetic. Mnemonic was retrieved at the start of this function. |
1301 int mod, regop, rm; | 1330 int mod, regop, rm; |
1302 get_modrm(*current, &mod, ®op, &rm); | 1331 get_modrm(*current, &mod, ®op, &rm); |
1303 Print("%s %s,", mnemonic, NameOfXMMRegister(regop)); | 1332 Print("%s %s,", mnemonic, NameOfXMMRegister(regop)); |
1304 current += PrintRightXMMOperand(current); | 1333 current += PrintRightXMMOperand(current); |
1305 } else { | 1334 } else { |
1306 UnimplementedInstruction(); | 1335 UnimplementedInstruction(); |
1307 } | 1336 } |
(...skipping 15 matching lines...) Expand all Loading... |
1323 // CVTSI2SS: integer to XMM single conversion. | 1352 // CVTSI2SS: integer to XMM single conversion. |
1324 int mod, regop, rm; | 1353 int mod, regop, rm; |
1325 get_modrm(*current, &mod, ®op, &rm); | 1354 get_modrm(*current, &mod, ®op, &rm); |
1326 Print("%ss %s,", mnemonic, NameOfXMMRegister(regop)); | 1355 Print("%ss %s,", mnemonic, NameOfXMMRegister(regop)); |
1327 current += PrintRightOperand(current); | 1356 current += PrintRightOperand(current); |
1328 } else if (opcode == 0x2C) { | 1357 } else if (opcode == 0x2C) { |
1329 // CVTTSS2SI: | 1358 // CVTTSS2SI: |
1330 // Convert with truncation scalar single-precision FP to dword integer. | 1359 // Convert with truncation scalar single-precision FP to dword integer. |
1331 int mod, regop, rm; | 1360 int mod, regop, rm; |
1332 get_modrm(*current, &mod, ®op, &rm); | 1361 get_modrm(*current, &mod, ®op, &rm); |
1333 Print("cvttss2si%c %s,", | 1362 Print("cvttss2si%c %s,", operand_size_code(), NameOfCPURegister(regop)); |
1334 operand_size_code(), NameOfCPURegister(regop)); | |
1335 current += PrintRightXMMOperand(current); | 1363 current += PrintRightXMMOperand(current); |
1336 } else if (opcode == 0x5A) { | 1364 } else if (opcode == 0x5A) { |
1337 // CVTSS2SD: | 1365 // CVTSS2SD: |
1338 // Convert scalar single-precision FP to scalar double-precision FP. | 1366 // Convert scalar single-precision FP to scalar double-precision FP. |
1339 int mod, regop, rm; | 1367 int mod, regop, rm; |
1340 get_modrm(*current, &mod, ®op, &rm); | 1368 get_modrm(*current, &mod, ®op, &rm); |
1341 Print("cvtss2sd %s,", NameOfXMMRegister(regop)); | 1369 Print("cvtss2sd %s,", NameOfXMMRegister(regop)); |
1342 current += PrintRightXMMOperand(current); | 1370 current += PrintRightXMMOperand(current); |
1343 } else if (opcode == 0x7E) { | 1371 } else if (opcode == 0x7E) { |
1344 int mod, regop, rm; | 1372 int mod, regop, rm; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1411 current += PrintOperands(idesc.mnem, idesc.op_order_, current); | 1439 current += PrintOperands(idesc.mnem, idesc.op_order_, current); |
1412 | 1440 |
1413 } else if (opcode == 0x12 || opcode == 0x14 || opcode == 0x15 || | 1441 } else if (opcode == 0x12 || opcode == 0x14 || opcode == 0x15 || |
1414 opcode == 0x16 || opcode == 0x51 || opcode == 0x52 || | 1442 opcode == 0x16 || opcode == 0x51 || opcode == 0x52 || |
1415 opcode == 0x53 || opcode == 0x54 || opcode == 0x56 || | 1443 opcode == 0x53 || opcode == 0x54 || opcode == 0x56 || |
1416 opcode == 0x57 || opcode == 0x58 || opcode == 0x59 || | 1444 opcode == 0x57 || opcode == 0x58 || opcode == 0x59 || |
1417 opcode == 0x5A || opcode == 0x5C || opcode == 0x5D || | 1445 opcode == 0x5A || opcode == 0x5C || opcode == 0x5D || |
1418 opcode == 0x5E || opcode == 0x5F) { | 1446 opcode == 0x5E || opcode == 0x5F) { |
1419 const char* mnemonic = NULL; | 1447 const char* mnemonic = NULL; |
1420 switch (opcode) { | 1448 switch (opcode) { |
1421 case 0x12: mnemonic = "movhlps"; break; | 1449 case 0x12: |
1422 case 0x14: mnemonic = "unpcklps"; break; | 1450 mnemonic = "movhlps"; |
1423 case 0x15: mnemonic = "unpckhps"; break; | 1451 break; |
1424 case 0x16: mnemonic = "movlhps"; break; | 1452 case 0x14: |
1425 case 0x51: mnemonic = "sqrtps"; break; | 1453 mnemonic = "unpcklps"; |
1426 case 0x52: mnemonic = "rsqrtps"; break; | 1454 break; |
1427 case 0x53: mnemonic = "rcpps"; break; | 1455 case 0x15: |
1428 case 0x54: mnemonic = "andps"; break; | 1456 mnemonic = "unpckhps"; |
1429 case 0x56: mnemonic = "orps"; break; | 1457 break; |
1430 case 0x57: mnemonic = "xorps"; break; | 1458 case 0x16: |
1431 case 0x58: mnemonic = "addps"; break; | 1459 mnemonic = "movlhps"; |
1432 case 0x59: mnemonic = "mulps"; break; | 1460 break; |
1433 case 0x5A: mnemonic = "cvtsd2ss"; break; | 1461 case 0x51: |
1434 case 0x5C: mnemonic = "subps"; break; | 1462 mnemonic = "sqrtps"; |
1435 case 0x5D: mnemonic = "minps"; break; | 1463 break; |
1436 case 0x5E: mnemonic = "divps"; break; | 1464 case 0x52: |
1437 case 0x5F: mnemonic = "maxps"; break; | 1465 mnemonic = "rsqrtps"; |
1438 default: UNREACHABLE(); | 1466 break; |
| 1467 case 0x53: |
| 1468 mnemonic = "rcpps"; |
| 1469 break; |
| 1470 case 0x54: |
| 1471 mnemonic = "andps"; |
| 1472 break; |
| 1473 case 0x56: |
| 1474 mnemonic = "orps"; |
| 1475 break; |
| 1476 case 0x57: |
| 1477 mnemonic = "xorps"; |
| 1478 break; |
| 1479 case 0x58: |
| 1480 mnemonic = "addps"; |
| 1481 break; |
| 1482 case 0x59: |
| 1483 mnemonic = "mulps"; |
| 1484 break; |
| 1485 case 0x5A: |
| 1486 mnemonic = "cvtsd2ss"; |
| 1487 break; |
| 1488 case 0x5C: |
| 1489 mnemonic = "subps"; |
| 1490 break; |
| 1491 case 0x5D: |
| 1492 mnemonic = "minps"; |
| 1493 break; |
| 1494 case 0x5E: |
| 1495 mnemonic = "divps"; |
| 1496 break; |
| 1497 case 0x5F: |
| 1498 mnemonic = "maxps"; |
| 1499 break; |
| 1500 default: |
| 1501 UNREACHABLE(); |
1439 } | 1502 } |
1440 int mod, regop, rm; | 1503 int mod, regop, rm; |
1441 get_modrm(*current, &mod, ®op, &rm); | 1504 get_modrm(*current, &mod, ®op, &rm); |
1442 Print("%s %s, ", mnemonic, NameOfXMMRegister(regop)); | 1505 Print("%s %s, ", mnemonic, NameOfXMMRegister(regop)); |
1443 current += PrintRightXMMOperand(current); | 1506 current += PrintRightXMMOperand(current); |
1444 } else if (opcode == 0xC2 || opcode == 0xC6) { | 1507 } else if (opcode == 0xC2 || opcode == 0xC6) { |
1445 int mod, regop, rm; | 1508 int mod, regop, rm; |
1446 get_modrm(*current, &mod, ®op, &rm); | 1509 get_modrm(*current, &mod, ®op, &rm); |
1447 if (opcode == 0xC2) { | 1510 if (opcode == 0xC2) { |
1448 Print("cmpps %s, ", NameOfXMMRegister(regop)); | 1511 Print("cmpps %s, ", NameOfXMMRegister(regop)); |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1555 | 1618 |
1556 if (!processed) { | 1619 if (!processed) { |
1557 switch (*data) { | 1620 switch (*data) { |
1558 case 0xC2: | 1621 case 0xC2: |
1559 Print("ret "); | 1622 Print("ret "); |
1560 PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1)); | 1623 PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1)); |
1561 data += 3; | 1624 data += 3; |
1562 break; | 1625 break; |
1563 | 1626 |
1564 case 0xC8: | 1627 case 0xC8: |
1565 Print("enter %d, %d", | 1628 Print("enter %d, %d", *reinterpret_cast<uint16_t*>(data + 1), data[3]); |
1566 *reinterpret_cast<uint16_t*>(data + 1), | |
1567 data[3]); | |
1568 data += 4; | 1629 data += 4; |
1569 break; | 1630 break; |
1570 | 1631 |
1571 case 0x69: // fall through | 1632 case 0x69: // fall through |
1572 case 0x6B: { | 1633 case 0x6B: { |
1573 int mod, regop, rm; | 1634 int mod, regop, rm; |
1574 get_modrm(*(data + 1), &mod, ®op, &rm); | 1635 get_modrm(*(data + 1), &mod, ®op, &rm); |
1575 int32_t imm = *data == 0x6B ? *(data + 2) | 1636 int32_t imm = |
1576 : *reinterpret_cast<int32_t*>(data + 2); | 1637 *data == 0x6B ? *(data + 2) : *reinterpret_cast<int32_t*>(data + 2); |
1577 Print("imul%c %s,%s,", | 1638 Print("imul%c %s,%s,", operand_size_code(), NameOfCPURegister(regop), |
1578 operand_size_code(), | |
1579 NameOfCPURegister(regop), | |
1580 NameOfCPURegister(rm)); | 1639 NameOfCPURegister(rm)); |
1581 PrintImmediateValue(imm); | 1640 PrintImmediateValue(imm); |
1582 data += 2 + (*data == 0x6B ? 1 : 4); | 1641 data += 2 + (*data == 0x6B ? 1 : 4); |
1583 break; | 1642 break; |
1584 } | 1643 } |
1585 | 1644 |
1586 case 0x81: // fall through | 1645 case 0x81: // fall through |
1587 case 0x83: // 0x81 with sign extension bit set | 1646 case 0x83: // 0x81 with sign extension bit set |
1588 data += PrintImmediateOp(data); | 1647 data += PrintImmediateOp(data); |
1589 break; | 1648 break; |
1590 | 1649 |
1591 case 0x0F: | 1650 case 0x0F: |
1592 data += TwoByteOpcodeInstruction(data); | 1651 data += TwoByteOpcodeInstruction(data); |
1593 break; | 1652 break; |
1594 | 1653 |
1595 case 0x8F: { | 1654 case 0x8F: { |
1596 data++; | 1655 data++; |
1597 int mod, regop, rm; | 1656 int mod, regop, rm; |
1598 get_modrm(*data, &mod, ®op, &rm); | 1657 get_modrm(*data, &mod, ®op, &rm); |
1599 if (regop == 0) { | 1658 if (regop == 0) { |
1600 Print("pop "); | 1659 Print("pop "); |
1601 data += PrintRightOperand(data); | 1660 data += PrintRightOperand(data); |
1602 } | 1661 } |
1603 } | 1662 } break; |
1604 break; | |
1605 | 1663 |
1606 case 0xFF: { | 1664 case 0xFF: { |
1607 data++; | 1665 data++; |
1608 int mod, regop, rm; | 1666 int mod, regop, rm; |
1609 get_modrm(*data, &mod, ®op, &rm); | 1667 get_modrm(*data, &mod, ®op, &rm); |
1610 const char* mnem = NULL; | 1668 const char* mnem = NULL; |
1611 switch (regop) { | 1669 switch (regop) { |
1612 case 0: | 1670 case 0: |
1613 mnem = "inc"; | 1671 mnem = "inc"; |
1614 break; | 1672 break; |
(...skipping 11 matching lines...) Expand all Loading... |
1626 break; | 1684 break; |
1627 default: | 1685 default: |
1628 mnem = "???"; | 1686 mnem = "???"; |
1629 } | 1687 } |
1630 if (regop <= 1) { | 1688 if (regop <= 1) { |
1631 Print("%s%c ", mnem, operand_size_code()); | 1689 Print("%s%c ", mnem, operand_size_code()); |
1632 } else { | 1690 } else { |
1633 Print("%s ", mnem); | 1691 Print("%s ", mnem); |
1634 } | 1692 } |
1635 data += PrintRightOperand(data); | 1693 data += PrintRightOperand(data); |
1636 } | 1694 } break; |
1637 break; | |
1638 | 1695 |
1639 case 0xC7: // imm32, fall through | 1696 case 0xC7: // imm32, fall through |
1640 case 0xC6: // imm8 | 1697 case 0xC6: // imm8 |
1641 { | 1698 { |
1642 bool is_byte = *data == 0xC6; | 1699 bool is_byte = *data == 0xC6; |
1643 data++; | 1700 data++; |
1644 if (is_byte) { | 1701 if (is_byte) { |
1645 Print("movb "); | 1702 Print("movb "); |
1646 data += PrintRightByteOperand(data); | 1703 data += PrintRightByteOperand(data); |
1647 int32_t imm = *data; | 1704 int32_t imm = *data; |
1648 Print(","); | 1705 Print(","); |
1649 PrintImmediateValue(imm); | 1706 PrintImmediateValue(imm); |
1650 data++; | 1707 data++; |
1651 } else { | 1708 } else { |
1652 Print("mov%c ", operand_size_code()); | 1709 Print("mov%c ", operand_size_code()); |
1653 data += PrintRightOperand(data); | 1710 data += PrintRightOperand(data); |
1654 int32_t imm = *reinterpret_cast<int32_t*>(data); | 1711 int32_t imm = *reinterpret_cast<int32_t*>(data); |
1655 Print(","); | 1712 Print(","); |
1656 PrintImmediateValue(imm); | 1713 PrintImmediateValue(imm); |
1657 data += 4; | 1714 data += 4; |
1658 } | 1715 } |
1659 } | 1716 } break; |
1660 break; | |
1661 | 1717 |
1662 case 0x80: { | 1718 case 0x80: { |
1663 data++; | 1719 data++; |
1664 Print("cmpb "); | 1720 Print("cmpb "); |
1665 data += PrintRightByteOperand(data); | 1721 data += PrintRightByteOperand(data); |
1666 int32_t imm = *data; | 1722 int32_t imm = *data; |
1667 Print(","); | 1723 Print(","); |
1668 PrintImmediateValue(imm); | 1724 PrintImmediateValue(imm); |
1669 data++; | 1725 data++; |
1670 } | 1726 } break; |
1671 break; | |
1672 | 1727 |
1673 case 0x88: // 8bit, fall through | 1728 case 0x88: // 8bit, fall through |
1674 case 0x89: // 32bit | 1729 case 0x89: // 32bit |
1675 { | 1730 { |
1676 bool is_byte = *data == 0x88; | 1731 bool is_byte = *data == 0x88; |
1677 int mod, regop, rm; | 1732 int mod, regop, rm; |
1678 data++; | 1733 data++; |
1679 get_modrm(*data, &mod, ®op, &rm); | 1734 get_modrm(*data, &mod, ®op, &rm); |
1680 if (is_byte) { | 1735 if (is_byte) { |
1681 Print("movb "); | 1736 Print("movb "); |
1682 data += PrintRightByteOperand(data); | 1737 data += PrintRightByteOperand(data); |
1683 Print(",%s", NameOfByteCPURegister(regop)); | 1738 Print(",%s", NameOfByteCPURegister(regop)); |
1684 } else { | 1739 } else { |
1685 Print("mov%c ", operand_size_code()); | 1740 Print("mov%c ", operand_size_code()); |
1686 data += PrintRightOperand(data); | 1741 data += PrintRightOperand(data); |
1687 Print(",%s", NameOfCPURegister(regop)); | 1742 Print(",%s", NameOfCPURegister(regop)); |
1688 } | 1743 } |
1689 } | 1744 } break; |
1690 break; | |
1691 | 1745 |
1692 case 0x90: | 1746 case 0x90: |
1693 case 0x91: | 1747 case 0x91: |
1694 case 0x92: | 1748 case 0x92: |
1695 case 0x93: | 1749 case 0x93: |
1696 case 0x94: | 1750 case 0x94: |
1697 case 0x95: | 1751 case 0x95: |
1698 case 0x96: | 1752 case 0x96: |
1699 case 0x97: { | 1753 case 0x97: { |
1700 int reg = (*data & 0x7) | (rex_b() ? 8 : 0); | 1754 int reg = (*data & 0x7) | (rex_b() ? 8 : 0); |
1701 if (reg == 0) { | 1755 if (reg == 0) { |
1702 Print("nop"); // Common name for xchg rax,rax. | 1756 Print("nop"); // Common name for xchg rax,rax. |
1703 } else { | 1757 } else { |
1704 Print("xchg%c rax, %s", operand_size_code(), NameOfCPURegister(reg)); | 1758 Print("xchg%c rax, %s", operand_size_code(), NameOfCPURegister(reg)); |
1705 } | 1759 } |
1706 data++; | 1760 data++; |
1707 } | 1761 } break; |
1708 break; | |
1709 case 0xB0: | 1762 case 0xB0: |
1710 case 0xB1: | 1763 case 0xB1: |
1711 case 0xB2: | 1764 case 0xB2: |
1712 case 0xB3: | 1765 case 0xB3: |
1713 case 0xB4: | 1766 case 0xB4: |
1714 case 0xB5: | 1767 case 0xB5: |
1715 case 0xB6: | 1768 case 0xB6: |
1716 case 0xB7: | 1769 case 0xB7: |
1717 case 0xB8: | 1770 case 0xB8: |
1718 case 0xB9: | 1771 case 0xB9: |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1757 case 0x6A: | 1810 case 0x6A: |
1758 Print("push "); | 1811 Print("push "); |
1759 PrintImmediateValue(*reinterpret_cast<int8_t*>(data + 1)); | 1812 PrintImmediateValue(*reinterpret_cast<int8_t*>(data + 1)); |
1760 data += 2; | 1813 data += 2; |
1761 break; | 1814 break; |
1762 | 1815 |
1763 case 0xA1: // Fall through. | 1816 case 0xA1: // Fall through. |
1764 case 0xA3: | 1817 case 0xA3: |
1765 switch (operand_size()) { | 1818 switch (operand_size()) { |
1766 case DOUBLEWORD_SIZE: { | 1819 case DOUBLEWORD_SIZE: { |
1767 PrintAddress( | 1820 PrintAddress(reinterpret_cast<uint8_t*>( |
1768 reinterpret_cast<uint8_t*>( | 1821 *reinterpret_cast<int32_t*>(data + 1))); |
1769 *reinterpret_cast<int32_t*>(data + 1))); | |
1770 if (*data == 0xA1) { // Opcode 0xA1 | 1822 if (*data == 0xA1) { // Opcode 0xA1 |
1771 Print("movzxlq rax,("); | 1823 Print("movzxlq rax,("); |
1772 PrintAddress( | 1824 PrintAddress(reinterpret_cast<uint8_t*>( |
1773 reinterpret_cast<uint8_t*>( | 1825 *reinterpret_cast<int32_t*>(data + 1))); |
1774 *reinterpret_cast<int32_t*>(data + 1))); | |
1775 Print(")"); | 1826 Print(")"); |
1776 } else { // Opcode 0xA3 | 1827 } else { // Opcode 0xA3 |
1777 Print("movzxlq ("); | 1828 Print("movzxlq ("); |
1778 PrintAddress( | 1829 PrintAddress(reinterpret_cast<uint8_t*>( |
1779 reinterpret_cast<uint8_t*>( | 1830 *reinterpret_cast<int32_t*>(data + 1))); |
1780 *reinterpret_cast<int32_t*>(data + 1))); | |
1781 Print("),rax"); | 1831 Print("),rax"); |
1782 } | 1832 } |
1783 data += 5; | 1833 data += 5; |
1784 break; | 1834 break; |
1785 } | 1835 } |
1786 case QUADWORD_SIZE: { | 1836 case QUADWORD_SIZE: { |
1787 // New x64 instruction mov rax,(imm_64). | 1837 // New x64 instruction mov rax,(imm_64). |
1788 if (*data == 0xA1) { // Opcode 0xA1 | 1838 if (*data == 0xA1) { // Opcode 0xA1 |
1789 Print("movq rax,("); | 1839 Print("movq rax,("); |
1790 PrintAddress(*reinterpret_cast<uint8_t**>(data + 1)); | 1840 PrintAddress(*reinterpret_cast<uint8_t**>(data + 1)); |
1791 Print(")"); | 1841 Print(")"); |
1792 } else { // Opcode 0xA3 | 1842 } else { // Opcode 0xA3 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1871 | 1921 |
1872 ASSERT(buffer_[buffer_pos_] == '\0'); | 1922 ASSERT(buffer_[buffer_pos_] == '\0'); |
1873 | 1923 |
1874 int instr_len = data - reinterpret_cast<uint8_t*>(pc); | 1924 int instr_len = data - reinterpret_cast<uint8_t*>(pc); |
1875 ASSERT(instr_len > 0); // Ensure progress. | 1925 ASSERT(instr_len > 0); // Ensure progress. |
1876 | 1926 |
1877 return instr_len; | 1927 return instr_len; |
1878 } | 1928 } |
1879 | 1929 |
1880 | 1930 |
1881 void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, | 1931 void Disassembler::DecodeInstruction(char* hex_buffer, |
1882 char* human_buffer, intptr_t human_size, | 1932 intptr_t hex_size, |
1883 int* out_instr_len, const Code& code, | 1933 char* human_buffer, |
1884 Object** object, uword pc) { | 1934 intptr_t human_size, |
| 1935 int* out_instr_len, |
| 1936 const Code& code, |
| 1937 Object** object, |
| 1938 uword pc) { |
1885 ASSERT(hex_size > 0); | 1939 ASSERT(hex_size > 0); |
1886 ASSERT(human_size > 0); | 1940 ASSERT(human_size > 0); |
1887 DisassemblerX64 decoder(human_buffer, human_size); | 1941 DisassemblerX64 decoder(human_buffer, human_size); |
1888 int instruction_length = decoder.InstructionDecode(pc); | 1942 int instruction_length = decoder.InstructionDecode(pc); |
1889 uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc); | 1943 uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc); |
1890 int hex_index = 0; | 1944 int hex_index = 0; |
1891 int remaining_size = hex_size - hex_index; | 1945 int remaining_size = hex_size - hex_index; |
1892 for (int i = 0; (i < instruction_length) && (remaining_size > 2); ++i) { | 1946 for (int i = 0; (i < instruction_length) && (remaining_size > 2); ++i) { |
1893 OS::SNPrint(&hex_buffer[hex_index], remaining_size, "%02x", pc_ptr[i]); | 1947 OS::SNPrint(&hex_buffer[hex_index], remaining_size, "%02x", pc_ptr[i]); |
1894 hex_index += 2; | 1948 hex_index += 2; |
(...skipping 11 matching lines...) Expand all Loading... |
1906 *object = NULL; | 1960 *object = NULL; |
1907 } | 1961 } |
1908 } | 1962 } |
1909 } | 1963 } |
1910 | 1964 |
1911 #endif // !PRODUCT | 1965 #endif // !PRODUCT |
1912 | 1966 |
1913 } // namespace dart | 1967 } // namespace dart |
1914 | 1968 |
1915 #endif // defined TARGET_ARCH_X64 | 1969 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |