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 20 matching lines...) Expand all Loading... |
31 | 31 |
32 //------------------------------------------------------------------ | 32 //------------------------------------------------------------------ |
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 | |
42 static const ByteMnemonic two_operands_instr[] = { | 41 static const ByteMnemonic two_operands_instr[] = { |
43 {0x00, BYTE_OPER_REG_OP_ORDER, "add"}, | 42 {0x00, BYTE_OPER_REG_OP_ORDER, "add"}, |
44 {0x01, OPER_REG_OP_ORDER, "add"}, | 43 {0x01, OPER_REG_OP_ORDER, "add"}, |
45 {0x02, BYTE_REG_OPER_OP_ORDER, "add"}, | 44 {0x02, BYTE_REG_OPER_OP_ORDER, "add"}, |
46 {0x03, REG_OPER_OP_ORDER, "add"}, | 45 {0x03, REG_OPER_OP_ORDER, "add"}, |
47 {0x08, BYTE_OPER_REG_OP_ORDER, "or"}, | 46 {0x08, BYTE_OPER_REG_OP_ORDER, "or"}, |
48 {0x09, OPER_REG_OP_ORDER, "or"}, | 47 {0x09, OPER_REG_OP_ORDER, "or"}, |
49 {0x0A, BYTE_REG_OPER_OP_ORDER, "or"}, | 48 {0x0A, BYTE_REG_OPER_OP_ORDER, "or"}, |
50 {0x0B, REG_OPER_OP_ORDER, "or"}, | 49 {0x0B, REG_OPER_OP_ORDER, "or"}, |
51 {0x10, BYTE_OPER_REG_OP_ORDER, "adc"}, | 50 {0x10, BYTE_OPER_REG_OP_ORDER, "adc"}, |
(...skipping 25 matching lines...) Expand all Loading... |
77 {0x85, REG_OPER_OP_ORDER, "test"}, | 76 {0x85, REG_OPER_OP_ORDER, "test"}, |
78 {0x86, BYTE_REG_OPER_OP_ORDER, "xchg"}, | 77 {0x86, BYTE_REG_OPER_OP_ORDER, "xchg"}, |
79 {0x87, REG_OPER_OP_ORDER, "xchg"}, | 78 {0x87, REG_OPER_OP_ORDER, "xchg"}, |
80 {0x88, BYTE_OPER_REG_OP_ORDER, "mov"}, | 79 {0x88, BYTE_OPER_REG_OP_ORDER, "mov"}, |
81 {0x89, OPER_REG_OP_ORDER, "mov"}, | 80 {0x89, OPER_REG_OP_ORDER, "mov"}, |
82 {0x8A, BYTE_REG_OPER_OP_ORDER, "mov"}, | 81 {0x8A, BYTE_REG_OPER_OP_ORDER, "mov"}, |
83 {0x8B, REG_OPER_OP_ORDER, "mov"}, | 82 {0x8B, REG_OPER_OP_ORDER, "mov"}, |
84 {0x8D, REG_OPER_OP_ORDER, "lea"}, | 83 {0x8D, REG_OPER_OP_ORDER, "lea"}, |
85 {-1, UNSET_OP_ORDER, ""}}; | 84 {-1, UNSET_OP_ORDER, ""}}; |
86 | 85 |
87 | |
88 static const ByteMnemonic zero_operands_instr[] = { | 86 static const ByteMnemonic zero_operands_instr[] = { |
89 {0xC3, UNSET_OP_ORDER, "ret"}, {0xC9, UNSET_OP_ORDER, "leave"}, | 87 {0xC3, UNSET_OP_ORDER, "ret"}, {0xC9, UNSET_OP_ORDER, "leave"}, |
90 {0xF4, UNSET_OP_ORDER, "hlt"}, {0xFC, UNSET_OP_ORDER, "cld"}, | 88 {0xF4, UNSET_OP_ORDER, "hlt"}, {0xFC, UNSET_OP_ORDER, "cld"}, |
91 {0xCC, UNSET_OP_ORDER, "int3"}, {0x60, UNSET_OP_ORDER, "pushad"}, | 89 {0xCC, UNSET_OP_ORDER, "int3"}, {0x60, UNSET_OP_ORDER, "pushad"}, |
92 {0x61, UNSET_OP_ORDER, "popad"}, {0x9C, UNSET_OP_ORDER, "pushfd"}, | 90 {0x61, UNSET_OP_ORDER, "popad"}, {0x9C, UNSET_OP_ORDER, "pushfd"}, |
93 {0x9D, UNSET_OP_ORDER, "popfd"}, {0x9E, UNSET_OP_ORDER, "sahf"}, | 91 {0x9D, UNSET_OP_ORDER, "popfd"}, {0x9E, UNSET_OP_ORDER, "sahf"}, |
94 {0x99, UNSET_OP_ORDER, "cdq"}, {0x9B, UNSET_OP_ORDER, "fwait"}, | 92 {0x99, UNSET_OP_ORDER, "cdq"}, {0x9B, UNSET_OP_ORDER, "fwait"}, |
95 {0xA4, UNSET_OP_ORDER, "movs"}, {0xA5, UNSET_OP_ORDER, "movs"}, | 93 {0xA4, UNSET_OP_ORDER, "movs"}, {0xA5, UNSET_OP_ORDER, "movs"}, |
96 {0xA6, UNSET_OP_ORDER, "cmps"}, {0xA7, UNSET_OP_ORDER, "cmps"}, | 94 {0xA6, UNSET_OP_ORDER, "cmps"}, {0xA7, UNSET_OP_ORDER, "cmps"}, |
97 {-1, UNSET_OP_ORDER, ""}}; | 95 {-1, UNSET_OP_ORDER, ""}}; |
98 | 96 |
99 | |
100 static const ByteMnemonic call_jump_instr[] = {{0xE8, UNSET_OP_ORDER, "call"}, | 97 static const ByteMnemonic call_jump_instr[] = {{0xE8, UNSET_OP_ORDER, "call"}, |
101 {0xE9, UNSET_OP_ORDER, "jmp"}, | 98 {0xE9, UNSET_OP_ORDER, "jmp"}, |
102 {-1, UNSET_OP_ORDER, ""}}; | 99 {-1, UNSET_OP_ORDER, ""}}; |
103 | 100 |
104 | |
105 static const ByteMnemonic short_immediate_instr[] = { | 101 static const ByteMnemonic short_immediate_instr[] = { |
106 {0x05, UNSET_OP_ORDER, "add"}, {0x0D, UNSET_OP_ORDER, "or"}, | 102 {0x05, UNSET_OP_ORDER, "add"}, {0x0D, UNSET_OP_ORDER, "or"}, |
107 {0x15, UNSET_OP_ORDER, "adc"}, {0x1D, UNSET_OP_ORDER, "sbb"}, | 103 {0x15, UNSET_OP_ORDER, "adc"}, {0x1D, UNSET_OP_ORDER, "sbb"}, |
108 {0x25, UNSET_OP_ORDER, "and"}, {0x2D, UNSET_OP_ORDER, "sub"}, | 104 {0x25, UNSET_OP_ORDER, "and"}, {0x2D, UNSET_OP_ORDER, "sub"}, |
109 {0x35, UNSET_OP_ORDER, "xor"}, {0x3D, UNSET_OP_ORDER, "cmp"}, | 105 {0x35, UNSET_OP_ORDER, "xor"}, {0x3D, UNSET_OP_ORDER, "cmp"}, |
110 {-1, UNSET_OP_ORDER, ""}}; | 106 {-1, UNSET_OP_ORDER, ""}}; |
111 | 107 |
112 | |
113 static const char* const conditional_code_suffix[] = { | 108 static const char* const conditional_code_suffix[] = { |
114 "o", "no", "c", "nc", "z", "nz", "na", "a", | 109 "o", "no", "c", "nc", "z", "nz", "na", "a", |
115 "s", "ns", "pe", "po", "l", "ge", "le", "g"}; | 110 "s", "ns", "pe", "po", "l", "ge", "le", "g"}; |
116 | 111 |
117 | |
118 enum InstructionType { | 112 enum InstructionType { |
119 NO_INSTR, | 113 NO_INSTR, |
120 ZERO_OPERANDS_INSTR, | 114 ZERO_OPERANDS_INSTR, |
121 TWO_OPERANDS_INSTR, | 115 TWO_OPERANDS_INSTR, |
122 JUMP_CONDITIONAL_SHORT_INSTR, | 116 JUMP_CONDITIONAL_SHORT_INSTR, |
123 REGISTER_INSTR, | 117 REGISTER_INSTR, |
124 PUSHPOP_INSTR, // Has implicit 64-bit operand size. | 118 PUSHPOP_INSTR, // Has implicit 64-bit operand size. |
125 MOVE_REG_INSTR, | 119 MOVE_REG_INSTR, |
126 CALL_JUMP_INSTR, | 120 CALL_JUMP_INSTR, |
127 SHORT_IMMEDIATE_INSTR | 121 SHORT_IMMEDIATE_INSTR |
128 }; | 122 }; |
129 | 123 |
130 | |
131 enum Prefixes { | 124 enum Prefixes { |
132 ESCAPE_PREFIX = 0x0F, | 125 ESCAPE_PREFIX = 0x0F, |
133 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66, | 126 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66, |
134 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67, | 127 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67, |
135 REPNE_PREFIX = 0xF2, | 128 REPNE_PREFIX = 0xF2, |
136 REP_PREFIX = 0xF3, | 129 REP_PREFIX = 0xF3, |
137 REPEQ_PREFIX = REP_PREFIX | 130 REPEQ_PREFIX = REP_PREFIX |
138 }; | 131 }; |
139 | 132 |
140 | |
141 struct InstructionDesc { | 133 struct InstructionDesc { |
142 const char* mnem; | 134 const char* mnem; |
143 InstructionType type; | 135 InstructionType type; |
144 OperandType op_order_; | 136 OperandType op_order_; |
145 bool byte_size_operation; // Fixed 8-bit operation. | 137 bool byte_size_operation; // Fixed 8-bit operation. |
146 }; | 138 }; |
147 | 139 |
148 | |
149 class InstructionTable : public ValueObject { | 140 class InstructionTable : public ValueObject { |
150 public: | 141 public: |
151 InstructionTable(); | 142 InstructionTable(); |
152 const InstructionDesc& Get(uint8_t x) const { return instructions_[x]; } | 143 const InstructionDesc& Get(uint8_t x) const { return instructions_[x]; } |
153 | 144 |
154 private: | 145 private: |
155 InstructionDesc instructions_[256]; | 146 InstructionDesc instructions_[256]; |
156 void Clear(); | 147 void Clear(); |
157 void Init(); | 148 void Init(); |
158 void CopyTable(const ByteMnemonic bm[], InstructionType type); | 149 void CopyTable(const ByteMnemonic bm[], InstructionType type); |
159 void SetTableRange(InstructionType type, | 150 void SetTableRange(InstructionType type, |
160 uint8_t start, | 151 uint8_t start, |
161 uint8_t end, | 152 uint8_t end, |
162 bool byte_size, | 153 bool byte_size, |
163 const char* mnem); | 154 const char* mnem); |
164 void AddJumpConditionalShort(); | 155 void AddJumpConditionalShort(); |
165 | 156 |
166 DISALLOW_COPY_AND_ASSIGN(InstructionTable); | 157 DISALLOW_COPY_AND_ASSIGN(InstructionTable); |
167 }; | 158 }; |
168 | 159 |
169 | |
170 InstructionTable::InstructionTable() { | 160 InstructionTable::InstructionTable() { |
171 Clear(); | 161 Clear(); |
172 Init(); | 162 Init(); |
173 } | 163 } |
174 | 164 |
175 | |
176 void InstructionTable::Clear() { | 165 void InstructionTable::Clear() { |
177 for (int i = 0; i < 256; i++) { | 166 for (int i = 0; i < 256; i++) { |
178 instructions_[i].mnem = "(bad)"; | 167 instructions_[i].mnem = "(bad)"; |
179 instructions_[i].type = NO_INSTR; | 168 instructions_[i].type = NO_INSTR; |
180 instructions_[i].op_order_ = UNSET_OP_ORDER; | 169 instructions_[i].op_order_ = UNSET_OP_ORDER; |
181 instructions_[i].byte_size_operation = false; | 170 instructions_[i].byte_size_operation = false; |
182 } | 171 } |
183 } | 172 } |
184 | 173 |
185 | |
186 void InstructionTable::Init() { | 174 void InstructionTable::Init() { |
187 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); | 175 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); |
188 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); | 176 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); |
189 CopyTable(call_jump_instr, CALL_JUMP_INSTR); | 177 CopyTable(call_jump_instr, CALL_JUMP_INSTR); |
190 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); | 178 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); |
191 AddJumpConditionalShort(); | 179 AddJumpConditionalShort(); |
192 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push"); | 180 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push"); |
193 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop"); | 181 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop"); |
194 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov"); | 182 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov"); |
195 } | 183 } |
196 | 184 |
197 | |
198 void InstructionTable::CopyTable(const ByteMnemonic bm[], | 185 void InstructionTable::CopyTable(const ByteMnemonic bm[], |
199 InstructionType type) { | 186 InstructionType type) { |
200 for (int i = 0; bm[i].b >= 0; i++) { | 187 for (int i = 0; bm[i].b >= 0; i++) { |
201 InstructionDesc* id = &instructions_[bm[i].b]; | 188 InstructionDesc* id = &instructions_[bm[i].b]; |
202 id->mnem = bm[i].mnem; | 189 id->mnem = bm[i].mnem; |
203 OperandType op_order = bm[i].op_order_; | 190 OperandType op_order = bm[i].op_order_; |
204 id->op_order_ = | 191 id->op_order_ = |
205 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG); | 192 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG); |
206 ASSERT(NO_INSTR == id->type); // Information not already entered | 193 ASSERT(NO_INSTR == id->type); // Information not already entered |
207 id->type = type; | 194 id->type = type; |
208 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0); | 195 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0); |
209 } | 196 } |
210 } | 197 } |
211 | 198 |
212 | |
213 void InstructionTable::SetTableRange(InstructionType type, | 199 void InstructionTable::SetTableRange(InstructionType type, |
214 uint8_t start, | 200 uint8_t start, |
215 uint8_t end, | 201 uint8_t end, |
216 bool byte_size, | 202 bool byte_size, |
217 const char* mnem) { | 203 const char* mnem) { |
218 for (uint8_t b = start; b <= end; b++) { | 204 for (uint8_t b = start; b <= end; b++) { |
219 InstructionDesc* id = &instructions_[b]; | 205 InstructionDesc* id = &instructions_[b]; |
220 ASSERT(NO_INSTR == id->type); // Information not already entered | 206 ASSERT(NO_INSTR == id->type); // Information not already entered |
221 id->mnem = mnem; | 207 id->mnem = mnem; |
222 id->type = type; | 208 id->type = type; |
223 id->byte_size_operation = byte_size; | 209 id->byte_size_operation = byte_size; |
224 } | 210 } |
225 } | 211 } |
226 | 212 |
227 | |
228 void InstructionTable::AddJumpConditionalShort() { | 213 void InstructionTable::AddJumpConditionalShort() { |
229 for (uint8_t b = 0x70; b <= 0x7F; b++) { | 214 for (uint8_t b = 0x70; b <= 0x7F; b++) { |
230 InstructionDesc* id = &instructions_[b]; | 215 InstructionDesc* id = &instructions_[b]; |
231 ASSERT(NO_INSTR == id->type); // Information not already entered | 216 ASSERT(NO_INSTR == id->type); // Information not already entered |
232 id->mnem = NULL; // Computed depending on condition code. | 217 id->mnem = NULL; // Computed depending on condition code. |
233 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 218 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
234 } | 219 } |
235 } | 220 } |
236 | 221 |
237 | |
238 static InstructionTable instruction_table; | 222 static InstructionTable instruction_table; |
239 | 223 |
240 | |
241 static InstructionDesc cmov_instructions[16] = { | 224 static InstructionDesc cmov_instructions[16] = { |
242 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 225 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
243 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 226 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
244 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 227 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
245 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 228 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
246 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 229 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
247 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 230 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
248 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 231 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
249 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 232 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
250 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 233 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
251 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 234 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
252 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 235 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
253 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 236 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
254 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 237 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
255 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 238 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
256 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, | 239 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, |
257 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}}; | 240 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}}; |
258 | 241 |
259 | |
260 //------------------------------------------------- | 242 //------------------------------------------------- |
261 // DisassemblerX64 implementation. | 243 // DisassemblerX64 implementation. |
262 | 244 |
263 | |
264 static const int kMaxXmmRegisters = 16; | 245 static const int kMaxXmmRegisters = 16; |
265 static const char* xmm_regs[kMaxXmmRegisters] = { | 246 static const char* xmm_regs[kMaxXmmRegisters] = { |
266 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", | 247 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", |
267 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"}; | 248 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"}; |
268 | 249 |
269 class DisassemblerX64 : public ValueObject { | 250 class DisassemblerX64 : public ValueObject { |
270 public: | 251 public: |
271 DisassemblerX64(char* buffer, intptr_t buffer_size) | 252 DisassemblerX64(char* buffer, intptr_t buffer_size) |
272 : buffer_(buffer), | 253 : buffer_(buffer), |
273 buffer_size_(buffer_size), | 254 buffer_size_(buffer_size), |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 uint8_t rex_; | 366 uint8_t rex_; |
386 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. | 367 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. |
387 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. | 368 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. |
388 uint8_t group_1_prefix_; | 369 uint8_t group_1_prefix_; |
389 // Byte size operand override. | 370 // Byte size operand override. |
390 bool byte_size_operand_; | 371 bool byte_size_operand_; |
391 | 372 |
392 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64); | 373 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64); |
393 }; | 374 }; |
394 | 375 |
395 | |
396 // Append the str to the output buffer. | 376 // Append the str to the output buffer. |
397 void DisassemblerX64::Print(const char* format, ...) { | 377 void DisassemblerX64::Print(const char* format, ...) { |
398 intptr_t available = buffer_size_ - buffer_pos_; | 378 intptr_t available = buffer_size_ - buffer_pos_; |
399 if (available <= 1) { | 379 if (available <= 1) { |
400 ASSERT(buffer_[buffer_pos_] == '\0'); | 380 ASSERT(buffer_[buffer_pos_] == '\0'); |
401 return; | 381 return; |
402 } | 382 } |
403 char* buf = buffer_ + buffer_pos_; | 383 char* buf = buffer_ + buffer_pos_; |
404 va_list args; | 384 va_list args; |
405 va_start(args, format); | 385 va_start(args, format); |
406 int length = OS::VSNPrint(buf, available, format, args); | 386 int length = OS::VSNPrint(buf, available, format, args); |
407 va_end(args); | 387 va_end(args); |
408 buffer_pos_ = | 388 buffer_pos_ = |
409 (length >= available) ? (buffer_size_ - 1) : (buffer_pos_ + length); | 389 (length >= available) ? (buffer_size_ - 1) : (buffer_pos_ + length); |
410 ASSERT(buffer_pos_ < buffer_size_); | 390 ASSERT(buffer_pos_ < buffer_size_); |
411 } | 391 } |
412 | 392 |
413 | |
414 int DisassemblerX64::PrintRightOperandHelper( | 393 int DisassemblerX64::PrintRightOperandHelper( |
415 uint8_t* modrmp, | 394 uint8_t* modrmp, |
416 RegisterNameMapping direct_register_name) { | 395 RegisterNameMapping direct_register_name) { |
417 int mod, regop, rm; | 396 int mod, regop, rm; |
418 get_modrm(*modrmp, &mod, ®op, &rm); | 397 get_modrm(*modrmp, &mod, ®op, &rm); |
419 RegisterNameMapping register_name = | 398 RegisterNameMapping register_name = |
420 (mod == 3) ? direct_register_name : &DisassemblerX64::NameOfCPURegister; | 399 (mod == 3) ? direct_register_name : &DisassemblerX64::NameOfCPURegister; |
421 switch (mod) { | 400 switch (mod) { |
422 case 0: | 401 case 0: |
423 if ((rm & 7) == 5) { | 402 if ((rm & 7) == 5) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 case 3: | 463 case 3: |
485 Print("%s", (this->*register_name)(rm)); | 464 Print("%s", (this->*register_name)(rm)); |
486 return 1; | 465 return 1; |
487 default: | 466 default: |
488 UnimplementedInstruction(); | 467 UnimplementedInstruction(); |
489 return 1; | 468 return 1; |
490 } | 469 } |
491 UNREACHABLE(); | 470 UNREACHABLE(); |
492 } | 471 } |
493 | 472 |
494 | |
495 int DisassemblerX64::PrintImmediate(uint8_t* data, | 473 int DisassemblerX64::PrintImmediate(uint8_t* data, |
496 OperandSize size, | 474 OperandSize size, |
497 bool sign_extend) { | 475 bool sign_extend) { |
498 int64_t value; | 476 int64_t value; |
499 int count; | 477 int count; |
500 switch (size) { | 478 switch (size) { |
501 case BYTE_SIZE: | 479 case BYTE_SIZE: |
502 if (sign_extend) { | 480 if (sign_extend) { |
503 value = *reinterpret_cast<int8_t*>(data); | 481 value = *reinterpret_cast<int8_t*>(data); |
504 } else { | 482 } else { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 | 524 |
547 void DisassemblerX64::PrintDisp(int disp, const char* after) { | 525 void DisassemblerX64::PrintDisp(int disp, const char* after) { |
548 if (-disp > 0) { | 526 if (-disp > 0) { |
549 Print("-%#x", -disp); | 527 Print("-%#x", -disp); |
550 } else { | 528 } else { |
551 Print("+%#x", disp); | 529 Print("+%#x", disp); |
552 } | 530 } |
553 if (after != NULL) Print("%s", after); | 531 if (after != NULL) Print("%s", after); |
554 } | 532 } |
555 | 533 |
556 | |
557 // Returns number of bytes used by machine instruction, including *data byte. | 534 // Returns number of bytes used by machine instruction, including *data byte. |
558 // Writes immediate instructions to 'tmp_buffer_'. | 535 // Writes immediate instructions to 'tmp_buffer_'. |
559 int DisassemblerX64::PrintImmediateOp(uint8_t* data) { | 536 int DisassemblerX64::PrintImmediateOp(uint8_t* data) { |
560 bool byte_size_immediate = (*data & 0x02) != 0; | 537 bool byte_size_immediate = (*data & 0x02) != 0; |
561 uint8_t modrm = *(data + 1); | 538 uint8_t modrm = *(data + 1); |
562 int mod, regop, rm; | 539 int mod, regop, rm; |
563 get_modrm(modrm, &mod, ®op, &rm); | 540 get_modrm(modrm, &mod, ®op, &rm); |
564 const char* mnem = "Imm???"; | 541 const char* mnem = "Imm???"; |
565 switch (regop) { | 542 switch (regop) { |
566 case 0: | 543 case 0: |
(...skipping 25 matching lines...) Expand all Loading... |
592 } | 569 } |
593 Print("%s%c ", mnem, operand_size_code()); | 570 Print("%s%c ", mnem, operand_size_code()); |
594 int count = PrintRightOperand(data + 1); | 571 int count = PrintRightOperand(data + 1); |
595 Print(","); | 572 Print(","); |
596 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size(); | 573 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size(); |
597 count += | 574 count += |
598 PrintImmediate(data + 1 + count, immediate_size, byte_size_immediate); | 575 PrintImmediate(data + 1 + count, immediate_size, byte_size_immediate); |
599 return 1 + count; | 576 return 1 + count; |
600 } | 577 } |
601 | 578 |
602 | |
603 // Returns number of bytes used, including *data. | 579 // Returns number of bytes used, including *data. |
604 int DisassemblerX64::F6F7Instruction(uint8_t* data) { | 580 int DisassemblerX64::F6F7Instruction(uint8_t* data) { |
605 ASSERT(*data == 0xF7 || *data == 0xF6); | 581 ASSERT(*data == 0xF7 || *data == 0xF6); |
606 uint8_t modrm = *(data + 1); | 582 uint8_t modrm = *(data + 1); |
607 int mod, regop, rm; | 583 int mod, regop, rm; |
608 get_modrm(modrm, &mod, ®op, &rm); | 584 get_modrm(modrm, &mod, ®op, &rm); |
609 if (mod == 3 && regop != 0) { | 585 if (mod == 3 && regop != 0) { |
610 const char* mnem = NULL; | 586 const char* mnem = NULL; |
611 switch (regop) { | 587 switch (regop) { |
612 case 2: | 588 case 2: |
(...skipping 21 matching lines...) Expand all Loading... |
634 int count = PrintRightOperand(data + 1); // Use name of 64-bit register. | 610 int count = PrintRightOperand(data + 1); // Use name of 64-bit register. |
635 Print(","); | 611 Print(","); |
636 count += PrintImmediate(data + 1 + count, operand_size()); | 612 count += PrintImmediate(data + 1 + count, operand_size()); |
637 return 1 + count; | 613 return 1 + count; |
638 } else { | 614 } else { |
639 UnimplementedInstruction(); | 615 UnimplementedInstruction(); |
640 return 2; | 616 return 2; |
641 } | 617 } |
642 } | 618 } |
643 | 619 |
644 | |
645 int DisassemblerX64::ShiftInstruction(uint8_t* data) { | 620 int DisassemblerX64::ShiftInstruction(uint8_t* data) { |
646 uint8_t op = *data & (~1); | 621 uint8_t op = *data & (~1); |
647 if (op != 0xD0 && op != 0xD2 && op != 0xC0) { | 622 if (op != 0xD0 && op != 0xD2 && op != 0xC0) { |
648 UnimplementedInstruction(); | 623 UnimplementedInstruction(); |
649 return 1; | 624 return 1; |
650 } | 625 } |
651 uint8_t modrm = *(data + 1); | 626 uint8_t modrm = *(data + 1); |
652 int mod, regop, rm; | 627 int mod, regop, rm; |
653 get_modrm(modrm, &mod, ®op, &rm); | 628 get_modrm(modrm, &mod, ®op, &rm); |
654 regop &= 0x7; // The REX.R bit does not affect the operation. | 629 regop &= 0x7; // The REX.R bit does not affect the operation. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 Print("%s%c %s,", mnem, operand_size_code(), | 670 Print("%s%c %s,", mnem, operand_size_code(), |
696 byte_size_operand_ ? NameOfByteCPURegister(rm) : NameOfCPURegister(rm)); | 671 byte_size_operand_ ? NameOfByteCPURegister(rm) : NameOfCPURegister(rm)); |
697 if (op == 0xD2) { | 672 if (op == 0xD2) { |
698 Print("cl"); | 673 Print("cl"); |
699 } else { | 674 } else { |
700 Print("%d", imm8); | 675 Print("%d", imm8); |
701 } | 676 } |
702 return num_bytes; | 677 return num_bytes; |
703 } | 678 } |
704 | 679 |
705 | |
706 int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) { | 680 int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) { |
707 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfCPURegister); | 681 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfCPURegister); |
708 } | 682 } |
709 | 683 |
710 | |
711 int DisassemblerX64::PrintRightByteOperand(uint8_t* modrmp) { | 684 int DisassemblerX64::PrintRightByteOperand(uint8_t* modrmp) { |
712 return PrintRightOperandHelper(modrmp, | 685 return PrintRightOperandHelper(modrmp, |
713 &DisassemblerX64::NameOfByteCPURegister); | 686 &DisassemblerX64::NameOfByteCPURegister); |
714 } | 687 } |
715 | 688 |
716 | |
717 int DisassemblerX64::PrintRightXMMOperand(uint8_t* modrmp) { | 689 int DisassemblerX64::PrintRightXMMOperand(uint8_t* modrmp) { |
718 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfXMMRegister); | 690 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfXMMRegister); |
719 } | 691 } |
720 | 692 |
721 | |
722 // Returns number of bytes used including the current *data. | 693 // Returns number of bytes used including the current *data. |
723 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. | 694 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. |
724 int DisassemblerX64::PrintOperands(const char* mnem, | 695 int DisassemblerX64::PrintOperands(const char* mnem, |
725 OperandType op_order, | 696 OperandType op_order, |
726 uint8_t* data) { | 697 uint8_t* data) { |
727 uint8_t modrm = *data; | 698 uint8_t modrm = *data; |
728 int mod, regop, rm; | 699 int mod, regop, rm; |
729 get_modrm(modrm, &mod, ®op, &rm); | 700 get_modrm(modrm, &mod, ®op, &rm); |
730 int advance = 0; | 701 int advance = 0; |
731 const char* register_name = byte_size_operand_ ? NameOfByteCPURegister(regop) | 702 const char* register_name = byte_size_operand_ ? NameOfByteCPURegister(regop) |
(...skipping 12 matching lines...) Expand all Loading... |
744 Print(",%s", register_name); | 715 Print(",%s", register_name); |
745 break; | 716 break; |
746 } | 717 } |
747 default: | 718 default: |
748 UNREACHABLE(); | 719 UNREACHABLE(); |
749 break; | 720 break; |
750 } | 721 } |
751 return advance; | 722 return advance; |
752 } | 723 } |
753 | 724 |
754 | |
755 void DisassemblerX64::PrintAddress(uint8_t* addr_byte_ptr) { | 725 void DisassemblerX64::PrintAddress(uint8_t* addr_byte_ptr) { |
756 uword addr = reinterpret_cast<uword>(addr_byte_ptr); | 726 uword addr = reinterpret_cast<uword>(addr_byte_ptr); |
757 Print("%#" Px "", addr); | 727 Print("%#" Px "", addr); |
758 } | 728 } |
759 | 729 |
760 | |
761 // Returns number of bytes used, including *data. | 730 // Returns number of bytes used, including *data. |
762 int DisassemblerX64::JumpShort(uint8_t* data) { | 731 int DisassemblerX64::JumpShort(uint8_t* data) { |
763 ASSERT(0xEB == *data); | 732 ASSERT(0xEB == *data); |
764 uint8_t b = *(data + 1); | 733 uint8_t b = *(data + 1); |
765 uint8_t* dest = data + static_cast<int8_t>(b) + 2; | 734 uint8_t* dest = data + static_cast<int8_t>(b) + 2; |
766 Print("jmp "); | 735 Print("jmp "); |
767 PrintAddress(dest); | 736 PrintAddress(dest); |
768 return 2; | 737 return 2; |
769 } | 738 } |
770 | 739 |
771 | |
772 // Returns number of bytes used, including *data. | 740 // Returns number of bytes used, including *data. |
773 int DisassemblerX64::JumpConditional(uint8_t* data) { | 741 int DisassemblerX64::JumpConditional(uint8_t* data) { |
774 ASSERT(0x0F == *data); | 742 ASSERT(0x0F == *data); |
775 uint8_t cond = *(data + 1) & 0x0F; | 743 uint8_t cond = *(data + 1) & 0x0F; |
776 uint8_t* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6; | 744 uint8_t* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6; |
777 const char* mnem = conditional_code_suffix[cond]; | 745 const char* mnem = conditional_code_suffix[cond]; |
778 Print("j%s ", mnem); | 746 Print("j%s ", mnem); |
779 PrintAddress(dest); | 747 PrintAddress(dest); |
780 return 6; // includes 0x0F | 748 return 6; // includes 0x0F |
781 } | 749 } |
782 | 750 |
783 | |
784 // Returns number of bytes used, including *data. | 751 // Returns number of bytes used, including *data. |
785 int DisassemblerX64::JumpConditionalShort(uint8_t* data) { | 752 int DisassemblerX64::JumpConditionalShort(uint8_t* data) { |
786 uint8_t cond = *data & 0x0F; | 753 uint8_t cond = *data & 0x0F; |
787 uint8_t b = *(data + 1); | 754 uint8_t b = *(data + 1); |
788 uint8_t* dest = data + static_cast<int8_t>(b) + 2; | 755 uint8_t* dest = data + static_cast<int8_t>(b) + 2; |
789 const char* mnem = conditional_code_suffix[cond]; | 756 const char* mnem = conditional_code_suffix[cond]; |
790 Print("j%s ", mnem); | 757 Print("j%s ", mnem); |
791 PrintAddress(dest); | 758 PrintAddress(dest); |
792 return 2; | 759 return 2; |
793 } | 760 } |
794 | 761 |
795 | |
796 // Returns number of bytes used, including *data. | 762 // Returns number of bytes used, including *data. |
797 int DisassemblerX64::SetCC(uint8_t* data) { | 763 int DisassemblerX64::SetCC(uint8_t* data) { |
798 ASSERT(0x0F == *data); | 764 ASSERT(0x0F == *data); |
799 uint8_t cond = *(data + 1) & 0x0F; | 765 uint8_t cond = *(data + 1) & 0x0F; |
800 const char* mnem = conditional_code_suffix[cond]; | 766 const char* mnem = conditional_code_suffix[cond]; |
801 Print("set%s%c ", mnem, operand_size_code()); | 767 Print("set%s%c ", mnem, operand_size_code()); |
802 PrintRightByteOperand(data + 2); | 768 PrintRightByteOperand(data + 2); |
803 return 3; // includes 0x0F | 769 return 3; // includes 0x0F |
804 } | 770 } |
805 | 771 |
806 | |
807 // Returns number of bytes used, including *data. | 772 // Returns number of bytes used, including *data. |
808 int DisassemblerX64::FPUInstruction(uint8_t* data) { | 773 int DisassemblerX64::FPUInstruction(uint8_t* data) { |
809 uint8_t escape_opcode = *data; | 774 uint8_t escape_opcode = *data; |
810 ASSERT(0xD8 == (escape_opcode & 0xF8)); | 775 ASSERT(0xD8 == (escape_opcode & 0xF8)); |
811 uint8_t modrm_byte = *(data + 1); | 776 uint8_t modrm_byte = *(data + 1); |
812 | 777 |
813 if (modrm_byte >= 0xC0) { | 778 if (modrm_byte >= 0xC0) { |
814 return RegisterFPUInstruction(escape_opcode, modrm_byte); | 779 return RegisterFPUInstruction(escape_opcode, modrm_byte); |
815 } else { | 780 } else { |
816 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1); | 781 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1); |
817 } | 782 } |
818 } | 783 } |
819 | 784 |
820 | |
821 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode, | 785 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode, |
822 int modrm_byte, | 786 int modrm_byte, |
823 uint8_t* modrm_start) { | 787 uint8_t* modrm_start) { |
824 const char* mnem = "?"; | 788 const char* mnem = "?"; |
825 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. | 789 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. |
826 switch (escape_opcode) { | 790 switch (escape_opcode) { |
827 case 0xD9: | 791 case 0xD9: |
828 switch (regop) { | 792 switch (regop) { |
829 case 0: | 793 case 0: |
830 mnem = "fld_s"; | 794 mnem = "fld_s"; |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1063 } | 1027 } |
1064 | 1028 |
1065 if (has_register) { | 1029 if (has_register) { |
1066 Print("%s st%d", mnem, modrm_byte & 0x7); | 1030 Print("%s st%d", mnem, modrm_byte & 0x7); |
1067 } else { | 1031 } else { |
1068 Print("%s", mnem); | 1032 Print("%s", mnem); |
1069 } | 1033 } |
1070 return 2; | 1034 return 2; |
1071 } | 1035 } |
1072 | 1036 |
1073 | |
1074 // TODO(srdjan): Should we add a branch hint argument? | 1037 // TODO(srdjan): Should we add a branch hint argument? |
1075 bool DisassemblerX64::DecodeInstructionType(uint8_t** data) { | 1038 bool DisassemblerX64::DecodeInstructionType(uint8_t** data) { |
1076 uint8_t current; | 1039 uint8_t current; |
1077 | 1040 |
1078 // Scan for prefixes. | 1041 // Scan for prefixes. |
1079 while (true) { | 1042 while (true) { |
1080 current = **data; | 1043 current = **data; |
1081 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix. | 1044 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix. |
1082 operand_size_ = current; | 1045 operand_size_ = current; |
1083 } else if ((current & 0xF0) == 0x40) { // REX prefix. | 1046 } else if ((current & 0xF0) == 0x40) { // REX prefix. |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1178 | 1141 |
1179 case NO_INSTR: | 1142 case NO_INSTR: |
1180 return false; | 1143 return false; |
1181 | 1144 |
1182 default: | 1145 default: |
1183 UNIMPLEMENTED(); // This type is not implemented. | 1146 UNIMPLEMENTED(); // This type is not implemented. |
1184 } | 1147 } |
1185 return true; | 1148 return true; |
1186 } | 1149 } |
1187 | 1150 |
1188 | |
1189 // Handle all two-byte opcodes, which start with 0x0F. | 1151 // Handle all two-byte opcodes, which start with 0x0F. |
1190 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. | 1152 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. |
1191 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. | 1153 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. |
1192 int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) { | 1154 int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) { |
1193 uint8_t opcode = *(data + 1); | 1155 uint8_t opcode = *(data + 1); |
1194 uint8_t* current = data + 2; | 1156 uint8_t* current = data + 2; |
1195 // At return, "current" points to the start of the next instruction. | 1157 // At return, "current" points to the start of the next instruction. |
1196 const char* mnemonic = TwoByteMnemonic(opcode); | 1158 const char* mnemonic = TwoByteMnemonic(opcode); |
1197 if (operand_size_ == 0x66) { | 1159 if (operand_size_ == 0x66) { |
1198 // 0x66 0x0F prefix. | 1160 // 0x66 0x0F prefix. |
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1561 } else { | 1523 } else { |
1562 Print(","); | 1524 Print(","); |
1563 current += PrintImmediate(current, BYTE_SIZE); | 1525 current += PrintImmediate(current, BYTE_SIZE); |
1564 } | 1526 } |
1565 } else { | 1527 } else { |
1566 UnimplementedInstruction(); | 1528 UnimplementedInstruction(); |
1567 } | 1529 } |
1568 return static_cast<int>(current - data); | 1530 return static_cast<int>(current - data); |
1569 } | 1531 } |
1570 | 1532 |
1571 | |
1572 // Mnemonics for two-byte opcode instructions starting with 0x0F. | 1533 // Mnemonics for two-byte opcode instructions starting with 0x0F. |
1573 // The argument is the second byte of the two-byte opcode. | 1534 // The argument is the second byte of the two-byte opcode. |
1574 // Returns NULL if the instruction is not handled here. | 1535 // Returns NULL if the instruction is not handled here. |
1575 const char* DisassemblerX64::TwoByteMnemonic(uint8_t opcode) { | 1536 const char* DisassemblerX64::TwoByteMnemonic(uint8_t opcode) { |
1576 switch (opcode) { | 1537 switch (opcode) { |
1577 case 0x1F: | 1538 case 0x1F: |
1578 return "nop"; | 1539 return "nop"; |
1579 case 0x2A: // F2/F3 prefix. | 1540 case 0x2A: // F2/F3 prefix. |
1580 return "cvtsi2s"; | 1541 return "cvtsi2s"; |
1581 case 0x31: | 1542 case 0x31: |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1619 return "movsxw"; | 1580 return "movsxw"; |
1620 case 0x12: | 1581 case 0x12: |
1621 return "movhlps"; | 1582 return "movhlps"; |
1622 case 0x16: | 1583 case 0x16: |
1623 return "movlhps"; | 1584 return "movlhps"; |
1624 default: | 1585 default: |
1625 return NULL; | 1586 return NULL; |
1626 } | 1587 } |
1627 } | 1588 } |
1628 | 1589 |
1629 | |
1630 int DisassemblerX64::InstructionDecode(uword pc) { | 1590 int DisassemblerX64::InstructionDecode(uword pc) { |
1631 uint8_t* data = reinterpret_cast<uint8_t*>(pc); | 1591 uint8_t* data = reinterpret_cast<uint8_t*>(pc); |
1632 | 1592 |
1633 const bool processed = DecodeInstructionType(&data); | 1593 const bool processed = DecodeInstructionType(&data); |
1634 | 1594 |
1635 if (!processed) { | 1595 if (!processed) { |
1636 switch (*data) { | 1596 switch (*data) { |
1637 case 0xC2: | 1597 case 0xC2: |
1638 Print("ret "); | 1598 Print("ret "); |
1639 PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1)); | 1599 PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1)); |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1936 } // !processed | 1896 } // !processed |
1937 | 1897 |
1938 ASSERT(buffer_[buffer_pos_] == '\0'); | 1898 ASSERT(buffer_[buffer_pos_] == '\0'); |
1939 | 1899 |
1940 int instr_len = data - reinterpret_cast<uint8_t*>(pc); | 1900 int instr_len = data - reinterpret_cast<uint8_t*>(pc); |
1941 ASSERT(instr_len > 0); // Ensure progress. | 1901 ASSERT(instr_len > 0); // Ensure progress. |
1942 | 1902 |
1943 return instr_len; | 1903 return instr_len; |
1944 } | 1904 } |
1945 | 1905 |
1946 | |
1947 void Disassembler::DecodeInstruction(char* hex_buffer, | 1906 void Disassembler::DecodeInstruction(char* hex_buffer, |
1948 intptr_t hex_size, | 1907 intptr_t hex_size, |
1949 char* human_buffer, | 1908 char* human_buffer, |
1950 intptr_t human_size, | 1909 intptr_t human_size, |
1951 int* out_instr_len, | 1910 int* out_instr_len, |
1952 const Code& code, | 1911 const Code& code, |
1953 Object** object, | 1912 Object** object, |
1954 uword pc) { | 1913 uword pc) { |
1955 ASSERT(hex_size > 0); | 1914 ASSERT(hex_size > 0); |
1956 ASSERT(human_size > 0); | 1915 ASSERT(human_size > 0); |
(...skipping 19 matching lines...) Expand all Loading... |
1976 *object = NULL; | 1935 *object = NULL; |
1977 } | 1936 } |
1978 } | 1937 } |
1979 } | 1938 } |
1980 | 1939 |
1981 #endif // !PRODUCT | 1940 #endif // !PRODUCT |
1982 | 1941 |
1983 } // namespace dart | 1942 } // namespace dart |
1984 | 1943 |
1985 #endif // defined TARGET_ARCH_X64 | 1944 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |