OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 16 matching lines...) Expand all Loading... | |
27 | 27 |
28 #include <assert.h> | 28 #include <assert.h> |
29 #include <stdio.h> | 29 #include <stdio.h> |
30 #include <stdarg.h> | 30 #include <stdarg.h> |
31 | 31 |
32 #include "v8.h" | 32 #include "v8.h" |
33 #include "disasm.h" | 33 #include "disasm.h" |
34 | 34 |
35 namespace disasm { | 35 namespace disasm { |
36 | 36 |
37 enum OperandOrder { | 37 enum OperandType { |
38 UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER | 38 UNSET_OP_ORDER = 0, |
39 // Operand size decides between 16, 32 and 64 bit operands. | |
40 REG_OPER_OP_ORDER = 1, // Register destination, operand source. | |
41 OPER_REG_OP_ORDER = 2, // Operand destination, register source. | |
42 // Fixed 8-bit operands. | |
43 BYTE_SIZE_OPERAND_FLAG = 4, | |
44 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG, | |
45 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG | |
39 }; | 46 }; |
40 | 47 |
41 //------------------------------------------------------------------ | 48 //------------------------------------------------------------------ |
42 // Tables | 49 // Tables |
43 //------------------------------------------------------------------ | 50 //------------------------------------------------------------------ |
44 struct ByteMnemonic { | 51 struct ByteMnemonic { |
45 int b; // -1 terminates, otherwise must be in range (0..255) | 52 int b; // -1 terminates, otherwise must be in range (0..255) |
46 OperandOrder op_order_; | 53 OperandType op_order_; |
47 const char* mnem; | 54 const char* mnem; |
48 }; | 55 }; |
49 | 56 |
50 | 57 |
51 static ByteMnemonic two_operands_instr[] = { | 58 static ByteMnemonic two_operands_instr[] = { |
52 { 0x03, REG_OPER_OP_ORDER, "add" }, | 59 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" }, |
53 { 0x21, OPER_REG_OP_ORDER, "and" }, | 60 { 0x01, OPER_REG_OP_ORDER, "add" }, |
54 { 0x23, REG_OPER_OP_ORDER, "and" }, | 61 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" }, |
55 { 0x3B, REG_OPER_OP_ORDER, "cmp" }, | 62 { 0x03, REG_OPER_OP_ORDER, "add" }, |
56 { 0x8D, REG_OPER_OP_ORDER, "lea" }, | 63 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" }, |
57 { 0x09, OPER_REG_OP_ORDER, "or" }, | 64 { 0x09, OPER_REG_OP_ORDER, "or" }, |
58 { 0x0B, REG_OPER_OP_ORDER, "or" }, | 65 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" }, |
59 { 0x1B, REG_OPER_OP_ORDER, "sbb" }, | 66 { 0x0B, REG_OPER_OP_ORDER, "or" }, |
60 { 0x29, OPER_REG_OP_ORDER, "sub" }, | 67 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" }, |
61 { 0x2B, REG_OPER_OP_ORDER, "sub" }, | 68 { 0x11, OPER_REG_OP_ORDER, "adc" }, |
62 { 0x85, REG_OPER_OP_ORDER, "test" }, | 69 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" }, |
63 { 0x31, OPER_REG_OP_ORDER, "xor" }, | 70 { 0x13, REG_OPER_OP_ORDER, "adc" }, |
64 { 0x33, REG_OPER_OP_ORDER, "xor" }, | 71 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" }, |
65 { 0x87, REG_OPER_OP_ORDER, "xchg" }, | 72 { 0x19, OPER_REG_OP_ORDER, "sbb" }, |
66 { 0x8A, REG_OPER_OP_ORDER, "movb" }, | 73 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" }, |
67 { 0x8B, REG_OPER_OP_ORDER, "mov" }, | 74 { 0x1B, REG_OPER_OP_ORDER, "sbb" }, |
75 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" }, | |
76 { 0x21, OPER_REG_OP_ORDER, "and" }, | |
77 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" }, | |
78 { 0x23, REG_OPER_OP_ORDER, "and" }, | |
79 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" }, | |
80 { 0x29, OPER_REG_OP_ORDER, "sub" }, | |
81 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" }, | |
82 { 0x2B, REG_OPER_OP_ORDER, "sub" }, | |
83 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" }, | |
84 { 0x31, OPER_REG_OP_ORDER, "xor" }, | |
85 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" }, | |
86 { 0x33, REG_OPER_OP_ORDER, "xor" }, | |
87 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" }, | |
88 { 0x39, OPER_REG_OP_ORDER, "cmp" }, | |
89 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" }, | |
90 { 0x3B, REG_OPER_OP_ORDER, "cmp" }, | |
91 { 0x8D, REG_OPER_OP_ORDER, "lea" }, | |
92 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" }, | |
93 { 0x85, REG_OPER_OP_ORDER, "test" }, | |
94 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" }, | |
95 { 0x87, REG_OPER_OP_ORDER, "xchg" }, | |
96 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" }, | |
97 { 0x89, OPER_REG_OP_ORDER, "mov" }, | |
98 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" }, | |
99 { 0x8B, REG_OPER_OP_ORDER, "mov" }, | |
68 { -1, UNSET_OP_ORDER, "" } | 100 { -1, UNSET_OP_ORDER, "" } |
69 }; | 101 }; |
70 | 102 |
71 | 103 |
72 static ByteMnemonic zero_operands_instr[] = { | 104 static ByteMnemonic zero_operands_instr[] = { |
73 { 0xC3, UNSET_OP_ORDER, "ret" }, | 105 { 0xC3, UNSET_OP_ORDER, "ret" }, |
74 { 0xC9, UNSET_OP_ORDER, "leave" }, | 106 { 0xC9, UNSET_OP_ORDER, "leave" }, |
75 { 0x90, UNSET_OP_ORDER, "nop" }, | 107 { 0x90, UNSET_OP_ORDER, "nop" }, |
76 { 0xF4, UNSET_OP_ORDER, "hlt" }, | 108 { 0xF4, UNSET_OP_ORDER, "hlt" }, |
77 { 0xCC, UNSET_OP_ORDER, "int3" }, | 109 { 0xCC, UNSET_OP_ORDER, "int3" }, |
(...skipping 12 matching lines...) Expand all Loading... | |
90 { 0xE8, UNSET_OP_ORDER, "call" }, | 122 { 0xE8, UNSET_OP_ORDER, "call" }, |
91 { 0xE9, UNSET_OP_ORDER, "jmp" }, | 123 { 0xE9, UNSET_OP_ORDER, "jmp" }, |
92 { -1, UNSET_OP_ORDER, "" } | 124 { -1, UNSET_OP_ORDER, "" } |
93 }; | 125 }; |
94 | 126 |
95 | 127 |
96 static ByteMnemonic short_immediate_instr[] = { | 128 static ByteMnemonic short_immediate_instr[] = { |
97 { 0x05, UNSET_OP_ORDER, "add" }, | 129 { 0x05, UNSET_OP_ORDER, "add" }, |
98 { 0x0D, UNSET_OP_ORDER, "or" }, | 130 { 0x0D, UNSET_OP_ORDER, "or" }, |
99 { 0x15, UNSET_OP_ORDER, "adc" }, | 131 { 0x15, UNSET_OP_ORDER, "adc" }, |
132 { 0x1D, UNSET_OP_ORDER, "sbb" }, | |
100 { 0x25, UNSET_OP_ORDER, "and" }, | 133 { 0x25, UNSET_OP_ORDER, "and" }, |
101 { 0x2D, UNSET_OP_ORDER, "sub" }, | 134 { 0x2D, UNSET_OP_ORDER, "sub" }, |
102 { 0x35, UNSET_OP_ORDER, "xor" }, | 135 { 0x35, UNSET_OP_ORDER, "xor" }, |
103 { 0x3D, UNSET_OP_ORDER, "cmp" }, | 136 { 0x3D, UNSET_OP_ORDER, "cmp" }, |
104 { -1, UNSET_OP_ORDER, "" } | 137 { -1, UNSET_OP_ORDER, "" } |
105 }; | 138 }; |
106 | 139 |
107 | 140 |
108 static const char* conditional_code_suffix[] = { | 141 static const char* conditional_code_suffix[] = { |
109 "o", "no", "c", "nc", "z", "nz", "a", "na", | 142 "o", "no", "c", "nc", "z", "nz", "a", "na", |
(...skipping 10 matching lines...) Expand all Loading... | |
120 PUSHPOP_INSTR, // Has implicit 64-bit operand size. | 153 PUSHPOP_INSTR, // Has implicit 64-bit operand size. |
121 MOVE_REG_INSTR, | 154 MOVE_REG_INSTR, |
122 CALL_JUMP_INSTR, | 155 CALL_JUMP_INSTR, |
123 SHORT_IMMEDIATE_INSTR | 156 SHORT_IMMEDIATE_INSTR |
124 }; | 157 }; |
125 | 158 |
126 | 159 |
127 struct InstructionDesc { | 160 struct InstructionDesc { |
128 const char* mnem; | 161 const char* mnem; |
129 InstructionType type; | 162 InstructionType type; |
130 OperandOrder op_order_; | 163 OperandType op_order_; |
164 bool byte_size_operation; // Fixed 8-bit operation. | |
131 }; | 165 }; |
132 | 166 |
133 | 167 |
134 class InstructionTable { | 168 class InstructionTable { |
135 public: | 169 public: |
136 InstructionTable(); | 170 InstructionTable(); |
137 const InstructionDesc& Get(byte x) const { | 171 const InstructionDesc& Get(byte x) const { |
138 return instructions_[x]; | 172 return instructions_[x]; |
139 } | 173 } |
140 | 174 |
141 private: | 175 private: |
142 InstructionDesc instructions_[256]; | 176 InstructionDesc instructions_[256]; |
143 void Clear(); | 177 void Clear(); |
144 void Init(); | 178 void Init(); |
145 void CopyTable(ByteMnemonic bm[], InstructionType type); | 179 void CopyTable(ByteMnemonic bm[], InstructionType type); |
146 void SetTableRange(InstructionType type, byte start, byte end, | 180 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size, |
147 const char* mnem); | 181 const char* mnem); |
148 void AddJumpConditionalShort(); | 182 void AddJumpConditionalShort(); |
149 }; | 183 }; |
150 | 184 |
151 | 185 |
152 InstructionTable::InstructionTable() { | 186 InstructionTable::InstructionTable() { |
153 Clear(); | 187 Clear(); |
154 Init(); | 188 Init(); |
155 } | 189 } |
156 | 190 |
157 | 191 |
158 void InstructionTable::Clear() { | 192 void InstructionTable::Clear() { |
159 for (int i = 0; i < 256; i++) { | 193 for (int i = 0; i < 256; i++) { |
160 instructions_[i].mnem = ""; | 194 instructions_[i].mnem = "(bad)"; |
161 instructions_[i].type = NO_INSTR; | 195 instructions_[i].type = NO_INSTR; |
162 instructions_[i].op_order_ = UNSET_OP_ORDER; | 196 instructions_[i].op_order_ = UNSET_OP_ORDER; |
197 instructions_[i].byte_size_operation = false; | |
163 } | 198 } |
164 } | 199 } |
165 | 200 |
166 | 201 |
167 void InstructionTable::Init() { | 202 void InstructionTable::Init() { |
168 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); | 203 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); |
169 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); | 204 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); |
170 CopyTable(call_jump_instr, CALL_JUMP_INSTR); | 205 CopyTable(call_jump_instr, CALL_JUMP_INSTR); |
171 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); | 206 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); |
172 AddJumpConditionalShort(); | 207 AddJumpConditionalShort(); |
173 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, "push"); | 208 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push"); |
174 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, "pop"); | 209 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop"); |
175 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); | 210 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov"); |
176 } | 211 } |
177 | 212 |
178 | 213 |
179 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { | 214 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { |
180 for (int i = 0; bm[i].b >= 0; i++) { | 215 for (int i = 0; bm[i].b >= 0; i++) { |
181 InstructionDesc* id = &instructions_[bm[i].b]; | 216 InstructionDesc* id = &instructions_[bm[i].b]; |
182 id->mnem = bm[i].mnem; | 217 id->mnem = bm[i].mnem; |
183 id->op_order_ = bm[i].op_order_; | 218 OperandType op_order = bm[i].op_order_; |
184 assert(id->type == NO_INSTR); // Information already entered | 219 id->op_order_ = |
220 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG); | |
221 assert(id->type == NO_INSTR); // Information not already entered | |
185 id->type = type; | 222 id->type = type; |
223 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0); | |
186 } | 224 } |
187 } | 225 } |
188 | 226 |
189 | 227 |
190 void InstructionTable::SetTableRange(InstructionType type, byte start, | 228 void InstructionTable::SetTableRange(InstructionType type, |
191 byte end, const char* mnem) { | 229 byte start, |
230 byte end, | |
231 bool byte_size, | |
232 const char* mnem) { | |
192 for (byte b = start; b <= end; b++) { | 233 for (byte b = start; b <= end; b++) { |
193 InstructionDesc* id = &instructions_[b]; | 234 InstructionDesc* id = &instructions_[b]; |
194 assert(id->type == NO_INSTR); // Information already entered | 235 assert(id->type == NO_INSTR); // Information already entered |
195 id->mnem = mnem; | 236 id->mnem = mnem; |
196 id->type = type; | 237 id->type = type; |
238 id->byte_size_operation = byte_size; | |
197 } | 239 } |
198 } | 240 } |
199 | 241 |
200 | 242 |
201 void InstructionTable::AddJumpConditionalShort() { | 243 void InstructionTable::AddJumpConditionalShort() { |
202 for (byte b = 0x70; b <= 0x7F; b++) { | 244 for (byte b = 0x70; b <= 0x7F; b++) { |
203 InstructionDesc* id = &instructions_[b]; | 245 InstructionDesc* id = &instructions_[b]; |
204 assert(id->type == NO_INSTR); // Information already entered | 246 assert(id->type == NO_INSTR); // Information already entered |
205 id->mnem = NULL; // Computed depending on condition code. | 247 id->mnem = NULL; // Computed depending on condition code. |
206 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 248 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
(...skipping 14 matching lines...) Expand all Loading... | |
221 class DisassemblerX64 { | 263 class DisassemblerX64 { |
222 public: | 264 public: |
223 DisassemblerX64(const NameConverter& converter, | 265 DisassemblerX64(const NameConverter& converter, |
224 UnimplementedOpcodeAction unimplemented_action = | 266 UnimplementedOpcodeAction unimplemented_action = |
225 ABORT_ON_UNIMPLEMENTED_OPCODE) | 267 ABORT_ON_UNIMPLEMENTED_OPCODE) |
226 : converter_(converter), | 268 : converter_(converter), |
227 tmp_buffer_pos_(0), | 269 tmp_buffer_pos_(0), |
228 abort_on_unimplemented_( | 270 abort_on_unimplemented_( |
229 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), | 271 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), |
230 rex_(0), | 272 rex_(0), |
231 operand_size_(0) { | 273 operand_size_(0), |
274 byte_size_operand_(false) { | |
232 tmp_buffer_[0] = '\0'; | 275 tmp_buffer_[0] = '\0'; |
233 } | 276 } |
234 | 277 |
235 virtual ~DisassemblerX64() { | 278 virtual ~DisassemblerX64() { |
236 } | 279 } |
237 | 280 |
238 // Writes one disassembled instruction into 'buffer' (0-terminated). | 281 // Writes one disassembled instruction into 'buffer' (0-terminated). |
239 // Returns the length of the disassembled machine instruction in bytes. | 282 // Returns the length of the disassembled machine instruction in bytes. |
240 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); | 283 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); |
241 | 284 |
242 private: | 285 private: |
286 enum OperandSize { | |
287 BYTE_SIZE = 0, | |
288 WORD_SIZE = 1, | |
289 DOUBLEWORD_SIZE = 2, | |
290 QUADWORD_SIZE = 3 | |
291 }; | |
243 | 292 |
244 const NameConverter& converter_; | 293 const NameConverter& converter_; |
245 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; | 294 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; |
246 unsigned int tmp_buffer_pos_; | 295 unsigned int tmp_buffer_pos_; |
247 bool abort_on_unimplemented_; | 296 bool abort_on_unimplemented_; |
248 // Prefixes parsed | 297 // Prefixes parsed |
249 byte rex_; | 298 byte rex_; |
250 byte operand_size_; | 299 byte operand_size_; |
300 // Byte size operand override. | |
301 bool byte_size_operand_; | |
251 | 302 |
252 void setOperandSizePrefix(byte prefix) { | 303 void setOperandSizePrefix(byte prefix) { |
253 ASSERT_EQ(0x66, prefix); | 304 ASSERT_EQ(0x66, prefix); |
254 operand_size_ = prefix; | 305 operand_size_ = prefix; |
255 } | 306 } |
256 | 307 |
257 void setRex(byte rex) { | 308 void setRex(byte rex) { |
258 ASSERT_EQ(0x40, rex & 0xF0); | 309 ASSERT_EQ(0x40, rex & 0xF0); |
259 rex_ = rex; | 310 rex_ = rex; |
260 } | 311 } |
261 | 312 |
262 bool rex() { return rex_ != 0; } | 313 bool rex() { return rex_ != 0; } |
263 | 314 |
264 bool rex_b() { return (rex_ & 0x01) != 0; } | 315 bool rex_b() { return (rex_ & 0x01) != 0; } |
265 | 316 |
266 // Actual number of base register given the low bits and the rex.b state. | 317 // Actual number of base register given the low bits and the rex.b state. |
267 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } | 318 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } |
268 | 319 |
269 bool rex_x() { return (rex_ & 0x02) != 0; } | 320 bool rex_x() { return (rex_ & 0x02) != 0; } |
270 | 321 |
271 bool rex_r() { return (rex_ & 0x04) != 0; } | 322 bool rex_r() { return (rex_ & 0x04) != 0; } |
272 | 323 |
273 bool rex_w() { return (rex_ & 0x08) != 0; } | 324 bool rex_w() { return (rex_ & 0x08) != 0; } |
274 | 325 |
275 int operand_size() { | 326 OperandSize operand_size() { |
276 return rex_w() ? 64 : (operand_size_ != 0) ? 16 : 32; | 327 if (byte_size_operand_) return BYTE_SIZE; |
328 if (rex_w()) return QUADWORD_SIZE; | |
329 if (operand_size_ != 0) return WORD_SIZE; | |
330 return DOUBLEWORD_SIZE; | |
277 } | 331 } |
278 | 332 |
279 char operand_size_code() { | 333 char operand_size_code() { |
280 return rex_w() ? 'q' : (operand_size_ != 0) ? 'w' : 'l'; | 334 return "bwlq"[operand_size()]; |
281 } | 335 } |
282 | 336 |
283 const char* NameOfCPURegister(int reg) const { | 337 const char* NameOfCPURegister(int reg) const { |
284 return converter_.NameOfCPURegister(reg); | 338 return converter_.NameOfCPURegister(reg); |
285 } | 339 } |
286 | 340 |
287 const char* NameOfByteCPURegister(int reg) const { | 341 const char* NameOfByteCPURegister(int reg) const { |
288 return converter_.NameOfByteCPURegister(reg); | 342 return converter_.NameOfByteCPURegister(reg); |
289 } | 343 } |
290 | 344 |
(...skipping 14 matching lines...) Expand all Loading... | |
305 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0); | 359 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0); |
306 *rm = (data & 7) | (rex_b() ? 8 : 0); | 360 *rm = (data & 7) | (rex_b() ? 8 : 0); |
307 } | 361 } |
308 | 362 |
309 void get_sib(byte data, | 363 void get_sib(byte data, |
310 int* scale, | 364 int* scale, |
311 int* index, | 365 int* index, |
312 int* base) { | 366 int* base) { |
313 *scale = (data >> 6) & 3; | 367 *scale = (data >> 6) & 3; |
314 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0); | 368 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0); |
315 *base = data & 7 | (rex_b() ? 8 : 0); | 369 *base = (data & 7) | (rex_b() ? 8 : 0); |
316 } | 370 } |
317 | 371 |
318 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; | 372 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; |
319 | 373 |
320 int PrintRightOperandHelper(byte* modrmp, | 374 int PrintRightOperandHelper(byte* modrmp, |
321 RegisterNameMapping register_name); | 375 RegisterNameMapping register_name); |
322 int PrintRightOperand(byte* modrmp); | 376 int PrintRightOperand(byte* modrmp); |
323 int PrintRightByteOperand(byte* modrmp); | 377 int PrintRightByteOperand(byte* modrmp); |
324 int PrintOperands(const char* mnem, | 378 int PrintOperands(const char* mnem, |
325 OperandOrder op_order, | 379 OperandType op_order, |
326 byte* data); | 380 byte* data); |
381 int PrintImmediate(byte* data, OperandSize size); | |
327 int PrintImmediateOp(byte* data); | 382 int PrintImmediateOp(byte* data); |
328 int F7Instruction(byte* data); | 383 int F7Instruction(byte* data); |
329 int D1D3C1Instruction(byte* data); | 384 int ShiftInstruction(byte* data); |
330 int JumpShort(byte* data); | 385 int JumpShort(byte* data); |
331 int JumpConditional(byte* data); | 386 int JumpConditional(byte* data); |
332 int JumpConditionalShort(byte* data); | 387 int JumpConditionalShort(byte* data); |
333 int SetCC(byte* data); | 388 int SetCC(byte* data); |
334 int FPUInstruction(byte* data); | 389 int FPUInstruction(byte* data); |
335 void AppendToBuffer(const char* format, ...); | 390 void AppendToBuffer(const char* format, ...); |
336 | 391 |
337 void UnimplementedInstruction() { | 392 void UnimplementedInstruction() { |
338 if (abort_on_unimplemented_) { | 393 if (abort_on_unimplemented_) { |
339 UNIMPLEMENTED(); | 394 UNIMPLEMENTED(); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
444 AppendToBuffer("%s", (this->*register_name)(rm)); | 499 AppendToBuffer("%s", (this->*register_name)(rm)); |
445 return 1; | 500 return 1; |
446 default: | 501 default: |
447 UnimplementedInstruction(); | 502 UnimplementedInstruction(); |
448 return 1; | 503 return 1; |
449 } | 504 } |
450 UNREACHABLE(); | 505 UNREACHABLE(); |
451 } | 506 } |
452 | 507 |
453 | 508 |
509 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) { | |
William Hesse
2009/07/14 09:09:22
I would call the argument immediate_size, since th
| |
510 int64_t value; | |
511 int count; | |
512 switch (size) { | |
513 case BYTE_SIZE: | |
514 value = *data; | |
515 count = 1; | |
516 break; | |
517 case WORD_SIZE: | |
518 value = *reinterpret_cast<int16_t*>(data); | |
519 count = 2; | |
520 break; | |
521 case DOUBLEWORD_SIZE: | |
522 value = *reinterpret_cast<uint32_t*>(data); | |
523 count = 4; | |
524 break; | |
525 case QUADWORD_SIZE: | |
526 value = *reinterpret_cast<int32_t*>(data); | |
527 count = 4; | |
528 break; | |
529 default: | |
530 UNREACHABLE(); | |
531 } | |
532 AppendToBuffer(V8_PTR_PREFIX"x", value); | |
533 return count; | |
534 } | |
535 | |
536 | |
454 int DisassemblerX64::PrintRightOperand(byte* modrmp) { | 537 int DisassemblerX64::PrintRightOperand(byte* modrmp) { |
455 return PrintRightOperandHelper(modrmp, | 538 return PrintRightOperandHelper(modrmp, |
456 &DisassemblerX64::NameOfCPURegister); | 539 &DisassemblerX64::NameOfCPURegister); |
457 } | 540 } |
458 | 541 |
459 | 542 |
460 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) { | 543 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) { |
461 return PrintRightOperandHelper(modrmp, | 544 return PrintRightOperandHelper(modrmp, |
462 &DisassemblerX64::NameOfByteCPURegister); | 545 &DisassemblerX64::NameOfByteCPURegister); |
463 } | 546 } |
464 | 547 |
465 | 548 |
466 // Returns number of bytes used including the current *data. | 549 // Returns number of bytes used including the current *data. |
467 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. | 550 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. |
468 int DisassemblerX64::PrintOperands(const char* mnem, | 551 int DisassemblerX64::PrintOperands(const char* mnem, |
469 OperandOrder op_order, | 552 OperandType op_order, |
470 byte* data) { | 553 byte* data) { |
471 byte modrm = *data; | 554 byte modrm = *data; |
472 int mod, regop, rm; | 555 int mod, regop, rm; |
473 get_modrm(modrm, &mod, ®op, &rm); | 556 get_modrm(modrm, &mod, ®op, &rm); |
474 int advance = 0; | 557 int advance = 0; |
558 const char* register_name = | |
559 byte_size_operand_ ? NameOfByteCPURegister(regop) | |
560 : NameOfCPURegister(regop); | |
475 switch (op_order) { | 561 switch (op_order) { |
476 case REG_OPER_OP_ORDER: { | 562 case REG_OPER_OP_ORDER: { |
477 AppendToBuffer("%s%c %s,", | 563 AppendToBuffer("%s%c %s,", |
478 mnem, | 564 mnem, |
479 operand_size_code(), | 565 operand_size_code(), |
480 NameOfCPURegister(regop)); | 566 register_name); |
481 advance = PrintRightOperand(data); | 567 advance = byte_size_operand_ ? PrintRightByteOperand(data) |
568 : PrintRightOperand(data); | |
482 break; | 569 break; |
483 } | 570 } |
484 case OPER_REG_OP_ORDER: { | 571 case OPER_REG_OP_ORDER: { |
485 AppendToBuffer("%s%c ", mnem, operand_size_code()); | 572 AppendToBuffer("%s%c ", mnem, operand_size_code()); |
486 advance = PrintRightOperand(data); | 573 advance = byte_size_operand_ ? PrintRightByteOperand(data) |
487 AppendToBuffer(",%s", NameOfCPURegister(regop)); | 574 : PrintRightOperand(data); |
575 AppendToBuffer(",%s", register_name); | |
488 break; | 576 break; |
489 } | 577 } |
490 default: | 578 default: |
491 UNREACHABLE(); | 579 UNREACHABLE(); |
492 break; | 580 break; |
493 } | 581 } |
494 return advance; | 582 return advance; |
495 } | 583 } |
496 | 584 |
497 | 585 |
498 // Returns number of bytes used by machine instruction, including *data byte. | 586 // Returns number of bytes used by machine instruction, including *data byte. |
499 // Writes immediate instructions to 'tmp_buffer_'. | 587 // Writes immediate instructions to 'tmp_buffer_'. |
500 int DisassemblerX64::PrintImmediateOp(byte* data) { | 588 int DisassemblerX64::PrintImmediateOp(byte* data) { |
501 bool sign_extension_bit = (*data & 0x02) != 0; | 589 bool byte_size_immediate = (*data & 0x02) != 0; |
502 byte modrm = *(data + 1); | 590 byte modrm = *(data + 1); |
503 int mod, regop, rm; | 591 int mod, regop, rm; |
504 get_modrm(modrm, &mod, ®op, &rm); | 592 get_modrm(modrm, &mod, ®op, &rm); |
505 const char* mnem = "Imm???"; | 593 const char* mnem = "Imm???"; |
506 switch (regop) { | 594 switch (regop) { |
507 case 0: | 595 case 0: |
508 mnem = "add"; | 596 mnem = "add"; |
509 break; | 597 break; |
510 case 1: | 598 case 1: |
511 mnem = "or"; | 599 mnem = "or"; |
512 break; | 600 break; |
513 case 2: | 601 case 2: |
514 mnem = "adc"; | 602 mnem = "adc"; |
515 break; | 603 break; |
516 case 4: | 604 case 4: |
517 mnem = "and"; | 605 mnem = "and"; |
518 break; | 606 break; |
519 case 5: | 607 case 5: |
520 mnem = "sub"; | 608 mnem = "sub"; |
521 break; | 609 break; |
522 case 6: | 610 case 6: |
523 mnem = "xor"; | 611 mnem = "xor"; |
524 break; | 612 break; |
525 case 7: | 613 case 7: |
526 mnem = "cmp"; | 614 mnem = "cmp"; |
527 break; | 615 break; |
528 default: | 616 default: |
529 UnimplementedInstruction(); | 617 UnimplementedInstruction(); |
530 } | 618 } |
531 AppendToBuffer("%s ", mnem); | 619 AppendToBuffer("%s%c ", mnem, operand_size_code()); |
532 int count = PrintRightOperand(data + 1); | 620 int count = PrintRightOperand(data + 1); |
533 if (sign_extension_bit) { | 621 AppendToBuffer(",0x"); |
534 AppendToBuffer(",0x%x", *(data + 1 + count)); | 622 OperandSize op_size = byte_size_immediate ? BYTE_SIZE : operand_size(); |
William Hesse
2009/07/14 09:09:22
immediate_size, not op_size.
| |
535 return 1 + count + 1 /*int8*/; | 623 count += PrintImmediate(data + 1 + count, op_size); |
536 } else { | 624 return 1 + count; |
537 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); | |
538 return 1 + count + 4 /*int32_t*/; | |
539 } | |
540 } | 625 } |
541 | 626 |
542 | 627 |
543 // Returns number of bytes used, including *data. | 628 // Returns number of bytes used, including *data. |
544 int DisassemblerX64::F7Instruction(byte* data) { | 629 int DisassemblerX64::F7Instruction(byte* data) { |
545 assert(*data == 0xF7); | 630 assert(*data == 0xF7); |
546 byte modrm = *(data + 1); | 631 byte modrm = *(data + 1); |
547 int mod, regop, rm; | 632 int mod, regop, rm; |
548 get_modrm(modrm, &mod, ®op, &rm); | 633 get_modrm(modrm, &mod, ®op, &rm); |
549 if (mod == 3 && regop != 0) { | 634 if (mod == 3 && regop != 0) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
582 int32_t imm = *reinterpret_cast<int32_t*>(data + 1 + count); | 667 int32_t imm = *reinterpret_cast<int32_t*>(data + 1 + count); |
583 AppendToBuffer(",0x%x", imm); | 668 AppendToBuffer(",0x%x", imm); |
584 return 1 + count + 4 /*int32_t*/; | 669 return 1 + count + 4 /*int32_t*/; |
585 } else { | 670 } else { |
586 UnimplementedInstruction(); | 671 UnimplementedInstruction(); |
587 return 2; | 672 return 2; |
588 } | 673 } |
589 } | 674 } |
590 | 675 |
591 | 676 |
592 int DisassemblerX64::D1D3C1Instruction(byte* data) { | 677 int DisassemblerX64::ShiftInstruction(byte* data) { |
593 byte op = *data; | 678 byte op = *data & (~1); |
594 assert(op == 0xD1 || op == 0xD3 || op == 0xC1); | 679 if (op != 0xD0 && op == 0xD0 && op == 0xC0) { |
680 UnimplementedInstruction(); | |
681 return 1; | |
682 } | |
595 byte modrm = *(data + 1); | 683 byte modrm = *(data + 1); |
596 int mod, regop, rm; | 684 int mod, regop, rm; |
597 get_modrm(modrm, &mod, ®op, &rm); | 685 get_modrm(modrm, &mod, ®op, &rm); |
598 ASSERT(regop < 8); | 686 ASSERT(regop < 8); |
599 int imm8 = -1; | 687 int imm8 = -1; |
600 int num_bytes = 2; | 688 int num_bytes = 2; |
601 if (mod == 3) { | 689 if (mod != 3) { |
602 const char* mnem = NULL; | 690 UnimplementedInstruction(); |
603 if (op == 0xD1) { | 691 return num_bytes; |
604 imm8 = 1; | 692 } |
605 switch (regop) { | 693 const char* mnem = NULL; |
606 case 2: | 694 switch (regop) { |
607 mnem = "rcl"; | 695 case 0: |
608 break; | 696 mnem = "rol"; |
609 case 7: | 697 break; |
610 mnem = "sar"; | 698 case 1: |
611 break; | 699 mnem = "ror"; |
612 case 4: | 700 break; |
613 mnem = "shl"; | 701 case 2: |
614 break; | 702 mnem = "rcl"; |
615 default: | 703 break; |
616 UnimplementedInstruction(); | 704 case 3: |
617 } | 705 mnem = "rcr"; |
618 } else if (op == 0xC1) { | 706 break; |
619 imm8 = *(data + 2); | 707 case 4: |
620 num_bytes = 3; | 708 mnem = "shl"; |
621 switch (regop) { | 709 break; |
622 case 2: | 710 case 5: |
623 mnem = "rcl"; | 711 mnem = "shr"; |
624 break; | 712 break; |
625 case 4: | 713 case 7: |
626 mnem = "shl"; | 714 mnem = "sar"; |
627 break; | 715 break; |
628 case 5: | 716 default: |
629 mnem = "shr"; | 717 UnimplementedInstruction(); |
630 break; | 718 return num_bytes; |
631 case 7: | 719 } |
632 mnem = "sar"; | 720 assert(mnem != NULL); |
633 break; | 721 if (op == 0xD0) { |
634 default: | 722 imm8 = 1; |
635 UnimplementedInstruction(); | 723 } else if (op == 0xC0) { |
636 } | 724 imm8 = *(data + 2); |
637 } else if (op == 0xD3) { | 725 num_bytes = 3; |
638 switch (regop) { | 726 } |
639 case 4: | 727 AppendToBuffer("%s%c %s,", |
640 mnem = "shl"; | 728 mnem, |
641 break; | 729 operand_size_code(), |
642 case 5: | 730 byte_size_operand_ ? NameOfByteCPURegister(rm) |
643 mnem = "shr"; | 731 : NameOfCPURegister(rm)); |
644 break; | 732 if (imm8 > 0) { |
William Hesse
2009/07/14 09:09:22
This seems wrong. Why aren't we testing the opcod
| |
645 case 7: | 733 AppendToBuffer("%d", imm8); |
646 mnem = "sar"; | |
647 break; | |
648 default: | |
649 UnimplementedInstruction(); | |
650 } | |
651 } | |
652 assert(mnem != NULL); | |
653 AppendToBuffer("%s%c %s,", | |
654 mnem, | |
655 operand_size_code(), | |
656 NameOfCPURegister(rm)); | |
657 if (imm8 > 0) { | |
658 AppendToBuffer("%d", imm8); | |
659 } else { | |
660 AppendToBuffer("cl"); | |
661 } | |
662 } else { | 734 } else { |
663 UnimplementedInstruction(); | 735 AppendToBuffer("cl"); |
664 } | 736 } |
665 return num_bytes; | 737 return num_bytes; |
666 } | 738 } |
667 | 739 |
668 | 740 |
669 // Returns number of bytes used, including *data. | 741 // Returns number of bytes used, including *data. |
670 int DisassemblerX64::JumpShort(byte* data) { | 742 int DisassemblerX64::JumpShort(byte* data) { |
671 assert(*data == 0xEB); | 743 assert(*data == 0xEB); |
672 byte b = *(data + 1); | 744 byte b = *(data + 1); |
673 byte* dest = data + static_cast<int8_t>(b) + 2; | 745 byte* dest = data + static_cast<int8_t>(b) + 2; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
709 } | 781 } |
710 | 782 |
711 | 783 |
712 // Returns number of bytes used, including *data. | 784 // Returns number of bytes used, including *data. |
713 int DisassemblerX64::FPUInstruction(byte* data) { | 785 int DisassemblerX64::FPUInstruction(byte* data) { |
714 byte b1 = *data; | 786 byte b1 = *data; |
715 byte b2 = *(data + 1); | 787 byte b2 = *(data + 1); |
716 if (b1 == 0xD9) { | 788 if (b1 == 0xD9) { |
717 const char* mnem = NULL; | 789 const char* mnem = NULL; |
718 switch (b2) { | 790 switch (b2) { |
719 case 0xE8: | 791 case 0xE0: |
720 mnem = "fld1"; | 792 mnem = "fchs"; |
721 break; | |
722 case 0xEE: | |
723 mnem = "fldz"; | |
724 break; | 793 break; |
725 case 0xE1: | 794 case 0xE1: |
726 mnem = "fabs"; | 795 mnem = "fabs"; |
727 break; | 796 break; |
728 case 0xE0: | 797 case 0xE4: |
729 mnem = "fchs"; | 798 mnem = "ftst"; |
730 break; | |
731 case 0xF8: | |
732 mnem = "fprem"; | |
733 break; | 799 break; |
734 case 0xF5: | 800 case 0xF5: |
735 mnem = "fprem1"; | 801 mnem = "fprem1"; |
736 break; | 802 break; |
737 case 0xF7: | 803 case 0xF7: |
738 mnem = "fincstp"; | 804 mnem = "fincstp"; |
739 break; | 805 break; |
740 case 0xE4: | 806 case 0xE8: |
741 mnem = "ftst"; | 807 mnem = "fld1"; |
808 break; | |
809 case 0xEE: | |
810 mnem = "fldz"; | |
811 break; | |
812 case 0xF8: | |
813 mnem = "fprem"; | |
742 break; | 814 break; |
743 } | 815 } |
744 if (mnem != NULL) { | 816 if (mnem != NULL) { |
745 AppendToBuffer("%s", mnem); | 817 AppendToBuffer("%s", mnem); |
746 return 2; | 818 return 2; |
747 } else if ((b2 & 0xF8) == 0xC8) { | 819 } else if ((b2 & 0xF8) == 0xC8) { |
748 AppendToBuffer("fxch st%d", b2 & 0x7); | 820 AppendToBuffer("fxch st%d", b2 & 0x7); |
749 return 2; | 821 return 2; |
750 } else { | 822 } else { |
751 int mod, regop, rm; | 823 int mod, regop, rm; |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
899 tmp_buffer_pos_ = 0; // starting to write as position 0 | 971 tmp_buffer_pos_ = 0; // starting to write as position 0 |
900 byte* data = instr; | 972 byte* data = instr; |
901 bool processed = true; // Will be set to false if the current instruction | 973 bool processed = true; // Will be set to false if the current instruction |
902 // is not in 'instructions' table. | 974 // is not in 'instructions' table. |
903 byte current; | 975 byte current; |
904 | 976 |
905 // Scan for prefixes. | 977 // Scan for prefixes. |
906 while (true) { | 978 while (true) { |
907 current = *data; | 979 current = *data; |
908 if (current == 0x66) { | 980 if (current == 0x66) { |
909 setOperandSizePrefix(current); | 981 // If the sequence is 66 0f, it's not a prefix, but a SSE escape. |
982 if (*(data + 1) == 0x0F) break; | |
910 data++; | 983 data++; |
911 } else if ((current & 0xF0) == 0x40) { | 984 } else if ((current & 0xF0) == 0x40) { |
912 setRex(current); | 985 setRex(current); |
913 if (rex_w()) AppendToBuffer("REX.W "); | 986 if (rex_w()) AppendToBuffer("REX.W "); |
914 data++; | 987 data++; |
915 } else { | 988 } else { |
916 break; | 989 break; |
917 } | 990 } |
918 } | 991 } |
919 | 992 |
920 const InstructionDesc& idesc = instruction_table.Get(current); | 993 const InstructionDesc& idesc = instruction_table.Get(current); |
994 byte_size_operand_ = idesc.byte_size_operation; | |
921 switch (idesc.type) { | 995 switch (idesc.type) { |
922 case ZERO_OPERANDS_INSTR: | 996 case ZERO_OPERANDS_INSTR: |
923 AppendToBuffer(idesc.mnem); | 997 AppendToBuffer(idesc.mnem); |
924 data++; | 998 data++; |
925 break; | 999 break; |
926 | 1000 |
927 case TWO_OPERANDS_INSTR: | 1001 case TWO_OPERANDS_INSTR: |
928 data++; | 1002 data++; |
929 data += PrintOperands(idesc.mnem, idesc.op_order_, data); | 1003 data += PrintOperands(idesc.mnem, idesc.op_order_, data); |
930 break; | 1004 break; |
(...skipping 11 matching lines...) Expand all Loading... | |
942 break; | 1016 break; |
943 case PUSHPOP_INSTR: | 1017 case PUSHPOP_INSTR: |
944 AppendToBuffer("%s %s", | 1018 AppendToBuffer("%s %s", |
945 idesc.mnem, | 1019 idesc.mnem, |
946 NameOfCPURegister(base_reg(current & 0x07))); | 1020 NameOfCPURegister(base_reg(current & 0x07))); |
947 data++; | 1021 data++; |
948 break; | 1022 break; |
949 case MOVE_REG_INSTR: { | 1023 case MOVE_REG_INSTR: { |
950 byte* addr = NULL; | 1024 byte* addr = NULL; |
951 switch (operand_size()) { | 1025 switch (operand_size()) { |
952 case 16: | 1026 case WORD_SIZE: |
953 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); | 1027 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); |
954 data += 3; | 1028 data += 3; |
955 break; | 1029 break; |
956 case 32: | 1030 case DOUBLEWORD_SIZE: |
957 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); | 1031 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); |
958 data += 5; | 1032 data += 5; |
959 break; | 1033 break; |
960 case 64: | 1034 case QUADWORD_SIZE: |
961 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); | 1035 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); |
962 data += 9; | 1036 data += 9; |
963 break; | 1037 break; |
964 default: | 1038 default: |
965 UNREACHABLE(); | 1039 UNREACHABLE(); |
966 } | 1040 } |
967 AppendToBuffer("mov%c %s,%s", | 1041 AppendToBuffer("mov%c %s,%s", |
968 operand_size_code(), | 1042 operand_size_code(), |
969 NameOfCPURegister(base_reg(current & 0x07)), | 1043 NameOfCPURegister(base_reg(current & 0x07)), |
970 NameOfAddress(addr)); | 1044 NameOfAddress(addr)); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1005 | 1079 |
1006 case 0x69: // fall through | 1080 case 0x69: // fall through |
1007 case 0x6B: { | 1081 case 0x6B: { |
1008 int mod, regop, rm; | 1082 int mod, regop, rm; |
1009 get_modrm(*(data + 1), &mod, ®op, &rm); | 1083 get_modrm(*(data + 1), &mod, ®op, &rm); |
1010 int32_t imm = *data == 0x6B ? *(data + 2) | 1084 int32_t imm = *data == 0x6B ? *(data + 2) |
1011 : *reinterpret_cast<int32_t*>(data + 2); | 1085 : *reinterpret_cast<int32_t*>(data + 2); |
1012 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop), | 1086 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop), |
1013 NameOfCPURegister(rm), imm); | 1087 NameOfCPURegister(rm), imm); |
1014 data += 2 + (*data == 0x6B ? 1 : 4); | 1088 data += 2 + (*data == 0x6B ? 1 : 4); |
1089 break; | |
1015 } | 1090 } |
1016 break; | |
1017 | 1091 |
1018 case 0xF6: { | 1092 case 0xF6: { |
1019 int mod, regop, rm; | 1093 int mod, regop, rm; |
1020 get_modrm(*(data + 1), &mod, ®op, &rm); | 1094 get_modrm(*(data + 1), &mod, ®op, &rm); |
1021 if (mod == 3 && regop == 0) { | 1095 if (mod == 3 && regop == 0) { |
1022 AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2)); | 1096 AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2)); |
1023 } else { | 1097 } else { |
1024 UnimplementedInstruction(); | 1098 UnimplementedInstruction(); |
1025 } | 1099 } |
1026 data += 3; | 1100 data += 3; |
1101 break; | |
1027 } | 1102 } |
1028 break; | |
1029 | 1103 |
1030 case 0x81: // fall through | 1104 case 0x81: // fall through |
1031 case 0x83: // 0x81 with sign extension bit set | 1105 case 0x83: // 0x81 with sign extension bit set |
1032 data += PrintImmediateOp(data); | 1106 data += PrintImmediateOp(data); |
1033 break; | 1107 break; |
1034 | 1108 |
1035 case 0x0F: { | 1109 case 0x0F: { |
1036 byte f0byte = *(data + 1); | 1110 byte f0byte = *(data + 1); |
1037 const char* f0mnem = F0Mnem(f0byte); | 1111 const char* f0mnem = F0Mnem(f0byte); |
1038 if (f0byte == 0x1F) { | 1112 if (f0byte == 0x1F) { |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1163 break; | 1237 break; |
1164 | 1238 |
1165 case 0x90: | 1239 case 0x90: |
1166 case 0x91: | 1240 case 0x91: |
1167 case 0x92: | 1241 case 0x92: |
1168 case 0x93: | 1242 case 0x93: |
1169 case 0x94: | 1243 case 0x94: |
1170 case 0x95: | 1244 case 0x95: |
1171 case 0x96: | 1245 case 0x96: |
1172 case 0x97: { | 1246 case 0x97: { |
1173 int reg = current & 0x7 | (rex_b() ? 8 : 0); | 1247 int reg = (current & 0x7) | (rex_b() ? 8 : 0); |
1174 if (reg == 0) { | 1248 if (reg == 0) { |
1175 AppendToBuffer("nop"); // Common name for xchg rax,rax. | 1249 AppendToBuffer("nop"); // Common name for xchg rax,rax. |
1176 } else { | 1250 } else { |
1177 AppendToBuffer("xchg%c rax, %s", | 1251 AppendToBuffer("xchg%c rax, %s", |
1178 operand_size_code(), | 1252 operand_size_code(), |
1179 NameOfByteCPURegister(reg)); | 1253 NameOfCPURegister(reg)); |
1180 } | 1254 } |
1181 } | 1255 } |
1182 | 1256 |
1183 | 1257 |
1184 case 0xFE: { | 1258 case 0xFE: { |
1185 data++; | 1259 data++; |
1186 int mod, regop, rm; | 1260 int mod, regop, rm; |
1187 get_modrm(*data, &mod, ®op, &rm); | 1261 get_modrm(*data, &mod, ®op, &rm); |
1188 if (mod == 3 && regop == 1) { | 1262 if (mod == 3 && regop == 1) { |
1189 AppendToBuffer("decb %s", NameOfCPURegister(rm)); | 1263 AppendToBuffer("decb %s", NameOfCPURegister(rm)); |
(...skipping 12 matching lines...) Expand all Loading... | |
1202 case 0x6A: | 1276 case 0x6A: |
1203 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); | 1277 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); |
1204 data += 2; | 1278 data += 2; |
1205 break; | 1279 break; |
1206 | 1280 |
1207 case 0xA8: | 1281 case 0xA8: |
1208 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1)); | 1282 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1)); |
1209 data += 2; | 1283 data += 2; |
1210 break; | 1284 break; |
1211 | 1285 |
1212 case 0xA9: | 1286 case 0xA9: { |
1213 AppendToBuffer("test%c rax,0x%x", // CHECKME! | 1287 int64_t value; |
1288 switch (operand_size()) { | |
1289 case WORD_SIZE: | |
1290 value = *reinterpret_cast<uint16_t*>(data + 1); | |
1291 data += 3; | |
1292 break; | |
1293 case DOUBLEWORD_SIZE: | |
1294 value = *reinterpret_cast<uint32_t*>(data + 1); | |
1295 data += 5; | |
1296 break; | |
1297 case QUADWORD_SIZE: | |
1298 value = *reinterpret_cast<int32_t*>(data + 1); | |
1299 data += 5; | |
1300 break; | |
1301 default: | |
1302 UNREACHABLE(); | |
1303 } | |
1304 break; | |
1305 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux", | |
1214 operand_size_code(), | 1306 operand_size_code(), |
1215 *reinterpret_cast<int32_t*>(data + 1)); | 1307 value); |
1216 data += 5; | 1308 } |
1217 break; | |
1218 | |
1219 case 0xD1: // fall through | 1309 case 0xD1: // fall through |
1220 case 0xD3: // fall through | 1310 case 0xD3: // fall through |
1221 case 0xC1: | 1311 case 0xC1: |
1222 data += D1D3C1Instruction(data); | 1312 data += ShiftInstruction(data); |
1313 break; | |
1314 case 0xD0: // fall through | |
1315 case 0xD2: // fall through | |
1316 case 0xC0: | |
1317 byte_size_operand_ = true; | |
1318 data += ShiftInstruction(data); | |
1223 break; | 1319 break; |
1224 | 1320 |
1225 case 0xD9: // fall through | 1321 case 0xD9: // fall through |
1226 case 0xDA: // fall through | 1322 case 0xDA: // fall through |
1227 case 0xDB: // fall through | 1323 case 0xDB: // fall through |
1228 case 0xDC: // fall through | 1324 case 0xDC: // fall through |
1229 case 0xDD: // fall through | 1325 case 0xDD: // fall through |
1230 case 0xDE: // fall through | 1326 case 0xDE: // fall through |
1231 case 0xDF: | 1327 case 0xDF: |
1232 data += FPUInstruction(data); | 1328 data += FPUInstruction(data); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1282 NameOfXMMRegister(rm)); | 1378 NameOfXMMRegister(rm)); |
1283 data++; | 1379 data++; |
1284 } | 1380 } |
1285 } | 1381 } |
1286 } else { | 1382 } else { |
1287 UnimplementedInstruction(); | 1383 UnimplementedInstruction(); |
1288 } | 1384 } |
1289 break; | 1385 break; |
1290 | 1386 |
1291 case 0xF3: | 1387 case 0xF3: |
1292 if (*(data + 1) == 0x0F && *(data + 2) == 0x2C) { | 1388 if (*(data + 1) == 0x0F) { |
1293 data += 3; | 1389 if (*(data + 2) == 0x2C) { |
1294 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data); | 1390 data += 3; |
1391 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data); | |
1392 } else { | |
1393 UnimplementedInstruction(); | |
1394 data += 1; | |
1395 } | |
1295 } else { | 1396 } else { |
1296 UnimplementedInstruction(); | 1397 UnimplementedInstruction(); |
1398 data += 1; | |
1297 } | 1399 } |
1298 break; | 1400 break; |
1299 | 1401 |
1300 case 0xF7: | 1402 case 0xF7: |
1301 data += F7Instruction(data); | 1403 data += F7Instruction(data); |
1302 break; | 1404 break; |
1303 | 1405 |
1304 default: | 1406 default: |
1305 UnimplementedInstruction(); | 1407 UnimplementedInstruction(); |
1408 data += 1; | |
1306 } | 1409 } |
1307 } // !processed | 1410 } // !processed |
1308 | 1411 |
1309 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { | 1412 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { |
1310 tmp_buffer_[tmp_buffer_pos_] = '\0'; | 1413 tmp_buffer_[tmp_buffer_pos_] = '\0'; |
1311 } | 1414 } |
1312 | 1415 |
1313 int instr_len = data - instr; | 1416 int instr_len = data - instr; |
1314 ASSERT(instr_len > 0); // Ensure progress. | 1417 ASSERT(instr_len > 0); // Ensure progress. |
1315 | 1418 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1423 fprintf(f, "%02x", *bp); | 1526 fprintf(f, "%02x", *bp); |
1424 } | 1527 } |
1425 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { | 1528 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { |
1426 fprintf(f, " "); | 1529 fprintf(f, " "); |
1427 } | 1530 } |
1428 fprintf(f, " %s\n", buffer.start()); | 1531 fprintf(f, " %s\n", buffer.start()); |
1429 } | 1532 } |
1430 } | 1533 } |
1431 | 1534 |
1432 } // namespace disasm | 1535 } // namespace disasm |
OLD | NEW |